c-返回复合文字



看看这段代码。我在这里返回一个复合文字的地址。

#include <stdio.h>
#define FOO(bar) ((bar)->a + (bar)->b)
struct bar {
int a;
int b;
};
static struct bar * to_bar(int a, int b);
int main(void)
{
int baz = FOO((struct bar *) {to_bar(1, 2)});
printf("%dn", baz);
return 0;
}
static struct bar *
to_bar(int a, int b)
{
return &(struct bar) {a, b};
}

输出:

3

ISO/IEC 9899规定:

如果复合文字出现在函数体之外,则对象具有静态存储持续时间;否则,它将自动与封闭块相关联的存储持续时间。

I。e.在to_bar函数中,由复合文字创建的未命名对象具有自动存储持续时间。因此,它将在to_bar的范围之外被破坏。这段代码似乎产生了未定义的行为(基于标准(。是这样吗?

你说得对。在您的示例中,从to_bar返回后立即检索字段,因此您没有时间破坏已故to_bar函数的堆栈帧。但这里有另一个例子:

struct bar {
int a;
int b;
};
static struct bar * to_bar(int a, int b);
int main(void)
{
struct bar * corrupted_bar = to_bar(1, 2);
printf("this print will corruptn");
int baz = corrupted_bar->a + corrupted_bar->b;
printf("baz = %dn", baz);
return 0;
}
static struct bar *
to_bar(int a, int b)
{
return &(struct bar) {a, b};
}

当执行时

this print will corrupt
baz = -59543507

如果你看组装

.LC0:
.string "this print will corrupt"
.LC1:
.string "baz = %dn"
main:
push    rbp
mov     rbp, rsp
sub     rsp, 16
mov     esi, 2
mov     edi, 1
call    to_bar                    ; call to_bar
mov     QWORD PTR [rbp-8], rax    ; save address returned to a local pointer
mov     edi, OFFSET FLAT:.LC0     ; argument into puts()
call    puts                      ; call puts(), which creates its own local variables that corrupts the bar struct
mov     rax, QWORD PTR [rbp-8]    
mov     edx, DWORD PTR [rax]
mov     rax, QWORD PTR [rbp-8]
mov     eax, DWORD PTR [rax+4]
add     eax, edx
mov     DWORD PTR [rbp-12], eax
mov     eax, DWORD PTR [rbp-12]
mov     esi, eax
mov     edi, OFFSET FLAT:.LC1
mov     eax, 0
call    printf
mov     eax, 0
leave
ret
to_bar:
push    rbp
mov     rbp, rsp
mov     DWORD PTR [rbp-20], edi
mov     DWORD PTR [rbp-24], esi
mov     eax, DWORD PTR [rbp-20]
mov     DWORD PTR [rbp-8], eax     ; field 'a' gets stored, notice dest addr rbp-8 is in the stack frame of this function (local variable)
mov     eax, DWORD PTR [rbp-24]
mov     DWORD PTR [rbp-4], eax     ; field 'b' gets stored, same as above
lea     rax, [rbp-8]
pop     rbp
ret

相关内容

  • 没有找到相关文章

最新更新