【问题标题】:C Program sometimes giving segfaultC程序有时会给出段错误
【发布时间】:2015-10-18 01:14:17
【问题描述】:

由于某种原因,我的程序有时可以正常运行,有时只是以段错误结束。我正在尝试创建 malloc 的实现。如果我从5000 的大小开始,然后我做malloc(1000),我预计剩余内存大小为3984(由于内存条目的大小也是如此)。

当我输出带有printf 的剩余内存时,它有时会打印3984,有时会以分段错误结束。任何帮助将不胜感激。

#include "malloc-free-impl.h"

static char memArr[5000];
static char* memArrPtr = &memArr;
static MemEntryPtr head = NULL;

void* custom_malloc(int size) {
    if (head == NULL) {
        head = (MemEntryPtr) memArrPtr;
        head->prev = NULL;
        head->next = NULL;
        head->isFree = 1;
        head->size = sizeof(memArr) - sizeof(head);
    }

    MemEntryPtr curr = head;
    while (curr->isFree != 1 && curr->size > size + sizeof(struct MemEntry)) {
        curr = curr->next;
    }

    if ((curr->size - (size)) > sizeof(struct MemEntry)) {
        MemEntryPtr newMemEntry = (MemEntryPtr) (&curr + sizeof(struct MemEntry) + size);
        newMemEntry->prev = curr;
        newMemEntry->next = NULL;
        newMemEntry->isFree = 1;
        newMemEntry->size = curr->size - (size + sizeof(newMemEntry));

        printf("%d\n", newMemEntry->size);

        curr->isFree = 0;
        curr->next = newMemEntry;

        return newMemEntry;
    }

    return NULL;
}

void* custom_free(MemEntryPtr memBlock) {
    memBlock->isFree = 1;
    return NULL;
}

int main(int argc, char** argv) {
    MemEntryPtr node = (MemEntryPtr) custom_malloc(1000);
    return 1;
}

【问题讨论】:

  • 您的指针算法在 pub 中。尝试将 newMemEntryPtr 行更改为 MemEntryPtr newMemEntry = (MemEntryPtr) ((char *)curr + sizeof(struct MemEntry) + size);
  • @amdixon 非常感谢,这似乎已经解决了这个问题。如果您将其发布为答案,我将选择它作为修复。
  • 另外:你在哪里检查“custom_malloc() failed”???
  • @paulsm4 我正在尝试大量的打印消息,并使用 GDB 尝试查看 seg 错误发生在哪里,但这并没有太大帮助。我想我应该学会使用 valgrind。

标签: c segmentation-fault malloc


【解决方案1】:

ma​​lloc-free-impl.h(复制问题的最小存根)

#ifndef _malloc_free_impl_
#define _malloc_free_impl_

struct MemEntry
{
    struct MemEntry *prev, *next;
      int isFree, size;
};

typedef struct MemEntry * MemEntryPtr;

#endif

valgrind 怎么说

$ gcc -g test.c -o test
test.c:8:26: warning: initialization from incompatible pointer type [enabled by default]
 static char* memArrPtr = &memArr;
                          ^
$ valgrind ./test
==30474== Memcheck, a memory error detector
==30474== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==30474== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==30474== Command: ./test
==30474== 
==30474== Invalid write of size 8
==30474==    at 0x4005FF: custom_malloc (test.c:27)
==30474==    by 0x4006A3: main (test.c:49)
==30474==  Address 0xfff001f90 is not stack'd, malloc'd or (recently) free'd
==30474== 
==30474== 
==30474== Process terminating with default action of signal 11 (SIGSEGV)
==30474==  Access not within mapped region at address 0xFFF001F90
==30474==    at 0x4005FF: custom_malloc (test.c:27)
==30474==    by 0x4006A3: main (test.c:49)
==30474==  If you believe this happened as a result of a stack
==30474==  overflow in your program's main thread (unlikely but
==30474==  possible), you can try to increase the size of the
==30474==  main thread stack using the --main-stacksize= flag.
==30474==  The main thread stack size used in this run was 8388608.
==30474== 
==30474== HEAP SUMMARY:
==30474==     in use at exit: 0 bytes in 0 blocks
==30474==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==30474== 
==30474== All heap blocks were freed -- no leaks are possible
==30474== 
==30474== For counts of detected and suppressed errors, rerun with: -v
==30474== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

valgrind 在第 27 行反对无效写入:

25   if ((curr->size - (size)) > sizeof(struct MemEntry)) {
26     MemEntryPtr newMemEntry = (MemEntryPtr) (&curr + sizeof(struct MemEntry) + size);
27     newMemEntry->prev = curr;

尤其是内存地址newMemEntry->prev无效。

追溯,只要 newMemEntry 是一个有效的 MemEntryPtr 地址,这个内存地址就应该是有效的。

但是newMemEntry的赋值是

  • 添加与 sizeof char 对齐的大小
  • 将此指针算法应用于类型 ( MemEntryPtr * ) 的基指针而不是 char * 以匹配 char 对齐的大小

更改代码以在基本 char * 上执行指针运算,因为所有 sizeofs 都考虑到这一点,我们得到:

25   if ((curr->size - (size)) > sizeof(struct MemEntry)) {
26     MemEntryPtr newMemEntry = (MemEntryPtr) ((char *)curr + sizeof(struct MemEntry) + size);
27     newMemEntry->prev = curr;

并使用 valgrind 检查此更改:

valgrind 重新检查

$ gcc -g test.c -o test
test.c:8:26: warning: initialization from incompatible pointer type [enabled by default]
 static char* memArrPtr = &memArr;
                          ^
$ valgrind ./test
==1212== Memcheck, a memory error detector
==1212== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==1212== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==1212== Command: ./test
==1212== 
3984
==1212== 
==1212== HEAP SUMMARY:
==1212==     in use at exit: 0 bytes in 0 blocks
==1212==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==1212== 
==1212== All heap blocks were freed -- no leaks are possible
==1212== 
==1212== For counts of detected and suppressed errors, rerun with: -v
==1212== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

现在内存使用正常 - 没有段错误

【讨论】:

  • 谢谢。我试图用 GDB 查找段错误,但它并没有从回溯中告诉我太多,只是问题出在 custom_malloc() 方法中。
猜你喜欢
  • 2021-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-31
  • 2018-04-12
相关资源
最近更新 更多