19

这是我见过的最奇怪的错误之一。

我正在做一个非常简单的调用来从 HttpRuntime 缓存返回值。电话是:

return HttpContext.Current.Cache[cacheKey];

如果它返回null,那很好。我检查返回值是否为 null 并采取相应措施。我已经使用这个电话很长时间了。

最近,由于某种原因,当 cacheKey 设置为这个确切值时:

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

抛出 System.OverflowException:取反二进制补码的最小值无效。

呼叫、相关代码或服务器没有任何变化。如果 cacheKey 有稍微不同的字符,它工作得很好。例如,这个 cacheKey 返回 null 而不抛出任何异常:

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

请注意,这两个字符串之间的唯一区别是时间字符:2010-08-31-20-00-00 与 2010-08-31-21-00-00。

为什么这会有什么不同?为什么现在这么久了?

堆栈跟踪是:

[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 ...

我尝试将缓存调用更改为使用 HttpRuntime.Cache 代替(即。HttpRuntime.Cache[cacheKey]),但这没有任何区别。我知道它是相同的底层缓存提供程序,但我认为不同的调用可能会有所不同。没有骰子。

4

1 回答 1

18

看起来在您的平台上,GetHashCode()(在 System.String 中)那个确切的字符串正在返回-2147483648。您可以通过将该字符串放入并简单地为其调用 GetHashCode() 来测试这一点(就像我所做的那样)。每个字符串都有一个哈希码,这就是一个。所以呢?好....

CacheMultiple.UpdateCache调用GetHashCode()你的键字符串,然后调用GetCacheSingle(),调用Math.Abs,最终调用AbsHelper。如果数字正好等于 -2147483648,AbsHelper 会抛出异常!(因为绝对值将比可以保持的最大值大一)

所以,恭喜你,你中了GetHashCode彩票——在 2^32 个可能的值中,你得到了正确的(嗯,错误的)一个。不幸的是,Web.Cache 的内部似乎根本不处理这个问题,所以你必须调用GetHashCode你的字符串来查看它是否等于 -2147483648,如果是的话,稍微改变一下字符串。或者,捕获此异常 - 如果被捕获,请在稍微更改您的密钥后重试(以可预测的方式,以便您可以再次以相同的方式重新创建它)。

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.

于 2010-09-01T02:20:06.910 回答