【问题标题】:C: Returning char* from a function crashes printfC:从函数返回 char* 会使 printf 崩溃
【发布时间】:2016-03-22 14:12:09
【问题描述】:

这是包含printf 的代码(带有行号,来自think.c):

30: char *think = getRandomMemory();
31: printf("\33[2K\r");
32: if(think == NULL)
33:     think = "NULL";
34: printf("I have an idea: %s\n", think);
35: parse(think);
36: freeMemory(think);
37: printf("> ");

来自getRandomMemory() 的代码确保返回的指针指向堆分配空间:

char *getRandomMemory()
{
    char *ret;

    // --SNIP--

    size_t l = strlen(ret) + 1;
    char *rret = getMemory(sizeof(char) * l);
    for(int i = 0; i < l; i++)
        rret[i] = ret[i];
    printf("--- %s ---\n", rret);
    return rret;
}

最后这就是 gdb 在运行它时给我的。请注意,“--- test ---”来自上面的“printf("--- %s ---\n", rret)”:

(gdb) run
Starting program: /home/v10lator/Private/projekte/KI/Lizzy 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Loading Lizzy 0.1... Done!

> --- test ---
[New Thread 0x7ffff781f700 (LWP 32359)]

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff781f700 (LWP 32359)]
0x00007ffff7869490 in _IO_vfprintf_internal (s=<optimized out>, format=<optimized out>, 
ap=ap@entry=0x7ffff781ee68) at vfprintf.c:1642
1642    vfprintf.c: Datei oder Verzeichnis nicht gefunden.
(gdb) bt
#0  0x00007ffff7869490 in _IO_vfprintf_internal (s=<optimized out>, format=<optimized out>, 
ap=ap@entry=0x7ffff781ee68) at vfprintf.c:1642
#1  0x00007ffff7919235 in ___printf_chk (flag=1, format=<optimized out>) at printf_chk.c:35
#2  0x00000000004016bc in printf () at /usr/include/bits/stdio2.h:104
#3  run (first=<optimized out>) at think.c:34
#4  0x00007ffff7bc64c6 in start_thread (arg=0x7ffff781f700) at pthread_create.c:333
#5  0x00007ffff790a86d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109

我真的不知道这里出了什么问题,所以希望有人能看到这个错误。

//编辑:忘记了 getMemory/freeMemory 函数:

/*
  * This allocates memory.
  * The difference between usig malloc directly is that this function will
  * print an error and exit the program in case something bad happens.
  */
char *getMemory(size_t size)
{
    char *mem = malloc(size);
    if(mem == NULL)
        crashWithMsg("Internal error (malloc failed)!");
    return mem;
}

/*
 * This deallocates memory.
 * The difference between using free directly is that this function will
 * set the pointer to NULL afterwards.
 */
void freeMemory(void **ptr)
{
    free(*ptr);
    *ptr = NULL;
}

【问题讨论】:

  • getRandomMemory: rret[i] = ret[i]; - ret 没有指向任何正确初始化的内存,所以你有UB(也有:size_t l = strlen(ret) + 1;)。
  • ret初始化为一个适当的字符串和适当的终止?
  • 你能告诉我们(或者更确切地说展示我们)getMemory 做了什么吗?
  • 不幸的是,看似正确的行为是未定义行为的可能结果之一。请尝试创建一个Minimal, Complete, and Verifiable Example 并向我们展示,因为现在除了猜测之外什么都做不了。
  • 寻求调试帮助的问题(“为什么这段代码不起作用?”)必须包括所需的行为、特定的问题或错误以及在问题本身中重现它所需的最短代码。没有明确问题陈述的问题对其他读者没有用处。请参阅:如何创建minimal reproducible example

标签: c pointers return printf segmentation-fault


【解决方案1】:

问题是你打电话给freeMemory

freeMemory(think);

您已经编写了该函数以获取指向要释放的内存的指针的地址,而不是指针本身。所以你需要调用它:

freeMemory(&think);

【讨论】:

  • 感谢您的提醒,但程序在调用freeMemory之前就崩溃了。
  • 我明白了。不知道发生了什么,但我也注意到您有时会在释放它之前将固定的"NULL" 字符串分配给think。这也会导致内存错误。但看起来你的问题发生在此之前。
  • @Thomas 你还没有以错误的方式之前调用freeMemory?你不循环运行你的代码?
  • @JoachimPileborg 不,freeMemory 之前没有被调用。是的,这段代码确实在循环中运行,嗯,更像是一个递归线程。但线程似乎也不是问题。如果你想看看,这是我到目前为止的示例代码:pastie.org/10635991 ...它也适用于线程,但一切正常。
  • @Thomas 您递归地创建线程,何时在第一个线程中发生崩溃?第二?经过许多线程?也许这只是通过创建多个线程来耗尽资源?哦,你确实释放了你在主循环中分配的内存吗? :)
【解决方案2】:

[删除错误陈述]

为什么不使用strcpy()

【讨论】:

  • 看看OP如何计算字符串的长度,以及OP如何复制。如果原始字符串中有终止符,它将被复制。但是是的,OP 应该改用 strcpy
猜你喜欢
  • 1970-01-01
  • 2013-11-25
  • 2021-08-14
  • 1970-01-01
  • 2017-04-29
  • 2016-08-03
  • 1970-01-01
  • 2012-02-18
  • 2018-05-09
相关资源
最近更新 更多