数值越界是需要引起重视的问题,后端服务没有严格检验请求字段的取值范围,则可能引发严重的后果。
事故
例如用户购买礼物,礼物单价为20金币。有用户购买了1073741825个礼物,却只需要花费20金币,这是为何?
原因
原来系统中设定的购买数量和金币均采用了uint32,uint32的取值范围为[0, 4294967295],显示购买的数量1073741825在uint32的表示范围里。但计算金币时,需要乘以20,则总金币值超过uint32的表达范围,即溢出。
那么我们现在来讲计算一下,购买数量乘以单价1073741825*20=21474836500,用二进制表示为10100000000000000000000000000010100,长度为35位。转换为uint32位,则最高三位举出丢弃,剩下的值为00000000000000000000000000010100,转为十进制为20。因此利用数值溢出的原理,用户就可以在仅仅消费20金币的情况下,购买得到惊人的1073741825个礼物。
补充:原码、反码、补码的表示
原码就是最高位作为符号位,0表示正数,1表示负数,其余位表示直值的绝对值。
反码与原码相比,符号位不变,其余位取反。
补码,正数的补码就是原码,负数的补码是反码的基础上加1