Someone managed to exploit a flaw in the way I calculate high scores for my game Gem Story.
As of 8/18/09,
|ma||2147483647||16||August 13 2009|
|Loren||1317023||28||August 16 2009|
|yan||1108697||9||August 04 2009|
|Matt||880118||20||August 06 2009|
|moogleii||313409||17||July 10 2009|
|smd||298247||1||July 08 2009|
|bud||284941||32||July 11 2009|
|Emily||242672||6||July 07 2009|
|hech||184688||8||July 15 2009|
|Gg||170662||13||August 05 2009|
I thought I had accounted for such a scenario with proper checks, but it looks like I made some false assumptions about how things are cast in Objective-C. Guess I should have read the documentation more thoroughly. I wonder if this is true with C as well. I admit, I haven’t coded in C in a long time.
Anyway, player “ma” got an exorbitant score as you can see. To computer science folks, his particular score number, 2147483647, should immediately pop out. That happens to be the maximum value for a signed integer. So I figured he must have lowered his score into the negative, and at some point, my program attempted to assign a negative value to a variable that only accepts positive values. When that happens, the number will wrap around to the other side. So assigning -1 to a positive-only variable will jump the number around to the highest value.
Anyway, as I said, I thought I had accounted for that, by doing something like:
if ( ( NSInteger ) score + ( pointValue * multiplier ) ) > 0 )
but I guess that wasn’t enough. I did some testing (I’ve renamed some stuff to make it a little more readable):
- NSUInteger uStartValue = 0;
- NSInteger sPointValue = -1000; //signed value
- NSUInteger uMultiplier = 10; //unsigned value
- NSInteger sMultiTest = sPointValue * uMultiplier; //-10000
- BOOL test = NO;
- test = (sPointValue * multiplier) > 0; // YES…whut?
- NSUInteger unsignedTest = (sPointValue * uMultiplier); //4294957296
So this is interesting. So 7 shows the overflow in action. 6 seems to show that if a mixed-type operation isn’t assigned to a value, then it will default to type NSUInteger, if the operation contains an NSUInteger. But if you explicitly assign it, as in 4, then it’ll work fine.