向Leetcode 435:种花问题 提交答案时,Leetcode平台出现了诡异的runtime error:
1 2 Line 1034: Char 34: runtime error: addition of unsigned offset to 0x602000000a50 overflowed to 0x602000000a4c (stl_vector.h) SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_vector.h:1043:34
测试用例如下:
提交的源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 bool canPlaceFlowers (vector<int >& flowerbed, int n) { int placed = 0 ; bool canPlace = false ; for (int i = 0 ; i < flowerbed.size (); i++) { if (flowerbed[i] == 0 ) { canPlace = false ; if (flowerbed.size () == 1 ) { canPlace = true ; } else if (i == 0 && flowerbed[i+1 ] == 0 ) { canPlace = true ; } else if (i == flowerbed.size () - 1 && flowerbed[i-1 ] == 0 ) { canPlace = true ; } else if (flowerbed[i-1 ] == 0 && flowerbed[i+1 ] == 0 ) { canPlace = true ; } if (canPlace) { flowerbed[i] = 1 ; placed++; } } } return placed >= n; }
实际上这个代码已经修改过一遍了,但是还是出现了runtime error,在本地用g++编译输出正确答案,没有出现runtime error。
Google一下错误日志后发现,可能是vscode的C++插件对代码的检查不严格,于是换用Visual Studio运行该代码,果然出现了错误:
点击忽略,可以看到出现未处理的异常:
查看调用堆栈,找到出现异常的位置:
可以看到程序停在第20行的位置,此时局部变量i
的值为0,访问vector数组的索引为-1,由于vector的索引为无符号数,此时直接溢出,变成一个非常大的值,所以程序报错addition of unsigned offset to 0x602000000a50 overflowed to 0x602000000a4c
,将程序重写后,错误消失,通过。重写后的程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 bool canPlaceFlowers (vector<int >& flowerbed, int n) { int placed = 0 ; bool canPlace = false ; for (int i = 0 ; i < flowerbed.size (); i++) { canPlace = false ; if (flowerbed[i] == 0 ) { if (i == 0 ) { if (flowerbed.size () == 1 ) { canPlace = true ; } else if (flowerbed[i+1 ] == 0 ) { canPlace = true ; } } else if (i == flowerbed.size () - 1 ) { if (flowerbed[i-1 ] == 0 ) { canPlace = true ; } } else { if (flowerbed[i-1 ] == 0 && flowerbed[i+1 ] == 0 ) { canPlace = true ; } } if (canPlace) { flowerbed[i] = 1 ; placed++; } } } return placed >= n; }
重写后的代码多了好几重判断,显得非常啰嗦。实际上可以通过在数组两侧都加上一个0作为padding,来避免进行复杂的检查。
2023.8.31: Update
Leetcode平台显示的报错内容实际上来自于g++编译器自带的address sanitizer
。在编译源文件时,在编译选项中添加-fsanitize=address
便可开启。添加address sanitizer
之后,程序在运行过程中出现数组越界、内存泄露、double free
等情况时,便会终止运行,并输出相应错误信息。