Everyone likes getting a pay raise. Well, I suppose it depends on why. And HR isn't going to be too happy about your raise if it comes as the result of an easy-to-avoid software bug.
Cédric V's company makes payroll software mostly used in and around France. One of their customers had a problem: when paying employees, it would give them a significant raise- sometimes by two orders of magnitude, rarely by three or four.
What was surprising is that this happened to one customer, but none of their other customers. They couldn't replicate it on their test environment either. But once Cédric started digging into the code, it wasn't hard to understand what the root cause was.
double origin = GetDoubleFromRandomMethod();
string str = origin.ToString().Replace(".",",");
decimal result = decimal.Parse(str);
The good thing I can say about this C# code is that it does, eventually, handle currency values using decimal
, which guarantees that we won't lose precision. Of course, that decimal
derives from a double
, so we might already have errors.
Those errors, of course, don't matter, because somebody made some terrible assumptions about locale and added in an unnecessary ToString
operation with an equally unnecessary Replace
.
The ToString
method on a double
, by default, uses format "G" (for "general"), which is locale specific. So, if you're in a French locale, it will use the "," as a decimal separator. "3.14" in a US locale would be "3,14" in a French locale.
So, if this is used in a French locale, the Replace
does nothing, and the Parse
successfully converts the value back into a decimal
.
But the customer with the sudden raise problem didn't run their servers configured in a French locale. Since much of their business involved US customers, they ran their servers in a US locale. In that case, the Replace
would change the "." to a ",". The Parse
would interpret the comma as a "thousands separator", but the parser just ignores that symbol, even if it's in the wrong place. So "3.14" becomes "3,14", which gets parsed as "314". The number of significant figures the double
has behind the decimal place determines how many orders of magnitude someone gets a raise by.
I suppose they should be happy that there values coming out of that GetDoubleFromRandomMethod
aren't the result of any division operations. One 8/12
and you are paying out a satanic amount in quadrilions.