【问题标题】:What makes the segmentation fault in the short C code?是什么导致短 C 代码中的分段错误?
【发布时间】:2017-08-03 09:02:24
【问题描述】:

每个人。我编写了以下代码,编译并运行它,但出现分段错误。

#include <stdio.h>
typedef long long ll_t;

void store_prod(ll_t * dest, int x, ll_t y) {
    * dest = x * y;
}

int main(void)
{
    int a = 2049;
    ll_t b = 2147483645;
    ll_t * c;

    store_prod(c, a, b);
    printf("%d * %lld = %lld\n", a, b, *c);

    return 0;
}

Dev-C++ 中的调试器转储以下内容:

0x00401500 <+0>:    push   %ebp
0x00401501 <+1>:    mov    %esp, %ebp
0x00401503 <+3>:    push   %ebx
0x00401504 <+4>:    sub    $0xc, %esp
0x00401507 <+7>:    mov    0x10(%ebp), %eax
0x0040150a <+10>:   mov    %eax, -0x10(%ebp)
0x0040150d <+13>:   mov    0x14(%ebp), %eax
0x00401510 <+16>:   mov    %eax, -0xc(%ebp)
0x00401513 <+19>:   mov    0xc(%ebp), %eax
0x00401516 <+22>:   mov    %eax, %edx
0x00401518 <+24>:   sar    $0x1f, %edx
0x0040151b <+27>:   mov    -0x10(%ebp), %ecx
0x0040151e <+30>:   mov    %ecx, %ebx
0x00401520 <+32>:   imul   %edx, %ebx
0x00401523 <+35>:   mov    -0xc(%ebp), %ecx
0x00401526 <+38>:   imul   %eax, %ecx
0x00401529 <+41>:   add    %ebx, %ecx
0x0040152b <+43>:   mull   -0x10(%ebp)
0x0040152e <+46>:   add    %edx, %ecx
0x00401530 <+48>:   mov    %ecx, %edx
0x00401532 <+50>:   mov    0x8(%ebp), %ecx
0x00401535 <+53>:   mov    %eax, (%ecx) ; The problem lies with this line
0x00401537 <+55>:   mov    %edx, 0x4(%ecx)
0x0040153a <+58>:   add    $0xc, %esp
0x0040153d <+61>:   pop    %ebx
0x0040153e <+62>:   pop    %ebp
0x0040153f <+63>:   ret

注册信息:

EAX 0x7fffe7fd  2147477501
ECX 0x40234e    4203342
EDX 0x400   1024
EBX 0x0 0
ESP 0x63fe58    0x63fe58
EBP 0x63fe68    0x63fe68
ESI 0x3d    61
EDI 0xb70d48    11996488
EIP 0x401535    0x401535 <store_prod+53>
EFLAGS  0x10206 [ PF IF RF ]
CS  0x23    35
SS  0x2b    43
DS  0x2b    43
ES  0x2b    43
FS  0x53    83
GS  0x2b    43

地址 [%ecx](即 0x40234e)处的代码似乎被覆盖了,但为什么会有这样的访问冲突呢? C代码有什么问题吗? 非常感谢您的帮助!

【问题讨论】:

  • ll_t * c; --> ll_t d, *c = &amp;d;
  • store_prod(c, a, b); 中,c 未初始化。启用编译器警告。
  • 是的,指针 ll_t * c 未初始化,因此它可以指向任何地方。谢谢大家的帮助。
  • 我们能否感谢有人在 SO 上发布问题之前尝试运行调试器这一事实?

标签: c debugging assembly compilation


【解决方案1】:

您尝试写入不属于您的内存 → 未定义的行为(段错误可选)

ll_t * c; 行中声明了c,但您没有使用malloc 或将其指向有效地址(例如:ll_t d; ll_t *c = &amp;d;

ll_t * c;更改为ll_t * c = malloc(sizeof(ll_t));并检查malloc是否失败,或者更改为ll_t d; ll_t *c = &amp;d;

编辑:正如@Ajay Brahmakshatriya 指出的那样,还有另一个(按时间顺序排列的)未定义行为 - 将未初始化的变量 (c) 发送到 store_prod(...)

【讨论】:

  • @fuz 你是怎么做那个箭头的? (试图改善我的写作:))
  • 在具有德语布局的 Linux 上,它是 AltGr + I。或者对于 html 实体,它是 &amp;rarr; 产生 → (显然在这里不起作用)。
  • 在“写入不属于你的内存”之前,读取未初始化的值。
  • @AjayBrahmakshatriya 会不会只是读取一个中间值而不使用它,我认为这不应该被视为 ub?
  • @CIsForCookies 1 声明使用对象作为参数是对参数的赋值。 2 (point 21) 表示未初始化值的“使用”是 UB。赋值给另一个变量算作使用,因为它需要左值到右值的转换。
【解决方案2】:

崩溃的原因是当您将值存储到未初始化指针c 指向的位置时的未定义行为。

无需将c 设为指针,将其定义为ll_t 并将其地址传递给函数:

#include <stdio.h>

typedef long long ll_t;

void store_prod(ll_t *dest, int x, ll_t y) {
    *dest = x * y;
}

int main(void) {
    int a = 2049;
    ll_t b = 2147483645;
    ll_t c;

    store_prod(&c, a, b);
    printf("%d * %lld = %lld\n", a, b, c);

    return 0;
}

你可以只返回计算值,但我想这个代码示例的目的是教使用指针来返回计算值。

【讨论】:

    猜你喜欢
    • 2011-01-10
    • 2012-08-14
    • 2021-11-25
    • 2012-10-23
    • 2017-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多