检查c指针的Segfault(LCTHW - Ex17,额外信用)

时间:2014-05-06 07:07:18

标签: c valgrind

我正在努力学习艰难道路学习练习17的额外功劳。

我在试图找出Valgrind抱怨的内容时陷入困境。

我做了很多研究,发现this Stackoverflow post似乎基本上是同一个问题,但解决方案并不适合我。我已经在Github和Pastebin上看了一些其他的解决方案,但代码是如此不同,以至于对于刚刚学习C的人我无法理解它。

非常感谢任何帮助。

相关代码:

void Database_set(struct Connection *conn, int id, const char *name, const char *email)
{
    struct Address *addr = &conn->db->rows[id];
    if (addr->set) die("Already set, delete it first", conn);

    addr->set = 1;

    const int MAX_DATA = conn->db->MAX_DATA;
    addr->name = malloc(sizeof(char) * MAX_DATA);
    addr->email = malloc(sizeof(char) * MAX_DATA);

    char *res = strncpy(addr->name, name, MAX_DATA);
    if (!res) die("Name copy failed", conn);
    res[conn->db->MAX_DATA - 1] = '\0';

    res = strncpy(addr->email, email, MAX_DATA);
    if (!res) die("Email copy failed", conn);
    res[conn->db->MAX_DATA - 1] = '\0';
}

Here是我完整的原始源代码。

以下是我的valgrind错误。

$ valgrind  ./ex17 db.dat s 1 zed zed@zedshaw.com
==22971== Memcheck, a memory error detector
==22971== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==22971== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==22971== Command: ./ex17 db.dat s 1 zed zed@zedshaw.com
==22971== 
==22971== Invalid read of size 4
==22971==    at 0x400D15: Database_set (ex17.c:133)
==22971==    by 0x40109C: main (ex17.c:208)
==22971==  Address 0x51f237c is not stack'd, malloc'd or (recently) free'd
==22971== 
==22971== Invalid write of size 4
==22971==    at 0x400D31: Database_set (ex17.c:135)
==22971==    by 0x40109C: main (ex17.c:208)
==22971==  Address 0x51f237c is not stack'd, malloc'd or (recently) free'd
==22971== 
==22971== Invalid write of size 1
==22971==    at 0x4C2C1B7: strncpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22971==    by 0x400DE1: Database_set (ex17.c:145)
==22971==    by 0x40109C: main (ex17.c:208)
==22971==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==22971== 
==22971== 
==22971== Process terminating with default action of signal 11 (SIGSEGV)
==22971==  Access not within mapped region at address 0x0
==22971==    at 0x4C2C1B7: strncpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22971==    by 0x400DE1: Database_set (ex17.c:145)
==22971==    by 0x40109C: main (ex17.c:208)
==22971==  If you believe this happened as a result of a stack
==22971==  overflow in your program's main thread (unlikely but
==22971==  possible), you can try to increase the size of the
==22971==  main thread stack using the --main-stacksize= flag.
==22971==  The main thread stack size used in this run was 8388608.
==22971== 
==22971== HEAP SUMMARY:
==22971==     in use at exit: 1,624 bytes in 5 blocks
==22971==   total heap usage: 5 allocs, 0 frees, 1,624 bytes allocated
==22971== 
==22971== LEAK SUMMARY:
==22971==    definitely lost: 512 bytes in 1 blocks
==22971==    indirectly lost: 0 bytes in 0 blocks
==22971==      possibly lost: 0 bytes in 0 blocks
==22971==    still reachable: 1,112 bytes in 4 blocks
==22971==         suppressed: 0 bytes in 0 blocks
==22971== Rerun with --leak-check=full to see details of leaked memory
==22971== 
==22971== For counts of detected and suppressed errors, rerun with: -v
==22971== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 2 from 2)
Segmentation fault (core dumped)

1 个答案:

答案 0 :(得分:-1)

我会检查你的代码中第133,135和145行会发生什么,这就是你被告知问题所在的地方。你巧妙地没有发布任何行号,但很容易弄清楚读取和写入addr-> set会导致问题,这意味着addr是垃圾。

检查id的值是什么。检查是否设置了conn->; db。

有点批评:调用strncpy是危险的。您的教练不应该允许您使用它。它完全不需要,因为您只需分配正确大小的名称和电子邮件即可。我从来没有见过有人检查strcpy或strncpy的返回值。如果失败,它会崩溃。一致地使用变量。在一个地方使用MAX_DATA,在另一个地方使用conn-> db-> MAX_DATA可以防止出现错误。找到有意义的变量名。 MAX_DATA没有意义。