fsantinize 弱智

2023-09-16 10:35:49 +08:00
 zzzkkk

fsantinize 还没智能到那种程度 简直给码农添加负担 给一个静态字符数组前面添加几个空格都会报错

请看

图 1

图 2

图 3

编译时报图 3 的错误 运行就报 ==1856626==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff15ef59e9 at pc 0x55d429175340 bp 0x7fff15ef5940 sp 0x7fff15ef5938

5388 次点击
所在节点    C++
85 条回复
qbqbqbqb
2023-09-16 17:59:18 +08:00
@zzzkkk 减到 s 之前是有问题的。

因为你这个循环至少还会再判断一次条件,必然会非法读取越界位置 s[-1]的值,这是不允许的。所以说 sanitizer 会报错。

而且你也不知道 s 前面有什么二进制数据,“下面 start2++ 刚好指向空格”,指针没有跑飞只是运气好。
zzzkkk
2023-09-16 18:00:12 +08:00
@geelaw
char s[] = "add";

这样也是合法的 编译期就能确定长度 再简单不过的事
cnbatch
2023-09-16 18:00:17 +08:00
@cnbatch 补充一条,无论是以 C 语言还是 C++来编译,同样都没报错
qbqbqbqb
2023-09-16 18:00:40 +08:00
假如 s 数组前面二进制数据一堆 0x20 ,指针就跑飞了
cy18
2023-09-16 18:01:33 +08:00
@zzzkkk #28 聪明的你倒是把数组长度正确的,会报假阳性的代码贴上来啊...建议聪明的你别用截图,难道指望其他人对着你的图手打一遍代码么...
zzzkkk
2023-09-16 18:02:40 +08:00
@qbqbqbqb
减到非空格的位置退出 while 循环
+1 不是刚好指向空格吗?还需要什么运气?

我发现 fsanitize 对字符串增加到一定长度后才报错
zzzkkk
2023-09-16 18:04:08 +08:00
@qbqbqbqb
数组名前面就是一个 byte 不过不属于数组 吓谁啊
别小看了这几个 while 循环 是老鸟才能写得出来的
geelaw
2023-09-16 18:05:05 +08:00
@zzzkkk #38

int a[1];
a + 0; // OK
a + 1; // OK
a - 1; // 未定义行为
a + 2; // 未定义行为

和 (a-1)、(a+2) 有没有被解引用没有任何关系。见 C++ 标准 [expr.add]/4:

When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.
(4.1) If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.
(4.2) Otherwise, if P points to an array element i of an array object x with n elements ([dcl.array]), the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) array element i+j of x if 0≤i+j≤n and the expression P - J points to the (possibly-hypothetical) array element i−j of x if 0≤i−j≤n.
(4.3) Otherwise, the behavior is undefined.

注意 4.2 要求表达式的结果指向数组对象或者数组末尾之后,不允许数组开头之前。
zzzkkk
2023-09-16 18:07:18 +08:00
@cy18

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

int main(int argc, char **argv) {
char s[] = " a bc ed sdff";
printf("%d\n%d\n",sizeof(s),strlen(s));
char *start, *start2;
start = s;
while ( *start != '\0') {
start++;
}
--start;
char s2[strlen(s) + 1];
char *s2p = s2;
char flag;
while (start > s) {
flag = 0;
while ( *start == ' ') start--;
while (start >= s && *start != ' ') start--;
start2 = start;
++start2;
while ( *start2 != ' ' && *start2 != '\0') {
*s2p++ = *start2++;
if (flag == 0) flag = 1;
}
if (flag == 1) {
*s2p++ = ' ';
}
}
*s2p = '\0';
start = s;
s2p = s2;
while ( *s2p != '\0') *start++ = *s2p++;
*start = '\0';
printf("%s\n%d\n", s, (int) strlen(s));

}




编译:

cc c.c -fsanitize=address -fsanitize-recover=address -fno-omit-frame-pointer -O0 -Wall
geelaw
2023-09-16 18:07:24 +08:00
@zzzkkk #47 假设编译器不检查内存,并且数组前面全是空格呢?

另外这个 while 循环写得可以说是乱七八糟了。
cy18
2023-09-16 18:13:02 +08:00
@zzzkkk #49
misdake
2023-09-16 18:13:43 +08:00
字符串结尾不是空格的话,while(*start2 != ' ')没有判\0 会超出 s2 范围,一路写出范围
geelaw
2023-09-16 18:14:46 +08:00
@zzzkkk #47 接续 #50 ,假设数组前面一切可读取的虚拟内存都是 ' ',且假设指针加减运算未定义行为的实现就是访问这些虚拟内存,那么这个程序会因为把 start 减到不可读的虚拟内存地址之后继续读 start 而访问违规,从而崩溃。
zzzkkk
2023-09-16 18:20:04 +08:00
@misdake
这里需要把 while(*start2 != ' ') 改成 while(*start2 != ' ' && *start2 != '\0')
@geelaw

嗯 这里需要把 while(*start = '' ) 改成 while(start >=s && *start == '')
zzzkkk
2023-09-16 18:22:26 +08:00
@misdake
第 14 层 早就加了字符串末尾判断
zzzkkk
2023-09-16 18:25:20 +08:00
@geelaw
那你有什么更好的 while ? 已经是最高效的了
zzzkkk
2023-09-16 18:28:29 +08:00
重新申明:
fsanitize 无论字符串多短 都报错了

早上具体什么情况 一会报错 一会不报错 想不起来了
flyqie
2023-09-16 18:31:20 +08:00
@zzzkkk #40

没有 c 板块?

https://v2ex.com/go/c
learningman
2023-09-16 18:38:37 +08:00
@GeruzoniAnsasu 别尬黑,人好歹是会写 epoll 的,只是不会配 nginx 而已
learningman
2023-09-16 18:39:57 +08:00
“别小看了这几个 while 循环 是老鸟才能写得出来的”
今日 V2EX 笑话

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/974343

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX