81 柔性数组造成的一些奇怪情况
前言
测试用例是来自于 陈皓 老师的博客
C语言结构体里的成员数组和指针
主要是测试 结构体中柔性数组 的相关特性
然后 参照的对象是 和 结构体中指针 来作为参照
然后 可以看到一些奇怪的现象, 然后 一去调试 发现更加奇怪
测试用例
#include "stdio.h"struct str {int len;char s[0];
// char *s;
};struct foo {struct str *a;
};int main() {struct foo f = {0};if (f.a->s) {printf(" this is in if scope \n");printf(" printf %s \n", f.a->s);}return 0;
}
然后执行程序, 效果如下, 然后 有点意外的是 居然进了 if block
root@ubuntu:~/Desktop/linux/HelloWorld# ./Test19AccessArray0this is in if scope
Segmentation fault
来调试看一下 情况, 这里 f.a 为 NULL, 然后 居然没有报错?
然后 会产生一个 SIGSEGV 的信号
柔性数组成员编译之后的 main
上下文的信息如下
可以看到的是这里 获取到 f.a 为 0, 然后 f.a->s 是 0 + 4[s的偏移]
然后 因此 得到的是上面的一系列的情况
最终 SIGSEGV 是在 printf 里面, 访问地址4, 然后 是一个非法的地址, 内核发送了 SIGSEGV 信号量
(gdb) list 17
12 };
13
14 int main() {
15
16 struct foo f = {0};
17 if (f.a->s) {
18 printf(" this is in if scope \n");
19 printf(" printf %s \n", f.a->s);
20 }
21
(gdb) b Test19AccessArray0.c:17
Breakpoint 1 at 0x400576: file Test19AccessArray0.c, line 17.
(gdb) run
Starting program: /root/Desktop/linux/HelloWorld/Test19AccessArray0Breakpoint 1, main () at Test19AccessArray0.c:17
17 if (f.a->s) {
(gdb) disassemble
Dump of assembler code for function main:0x0000000000400566 <+0>: push %rbp0x0000000000400567 <+1>: mov %rsp,%rbp0x000000000040056a <+4>: sub $0x10,%rsp0x000000000040056e <+8>: movq $0x0,-0x10(%rbp)
=> 0x0000000000400576 <+16>: mov -0x10(%rbp),%rax0x000000000040057a <+20>: add $0x4,%rax0x000000000040057e <+24>: test %rax,%rax0x0000000000400581 <+27>: je 0x4005a7 <main+65>0x0000000000400583 <+29>: mov $0x400634,%edi0x0000000000400588 <+34>: call 0x400430 <puts@plt>0x000000000040058d <+39>: mov -0x10(%rbp),%rax0x0000000000400591 <+43>: add $0x4,%rax0x0000000000400595 <+47>: mov %rax,%rsi0x0000000000400598 <+50>: mov $0x40064a,%edi0x000000000040059d <+55>: mov $0x0,%eax0x00000000004005a2 <+60>: call 0x400440 <printf@plt>0x00000000004005a7 <+65>: mov $0x0,%eax0x00000000004005ac <+70>: leave0x00000000004005ad <+71>: ret
End of assembler dump.
(gdb) nexti
0x000000000040057a 17 if (f.a->s) {
(gdb) info registers
rax 0x0 0
rbx 0x0 0
rcx 0x0 0
rdx 0x7fffffffe588 140737488348552
rsi 0x7fffffffe578 140737488348536
rdi 0x1 1
rbp 0x7fffffffe490 0x7fffffffe490
rsp 0x7fffffffe480 0x7fffffffe480
r8 0x400620 4195872
r9 0x7ffff7de7af0 140737351940848
r10 0x846 2118
r11 0x7ffff7a2d750 140737348032336
r12 0x400470 4195440
r13 0x7fffffffe570 140737488348528
r14 0x0 0
r15 0x0 0
rip 0x40057a 0x40057a <main+20>
eflags 0x202 [ IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) nexti
0x000000000040057e 17 if (f.a->s) {
(gdb) info registers
rax 0x4 4
rbx 0x0 0
rcx 0x0 0
rdx 0x7fffffffe588 140737488348552
rsi 0x7fffffffe578 140737488348536
rdi 0x1 1
rbp 0x7fffffffe490 0x7fffffffe490
rsp 0x7fffffffe480 0x7fffffffe480
r8 0x400620 4195872
r9 0x7ffff7de7af0 140737351940848
r10 0x846 2118
r11 0x7ffff7a2d750 140737348032336
r12 0x400470 4195440
r13 0x7fffffffe570 140737488348528
r14 0x0 0
r15 0x0 0
rip 0x40057e 0x40057e <main+24>
eflags 0x202 [ IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
指针成员编译之后的 main
将结构体 str 中的 s 成员更新成为 “char *s”
然后 再来看一下 具体的效果
这下可以看到的是 在访问 f.a->s 的时候 就已经出现了异常
可以看到的是这里 获取到 f.a 为 0, 然后 f.a->s 是 访问 0 的数据
然后 访问地址0, 然后 是一个非法的地址, 内核发送了 SIGSEGV 信号量
(gdb) list 17
12 };
13
14 int main() {
15
16 struct foo f = {0};
17 if (f.a->s) {
18 printf(" this is in if scope \n");
19 printf(" printf %s \n", f.a->s);
20 }
21
(gdb) b Test19AccessArray0.c:17
Breakpoint 1 at 0x400576: file Test19AccessArray0.c, line 17.
(gdb) run
Starting program: /root/Desktop/linux/HelloWorld/Test19AccessArray0Breakpoint 1, main () at Test19AccessArray0.c:17
17 if (f.a->s) {
(gdb) disassemble
Dump of assembler code for function main:0x0000000000400566 <+0>: push %rbp0x0000000000400567 <+1>: mov %rsp,%rbp0x000000000040056a <+4>: sub $0x10,%rsp0x000000000040056e <+8>: movq $0x0,-0x10(%rbp)
=> 0x0000000000400576 <+16>: mov -0x10(%rbp),%rax0x000000000040057a <+20>: mov 0x8(%rax),%rax0x000000000040057e <+24>: test %rax,%rax0x0000000000400581 <+27>: je 0x4005a7 <main+65>0x0000000000400583 <+29>: mov $0x400634,%edi0x0000000000400588 <+34>: call 0x400430 <puts@plt>0x000000000040058d <+39>: mov -0x10(%rbp),%rax0x0000000000400591 <+43>: mov 0x8(%rax),%rax0x0000000000400595 <+47>: mov %rax,%rsi0x0000000000400598 <+50>: mov $0x40064a,%edi0x000000000040059d <+55>: mov $0x0,%eax0x00000000004005a2 <+60>: call 0x400440 <printf@plt>0x00000000004005a7 <+65>: mov $0x0,%eax0x00000000004005ac <+70>: leave0x00000000004005ad <+71>: ret
End of assembler dump.
(gdb) nexti
0x000000000040057a 17 if (f.a->s) {
(gdb) info registers
rax 0x0 0
rbx 0x0 0
rcx 0x0 0
rdx 0x7fffffffe588 140737488348552
rsi 0x7fffffffe578 140737488348536
rdi 0x1 1
rbp 0x7fffffffe490 0x7fffffffe490
rsp 0x7fffffffe480 0x7fffffffe480
r8 0x400620 4195872
r9 0x7ffff7de7af0 140737351940848
r10 0x846 2118
r11 0x7ffff7a2d750 140737348032336
r12 0x400470 4195440
r13 0x7fffffffe570 140737488348528
r14 0x0 0
r15 0x0 0
rip 0x40057a 0x40057a <main+20>
eflags 0x202 [ IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) nextiProgram received signal SIGSEGV, Segmentation fault.
0x000000000040057a in main () at Test19AccessArray0.c:17
完