views:

81

answers:

1

This is one of the strangest errors I've ever seen.

I'm doing a very simple call to return values from the HttpRuntime cache. The call is:

return HttpContext.Current.Cache[cacheKey];

If it returns null, that's fine. I check if the returned value is null and act accordingly. I've been using this call for a long time.

Recently, for some reason, when cacheKey is set to this exact value:

"Topic_GridSelectAll:5,null,2010-08-31-20-00-00,Published,desc,5,1"

a System.OverflowException is thrown: Negating the minimum value of a twos complement number is invalid.

Nothing about the call, associated code or server has changed. If the cacheKey has slightly different characters, it works perfectly fine. For instance, this cacheKey returns null without throwing any exception:

"Topic_GridSelectAll:5,null,2010-08-31-21-00-00,Published,desc,5,1"

Notice, the only difference between those two strings is the time characters: 2010-08-31-20-00-00 versus 2010-08-31-21-00-00.

Why the hell would that make any difference? And why now after all this time?

The stack trace is:

[OverflowException: Negating the minimum value of a twos complement number is invalid.]
   System.Math.AbsHelper(Int32 value) +12753486
   System.Web.Caching.CacheMultiple.UpdateCache(CacheKey cacheKey, CacheEntry newEntry, Boolean replace, CacheItemRemovedReason removedReason, Object& valueOld) +142
   System.Web.Caching.CacheInternal.DoGet(Boolean isPublic, String key, CacheGetOptions getOptions) +122
   MyProject.Helpers.CacheHelper.GetData(String cacheDomain, String cacheKey) in ...

I've tried changing the cache call to use HttpRuntime.Cache instead (ie. HttpRuntime.Cache[cacheKey]), but that made no difference. I know it's the same underlying cache provider, but I thought maybe the different call would make a difference. No dice.

+9  A: 

It looks like on your platform, GetHashCode() (in System.String) for that exact string is returning -2147483648. You could test this (as I did) by putting that string in and simply calling GetHashCode() for it. Every string gets a hash code, and this is one. So what? well....

CacheMultiple.UpdateCache calls GetHashCode() on your key string, then calls GetCacheSingle(), which calls Math.Abs, which eventually calls AbsHelper. AbsHelper throws an exception if the number is exactly equal to -2147483648! (since the absoulte value would be one more than the maximum value that can be held)

So, congratulations, you won the GetHashCode lottery - out of 2^32 possible values, you got the right (well, wrong) one. Unfortunately, it seems that the internals of Web.Cache don't handle this at all, so you would have to call GetHashCode on your string to see if it was equal to -2147483648, and if so alter the string slightly. Or, trap for this exception - and if caught, try again after slightly altering your key (in a predictable manner so that you can recreate it the same way again).

Nice bug find - I'd probably go ahead and put a bug on the Connect site if I were you... in my opinion, it shouldn't be the responsibility of the caller to detect and correct edge case problems due to internal implementation decisions.

Philip Rieck
Interesting. That makes sense. _"in my opinion, it shouldn't be the responsibility of the caller to detect and correct edge case problems due to internal implementation decisions."_ Agreed. Why the heck would Microsoft not consider that that might happen. I'll run it up their flag pole.
sohtimsso1970
Yeah, that was it. The hash code is a twos complement. Great. Well, try/catch it is, I guess.
sohtimsso1970
"Why the heck would Microsoft not consider that that might happen." Maybe because they figured the odds were about 1 in 2^32? Although it's certainly conceivable that something about their hash function's implementation actually makes the odds much higher.
MatrixFrog