This is a snippet from the code review conducted during the public inquiry of the ongoing UK Post Office scandal.
Yes, the Horizon software that contains this code is still in use today.
This makes me want to scream
I have only two words: Ave Maria.
> bankruptcy, imprisonment, suicide
so nobody bothered to check whether the bills actually make sense?
Fujitsu were logging into the backend and modifying the numbers to make things square up.
Multiple lead engineers quit Fujitsu and whistle blew about it. They were thrown under the bus too. There's no reason the UK government should be taking the financial hit for this. The people who helped cover it up inside the government and fujitsu should be rotting in jail and Fujitsu should be on the hook for billions in damages to the UK government in order to roll out a new system and to compensatethe families affected.
If you want more background there were two fantastic productions that kept this in the public view in the UK.
BBC Panorama - Scandal at the Post Office https://m.youtube.com/watch?v=d4UYP8JP61A
And a dramatisation made more recently about the people affected, which brought it back into the public eye.
https://tv.apple.com/ca/show/mr-bates-vs-the-post-office/umc.cmc.6fyn4tqnvb2n3xl5ify1to8qx.
It should be noted that once it did jump back into the public eye it became clear the government and Fujitsu were still deflecting and covering up and most people due compensation still hadn't got any.
I heard a quote from one of the jail postmasters along the lines of 'I went to jail for a crime I didn't commit. Why has no one gone to jail for crimes they have been proven to have committed?'
Iirc some postmasters tried to prove their innocence by keeping paper logs along side the digital system.
Royal mail and Fujitsu rejected their appeals stating that the digital system is correct as it cannot make mistakes...
rejected their appeals stating that the digital system is correct as it cannot make mistakes
"Stop me if you've heard this one before..."
Allegedly there were people in a master control room somewhere at Fujitsu who were quietly monitoring all the installed instances of the software on post office computers and simply logging directly in to them through a back-door and manually rewriting individual register values buried god-knows-where in the guts of the running code whenever a problem arose. There are stories of postmasters literally seeing erroneous financial transactions being "corrected" (and, in some cases, actually being made even worse) on the screens right in front of them whilst they were calling tech support on the phone, and then being personally blamed for their accounts not adding up.
How... how did someone think "mmm, ho do I calculate -x? Oh right, I do x-2x"
Literally how, were they high or something?
lines of code being the measure of productivity
But x=-x is equal amount of lines as x=x-2x.
Were they paid by line length?
People who have been lobotomized and/or have never seen a programming book or university from the inside.
geeez I have no idea who reviewed this but not even the juniorest of my juniors would dare to write such abominations
lgtm, pull request approved
Wait, is that VB??
Looks like it might be Ada
I just checked. Horizon was written in VB6.
I thought it was bad before..... and then it gets worse
One of the most important and impactful computer systems in the UK was written in VB6. Awesome.
In my professional life I am aware of a few large and critical systems written in VB. Some were originally classic ASP websites that have been continuously used and updated. I don't think it's particularly rare.
If d is greater than 0, d = 0-d surely?
d *= -1
Even easier.
d = -d
It's called unary negation in many languages
I kind of expected that to not work, but I have no idea what language that is, so I don’t know whether mine works either lol
What about Abs(d)?
abs always returns positive. This is converting +d to -d and -d to +d
Ah, I guess I should go work for Fujitsu then
Doesn't matter if d is positive, negative or 0. To reverse the sign, you always just do -d, (aka 0-d).
If d is positive, -d is a negative number
If d is negative, -d is a positive number
If d is 0, 0-0 is still 0.
Ah great shout
The worst part of the story is not the roll out of the faulty software, the reason that lead to imprisonment, bankruptcy and suicide is the denial of the problem by the post office fearing public scrutiny so they swept every report of faulty accounting by the horizon software under the rug and forced the post masters running the indivual shops to financially cover the faulty accounting
probably loc was a measure of productivity,
I wonder, is obfuscatory code like this an effort to make decompiling and reverse-engineering from binaries more challenging?
"paid by the line of code"
No, this looks to be so simple to be an obfuscation attemp.
This is 9PM on a friday code
I wonder about this too, what could be the point of doing this, it's not weird shenanigans because their language or whatever doesn't support negating a number because they're doing it in the actual function. This isn't bad code, it was written like this on purpose. Tho I can't figure out the purpose, why would they want to protect reverse engineering a negating function ?
Conceivably you might have requirements to, say, log when a value is being double negated or something? Where you’d want the operation to be a function call rather than inlined, so you have somewhere to insert breakpoints, etc.
But in isolation the existence of this function makes zero sense.
when you work is measured by the number of lines you write
https://en.m.wikipedia.org/wiki/British_Post_Office_scandal Wiki page on the scandal for those curious
In defence of Fujitsu I think this was actually International Computers Limited as the Horizon contract was awarded to them some time before Fujitsu bought them. So we can't blame the Japanese for this goof.
I think the press likes to blame it on Fujitsu through a mix of racism and avoiding admitting it's our fault. How much the Japanese parent was involved is somewhere between slim and none.
Fujitsu don't need defending on this.
From the wiki (with links to the references):
Business applications on Legacy Horizon (including EPOSS, the accounting application) were written by Fujitsu. The history and poor state of the EPOSS software is described in 2001 in an internal Fujitsu document "Report on the EPOSS PinICL TaskForce".
EPOSS, the component of Horizon that this snippet is auditing and the source of faults that ruined the lives of innocent people, was written by Fujitsu.
Your hearts in the right place but Fujitsu should've done much better, from the wiki:
"At the Inquiry in 2024, it was revealed that Fujitsu was aware that the Horizon software contained bugs as early as 1999, but this was not disclosed to the subpostmasters or to the courts in which prosecutions were conducted"
ICL was bought by Fujitsu in 1998. Horizon "conceived in 1996". You are absolutely spot on to mention this.
When I was playing around with sound shaders, you often wanted to move the wave but keep it's sign and amplitude. So a ton of sng = sing(f); amp = abs(f)
and then you do some math on it like amp+=0.2;
before assembling it again f_out = amp*sign;
and yes errors were all over the place.
After a whole someone told me that tanh(x) = smoothsign(x)
and that really opened some mind eyes.
Why is nobody talking about d < o?? They're casually comparing d to some global variable o which they assume is 0...
I think it's just a bad font. Looking at the "2" (the only other digit in the code): it is also smaller than all the other characters in the code.
Oh fuck, oh sweet Jesus fuck, you're right! Unless what we're seeing here is one hell of a misprint, some knuckle-dragging imbecile actually used the letter "o" as a variable name! In a book-keeping program written for a whole fucking national institution that doesn't just deliver the post, but also provides actual high-street banking services, often to some of the most old and vulnerable!!
There are no more words. There is only horror. I need to lie down.
It's just a bad (for code) font.
I defy you to show me any font ever created that renders the numeral zero so that it is indistinguishable from a lower-case "o." And if any such thing truly does exist, that also makes me incandescently angry.
EDIT: Wait, holy crap, you may actually be right, because it also renders the numeral two the same size as a lower-case letter. Incandescently angry it is, then; that's even worse than a misprint! Thanks for pointing that out, this debacle is just incompetence and craziness all the way down.
That’s even worse that they would write code in such a terrible font!
I think it is a 0 (I hope!) ..if you look at the next page the date is 14/05/01 and has the same font as that 0.. weird font seems almost like old typewriters ones
d = strtoint("-" + inttostr(d))
This looks like it was written by someone who has absolutely no understanding of computer arithmetic.
Is too complicated for sure. But it does work. Is this the bug that caused suicides?
It only works most of the time.
D*2 can overflow, and presumably you can get other precision errors from the unnecessary operations
It wasn't this code, but the truth is much much worse. The hosting company was actively changing submitted values in the database whilst assuring users that this was impossible. And then laying the blame at the users door.
There should be people in prison for this and not the poor souls who did through no fault of their own. It's the greatest miscarriage of justice in British history.
ITV did an amazing dramatisation of it all at the start of of 2024. Look up Mr Bates vs The Post Office.
Maybe, it could've overflowed.
Sometimes this happens to me when I'm trying to improve a MVP function into something that actually works with what I'm trying to do
And then I say "what the fuck is wrong with me" when I notice it
[deleted]
you're making a lot of assumptions
So reverse sign of 5 is -20. Got it.
yeah, no.
that d*2 could overflow
Surely that's the actual bug that got people killed.
Nobody directly died, but the accounting software messed up. Money was missing and the British post office went to Fujitsu and they swore up and down that it couldn’t possibly be due to bugs in their software. So on that basis they blamed (and in some cases charged with criminal fraud) a bunch of post office managers thinking they embezzled the money.
But actually the software was buggy as fuck and they ruined a bunch of people’s reputations because Fujitsu was incompetent. Several wrongly convicted people committed suicide. https://en.m.wikipedia.org/wiki/British_Post_Office_scandal
Nonetheless, that sort of "look at how clever I am" usage of elaborate mathematical juggling to essentially achieve a single bit flip is awfully reminsicent of the infamous THERAC-25, which did directly kill people due to a nasty combination of terrible design and code flaws, one of which was indeed an arithmetic overflow.
Oh yeah, whoever did this seems grossly incompetent.
Honestly, I'm still unsure whether the code we see here could have been produced merely by colossal incompetence, or whether it is the result of active, wilful perversity.
100%. I don’t know if I am smart enough to write something this convoluted. Like, why? What purpose could it possibly serve? Was the coder getting paid by the character? If so, I could think of much more profitable ways to write this.
In another comment I mentioned that you might want a function like this if you, say, need to log or track different financial operations. That way you have somewhere to, say, insert a breakpoint or tracepoint whenever you try to negate a negative value. A negation operator would likely be inlined.
Obviously the way they’re doing the actual math operation there is awful, though.
Twos complement makes it more complex than that... But just multiplying by -1 would replace that whole function, in all cases, with fewer bugs while running faster and using less memory.
There's no need to do any of that mess.
you can't just bit flip the sign digit
Yeah it’s not a single bit flip, but I don’t know of any language that isn’t capable of handling the sign flip with a single operation equivalent to
x = -x
. Even assembly languages can domvn
or equivalent.In languages with two's complement integers, the minimum integer of a given size has no additive inverse in that same size. E.g. in C, an
int
can fitINT_MIN
but not-INT_MIN
. The fix is to check if the number to be inverted isINT_MIN
and if so error. Otherwise just negate, all other values are safe. Or use the checked APIs that got added in C23.~x + 1
Bit flip won't work on ints in U2 coding.
Fujitsu are hiring
negating a number is not a single bit flip..
At least 13 people died as a direct result of this. This bug impacted the Country greatly. Post Masters here are often just wee old Ladies out in the sticks.
https://www.nytimes.com/2025/07/10/world/europe/uk-post-office-scandal-report.html
Post Office has the far greater blame IMO because their role as a prosecutor conferred many responsibilities they failed to meet, which would have avoided many deaths.
In over seven hundred cases the post office prosecuted people sending many to prison, many more were financially ruined trying to avoid prosecution.
The Post Office had access to keystroke data which would have been exonerating in many cases which they didn't disclose because their contract made it too expensive.
As the scandal began coming to light a memo was written internally suggesting minutes of meetings related to it were destroyed believing (wrongly) that meant they didn't have to disclose it.
Of the relative few who had convictions quashed by appeal (the majority of victims had their convictions quashed by an absolutely extraordinary act of parliament because the appeal court had not the resources to hear so many cases) some had already died believing the shadow of this legal atrocity had condemned them to ignobility.
Some committed suicide. Lives were doubtless shortened.
The full judgment in a combined appeal for only 39 of the hundreds directly harmed and thousands indirectly is available and explains the truly horrific details: https://www.judiciary.uk/wp-content/uploads/2022/07/Hamilton-Others-v-Post-Office-judgment-230421.pdf
Yeah, the whole thing was a clusterfuck at every level. By no means did I mean to make it sound like the post office was blameless. Courts giving criminal convictions on pretty flimsy evidence was awful too.
"Nobody directly died"
13 people literally killed themselves over it
When you say “got people killed” I think more of things like https://en.m.wikipedia.org/wiki/Therac-25.
The whole thing was handled amazingly badly at every level. It’s hard to envision ‘bugs in this financial software being written by the lowest bidder will result in people committing suicide’ up front.
Someone did commint s*icide from the stress and damage from the software.
As I wrote:
“The” bug was a combo of ui refresh delay and form re-submit logic resulting in cash to till deposits being double counted.
That is to say, cashiers would get given £100, type 100, hit enter, see nothing happens, and hit enter again, till balance would be 200, but cash in till 100, and the postmaster accused of taking the difference.
Yeah, guy should have known that the right way to do it is
d = 2(d/2.0 - d)
Smh my head
It can't d is positive so it's not possibleEdit: nevermind you can make it negative if the second to last, leftmost bit is set 🤦♂️
Are you sure ? In the case that d>(MAX_INT/2), wouldn't d*2 overflow and cause d-(d*2) != -d?
Honestly, if it's causing this much confusion, guesswork and debate as to what, precisely, it's even supposed to do, then it's direfully bad code regardless of any cleverly subtle functionality it may or may not turn out to have.
Not sqrt, it's less than half of max UNSIGNED int. Multiplication by 2 is equivalent to left shifting the bits by 1. So to overflow the leftmost bit needs to be 1. In two's compliment, positive integers have their leftmost bit as 0 by definition (1 for negative) so its impossible to overflow a positive signed number by multiplying by 2.given an 8 bit signed integer:
01000000 = 64
01000000 << 1 = 10000000
10000000 = -128
By overflow he means go negative. Which most of us would count as overflow when we talk about signed variables.