向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
[0,1,0]
1

提交的源代码如下:

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运行该代码,果然出现了错误:

点击忽略,可以看到出现未处理的异常:

leetcode-strange-runtime-error-2.jpg

查看调用堆栈,找到出现异常的位置:

leetcode-strange-runtime-error-3.jpg

可以看到程序停在第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等情况时,便会终止运行,并输出相应错误信息。