【问题标题】:Calling free() on malloc()'d char pointer causes program to crash with invalid pointer在 malloc() 的 char 指针上调用 free() 会导致程序因指针无效而崩溃
【发布时间】:2016-07-23 18:51:08
【问题描述】:

当我遇到这个时,我正在学习 C 并玩了一下堆内存:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    char* test = malloc(1024);
    test = "Hello!";
    printf("%s\n", test);
    free(test);
    return 0;
}

我认为它应该做什么:

  • 在堆上分配 1024 个字节
  • 将“Hello!\0”写入该内存的开头
  • 从我从malloc() 得到的指针开始写入stdout,直到找到\0
  • 释放malloc()分配的1024字节内存
  • 返回 0

但是,当调用 free() 时,我的程序会崩溃。为什么?

~$ ./mem                                                                                                                                                              
Hello!
*** Error in `./mem': munmap_chunk(): invalid pointer: 0x0000000000400684 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x77725)[0x7f9f99ac5725]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x1a8)[0x7f9f99ad1c18]
./mem[0x4005ec]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f9f99a6e830]
./mem[0x4004e9]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:01 3801151                            /home/gala/mem
00600000-00601000 r--p 00000000 08:01 3801151                            /home/gala/mem
00601000-00602000 rw-p 00001000 08:01 3801151                            /home/gala/mem
015e6000-01607000 rw-p 00000000 00:00 0                                  [heap]
7f9f99838000-7f9f9984e000 r-xp 00000000 08:01 1970703                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f9f9984e000-7f9f99a4d000 ---p 00016000 08:01 1970703                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f9f99a4d000-7f9f99a4e000 rw-p 00015000 08:01 1970703                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f9f99a4e000-7f9f99c0e000 r-xp 00000000 08:01 1970665                    /lib/x86_64-linux-gnu/libc-2.23.so
7f9f99c0e000-7f9f99e0d000 ---p 001c0000 08:01 1970665                    /lib/x86_64-linux-gnu/libc-2.23.so
7f9f99e0d000-7f9f99e11000 r--p 001bf000 08:01 1970665                    /lib/x86_64-linux-gnu/libc-2.23.so
7f9f99e11000-7f9f99e13000 rw-p 001c3000 08:01 1970665                    /lib/x86_64-linux-gnu/libc-2.23.so
7f9f99e13000-7f9f99e17000 rw-p 00000000 00:00 0 
7f9f99e17000-7f9f99e3d000 r-xp 00000000 08:01 1970637                    /lib/x86_64-linux-gnu/ld-2.23.so
7f9f9a013000-7f9f9a016000 rw-p 00000000 00:00 0 
7f9f9a039000-7f9f9a03c000 rw-p 00000000 00:00 0 
7f9f9a03c000-7f9f9a03d000 r--p 00025000 08:01 1970637                    /lib/x86_64-linux-gnu/ld-2.23.so
7f9f9a03d000-7f9f9a03e000 rw-p 00026000 08:01 1970637                    /lib/x86_64-linux-gnu/ld-2.23.so
7f9f9a03e000-7f9f9a03f000 rw-p 00000000 00:00 0 
7ffcc81cb000-7ffcc81ec000 rw-p 00000000 00:00 0                          [stack]
7ffcc81f8000-7ffcc81fa000 r--p 00000000 00:00 0                          [vvar]
7ffcc81fa000-7ffcc81fc000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
[1]    12941 abort      ./mem

【问题讨论】:

  • test = "Hello!"; 错误,它不会写入分配的内存,而是丢弃您的指针并用指向字符串"Hello!" 的指针覆盖它
  • char* test = strdup("Hello");
  • @jpw - strncpy 会稍微好一点
  • 除了cmets和answers中给出的信息外,在将数据复制到分配的内存之前,您应该确认malloc成功。 malloc 失败时返回 NULL

标签: c pointers memory-management


【解决方案1】:

在 cmets 中,情况如下:

int main(void) {
    char* test = malloc(1024);     /* You allocate, great! */
    test = "Hello!";               /* Huh, what's this? You point 'test' 
                                    * to some area in the code section.
                                    * Valid, but considering you just 
                                    * allocated some memory, strange */
    printf("%s\n", test);          /* Print out a string from the code
                                    * section: fine. */
    free(test);                    /* What?! You want to try to free() the
                                    * memory in the code section? That's a 
                                    * big no-no! */
    return 0;                      /* whatever */
}

现在,你应该做什么:

int main(void) {
    char* test = malloc(1024);     /* You allocate, great! */
    strcpy(test, "Hello!");        /* Copy some data into that 
                                    * allocated memory */
    printf("%s\n", test);          /* Print out a string from the
                                    * heap: fine. */
    free(test);                    /* Free that allocated memory! */
    return 0;                      /* aaaand, we're done */
}

【讨论】:

  • 你想要 7,而不是 6。
  • 为了安全起见,您必须在strncpy 之后处理 nul 终止符。
  • 不错!字符串“Hello!”在哪里?传递给 strncpy() 被存储?堆栈作为局部变量?调用后是否立即丢弃?
  • 更新了我的答案。
  • @Gala,堆对于从不改变的静态字符串不是很有用,但对于确实改变的数据或大块数据很有用(否则堆栈可能会溢出和其他讨厌的东西)
【解决方案2】:

欢迎来到复杂的 C 世界!

基本上,您正在用地址"Hello!"(即静态不可变数组)覆盖指针test

它崩溃是因为你试图释放一个你没有创建的东西。

您应该使用strcpy() 或循环将您的字符串复制到text

【讨论】:

  • 由于历史原因,C 字符串文字不是const"Hello!" 的类型是 char[7],而不是 const char[7]。但是尝试修改字符串文字有未定义的行为。
  • @KeithThompson 谢谢,我没想到会这样。已编辑。
【解决方案3】:

test 最初指向由 malloc 分配的大小为 1024 的内存。 现在在下一行中,您将 test 指向“Hello!”引用的内存。 所以你的测试指针现在指向“你好!”而不是您首先使用malloc分配的内容。 现在您正在尝试释放“Hello!”,这是无效的,因为该内存不是使用 malloc 分配的,因此您的编程正在崩溃。

char* test = malloc(1024);
test = "Hello!"; /* This is wrong. You pointer is pointing to "Hello!" string base address */

存储“你好!”在测试分配的内存中,你需要使用memcpy。 所以而不是:

test = "Hello!"

使用:

memcpy(test, "Hello!", sizeof("Hello!");

这将修复您的代码。

【讨论】:

  • strcpy 在遇到空字符时终止,memcpy 将为您复制最后一个参数中指定的确切字节,无论源是否为空终止。在这种情况下,它们中的任何一个都对您有用。但是尝试养成使用“strncpy 而不是 strcpy”或 memcpy 的习惯。但是如果 strncpy 是特定于字符串的,我宁愿说使用 memcpy。
  • 在这种情况下,memcpy(test, "Hello!", sizeof("Hello!");strcpy(test, "Hello!"); 的作用完全相同——除了你必须指定源字符串两次,这很容易出错。 strncpy 不小心非常使用会很危险;它不是真正的字符串函数(请参阅我在其他 cmets 中链接到的文章)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-09
  • 1970-01-01
  • 1970-01-01
  • 2012-02-21
  • 1970-01-01
  • 2016-01-21
  • 1970-01-01
相关资源
最近更新 更多