最近碰到了一个整数溢出的问题,排查了半天
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | struct fs_opened { int slice_size; int next_slice; ... } static int start_upload( struct dlife_cloud *cloud, struct fs_opened *opened, int64_t file_size) { int64_t uploaded_size = opened->next_slice * opened->slice_size; int64_t remain_size = file_size - uploaded_size; int upload_size = MIN(remain_size, opened->slice_size); if (upload_size == 0 || rb_len(&opened->rb) < upload_size) return 0; ... } |
文件按块分片上传,一个块是10M,所以opened->slice_size的值是:10*1024*1024,opened->next_slice的值是已经上传的块,
上面的逻辑很简单,用文件大小减去已经上传的大小,得到剩余待上传的大小remain_size,然后和分片10M比较,取最小值,得到当前上传分片的大小。rb_len()是缓存的大小,如果缓存够了,就触发上传。
上传一个3G多的文件,最后一个块传输不了,从上面return 0返回了,最后一个分片打印出来upload_size是10M,而不是最后一个片剩余的大小,百思不得其解,最后加了详细的打印,发现是
1 | int64_t uploaded_size = opened->next_slice * opened->slice_size; |
计算溢出了。
slice_size: 10*1024*1024
next_silice: 324
他们都是32位整数,相乘赋值给64位整数,但是乘的时候已经溢出了,得到uploaded_size是:-897581056,导致remain_size计算错误。
导致最后一个片,认为是没有足够的缓存,而没有触发上传。
总结:
int64 = int * int
这种形式会存在整数计算溢出,需要小心。