C malloc 어설 션 실패가 발생하는 이유는 무엇입니까?


85

OpenCL 구현에 대해 벤치마킹 할 수 있도록 분할 및 정복 다항식 알고리즘을 구현하고 있지만 malloc작업을 수행 할 수 없습니다 . 프로그램을 실행하면 여러 가지를 할당하고 몇 가지 사항을 확인한 다음 size/2알고리즘 에을 보냅니다 . 그런 다음 malloc다시 라인을 쳤을 때 다음과 같이 뱉어냅니다.

malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
Aborted

문제의 라인은 다음과 같습니다.

int *mult(int size, int *a, int *b) {
    int *out,i, j, *tmp1, *tmp2, *tmp3, *tmpa1, *tmpa2, *tmpb1, *tmpb2,d, *res1, *res2;
    fprintf(stdout, "size: %d\n", size);

    out = (int *)malloc(sizeof(int) * size * 2);
}

나는으로 크기를 확인 fprintf했고 그것은 양의 정수 (보통 그 시점에서 50)이다. malloc일반 번호로 전화 를 시도했지만 여전히 오류가 발생합니다. 나는 무슨 일이 일어나고 있는지 어리둥절하고 지금까지 내가 찾은 Google의 어떤 것도 도움이되지 않습니다.

무슨 일이 일어나고 있는지 아이디어가 있습니까? 컴파일러 오류 인 경우 최신 GCC를 컴파일하는 방법을 알아 내려고 노력하고 있지만 정말 의심 스럽습니다.


나는 문제가 실제로 그 앞에 한 줄이라고 생각합니다. 이중 무료일까요?
Mitch Wheat

프로그램의 세 번째 줄 : int * mult (int size, int * a, int * b) {int * out, i, j, * tmp1, * tmp2, * tmp3, * tmpa1, * tmpa2, * tmpb1, * tmpb2 , d, * res1, * res2; fprintf (stdout, "크기 : % d \ n", 크기); out = (int *) malloc (sizeof (int) * size * 2);
Chris

답변:


98

메모리가 손상되었을 가능성이 99.9 % (버퍼 오버플로 또는 언더 플로, 해제 된 후 포인터에 쓰기, 같은 포인터에서 두 번 free 호출 등)

Valgrind 에서 코드를 실행하여 프로그램이 잘못한 부분을 확인하십시오.


1
결정된. Valgrind가 확실히 도움을주었습니다. 내 오래된 matlab 코드를 잘못 복사하고 j를 반복하는 for 루프가 있었고 내부에서 j ++를 사용하여 작성중인 배열을 덮어 쓰고 어떻게 든 malloc이 실패했습니다. 도와 주셔서 감사합니다!
크리스

Valgrind는이 오류가 발생했을 때 무슨 일이 일어나고 있는지 파악하는 데 필요한 도구였습니다. 언급 해 주셔서 감사합니다.
alexwells

77

이런 일이 발생 하는지 더 잘 이해하기 위해 @ r-samuel-klatchko의 답변을 조금 확장하고 싶습니다.

를 호출 할 때 malloc실제로 일어나는 일은 단순히 재생할 메모리 덩어리를 제공하는 것보다 조금 더 복잡합니다. 내부적 malloc으로은 (는) 제공 한 메모리 (가장 중요한 것은 크기)에 대한 일부 관리 정보를 유지하므로를 호출 할 때 해제 할 free메모리 양과 같은 정보를 알 수 있습니다. 이 정보는 일반적으로에서 메모리 위치를 반환하기 직전에 보관됩니다 malloc. 더 자세한 정보는 internet ™ 에서 찾을 수 있지만 (매우) 기본적인 아이디어는 다음과 같습니다.

+------+-------------------------------------------------+
+ size |                  malloc'd memory                +
+------+-------------------------------------------------+
       ^-- location in pointer returned by malloc

이를 기반으로 (그리고 크게 단순화)를 호출 할 때 malloc사용 가능한 메모리의 다음 부분에 대한 포인터를 가져와야합니다. 이 작업을 수행하는 매우 간단한 방법 중 하나는 이전에 제공 한 메모리 비트를보고 메모리에서 size바이트를 더 아래 (또는 위로) 이동하는 것 입니다. 이 구현으로, 당신은 할당 한 후이 같은 것을보고 당신의 기억과 끝 p1, p2그리고 p3:

+------+----------------+------+--------------------+------+----------+
+ size |                | size |                    | size |          +
+------+----------------+------+--------------------+------+----------+
       ^- p1                   ^- p2                       ^- p3

그렇다면 오류의 원인은 무엇입니까?

글쎄, 당신의 코드가 당신이 할당 한 메모리의 양을 넘어서 잘못 쓴다고 상상 해보자. 코드가 너무 많은 데이터를 작성하여 의 필드에 p2있는 내용을 덮어 쓰기 시작 한다고 가정 해보십시오 . 이제 다음에 호출 하면 반환 된 마지막 메모리 위치를보고 크기 필드로 이동 한 다음 거기에서 메모리 할당을 시작합니다. 그러나 코드가 덮어 쓰기되었으므로이 메모리 위치는 더 이상 이전에 할당 된 메모리 뒤에 있지 않습니다.p3sizemallocp3 + sizesize

말할 필요도없이 이것은 혼란을 일으킬 수 있습니다! malloc따라서 의 구현 자는 이러한 문제 (및 기타 문제)가 발생하려고 할 때이를 포착하기 위해 여러 건전성 검사를 시도하는 여러 "어설 션"또는 검사를 넣었습니다. 특정 경우에 이러한 주장이 위반되어 malloc중단 되어 코드가 실제로 수행해서는 안되는 작업을 수행하려고한다는 것을 알려줍니다.

이전에 언급했듯이 이것은 지나치게 단순화 한 것이지만 요점을 설명하는 것으로 충분합니다. glibc 구현은 malloc5k 라인 이상이며 좋은 동적 메모리 할당 메커니즘을 구축하는 방법에 대한 상당한 양의 연구가 있었으므로 모든 것을 SO 답변으로 다루는 것은 불가능합니다. 바라건대 이것이 실제로 문제를 일으키는 원인에 대한 약간의 견해를 제공했기를 바랍니다!


14

Valgrind 사용에 대한 나의 대체 솔루션 :

친구가 프로그램을 디버깅하는 것을 도왔 기 때문에 매우 기쁩니다. 그의 프로그램은 malloc()GDB의 동일한 오류 메시지와 함께이 정확한 문제 ( 중단 원인)를 가졌습니다 .

Address Sanitizer 를 사용하여 그의 프로그램을 컴파일했습니다.

gcc -Wall -g3 -fsanitize=address -o new new.c
              ^^^^^^^^^^^^^^^^^^

그리고 gdb new. 프로그램이 SIGABRT후속에서 원인으로 종료되면 malloc()유용한 정보가 많이 인쇄됩니다.

=================================================================
==407==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6060000000b4 at pc 0x7ffffe49ed1a bp 0x7ffffffedc20 sp 0x7ffffffed3c8
WRITE of size 104 at 0x6060000000b4 thread T0
    #0 0x7ffffe49ed19  (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x5ed19)
    #1 0x8001dab in CreatHT2 /home/wsl/Desktop/hash/new.c:59
    #2 0x80031cf in main /home/wsl/Desktop/hash/new.c:209
    #3 0x7ffffe061b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #4 0x8001679 in _start (/mnt/d/Desktop/hash/new+0x1679)

0x6060000000b4 is located 0 bytes to the right of 52-byte region [0x606000000080,0x6060000000b4)
allocated by thread T0 here:
    #0 0x7ffffe51eb50 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb50)
    #1 0x8001d56 in CreatHT2 /home/wsl/Desktop/hash/new.c:55
    #2 0x80031cf in main /home/wsl/Desktop/hash/new.c:209
    #3 0x7ffffe061b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)

출력, 특히 스택 추적을 살펴 보겠습니다.

첫 번째 부분은에 잘못된 쓰기 작업이 있음을 나타 new.c:59냅니다. 그 줄은

memset(len,0,sizeof(int*)*p);
             ^^^^^^^^^^^^

두 번째 부분은 잘못된 쓰기가 발생한 메모리가 new.c:55. 그 줄은

if(!(len=(int*)malloc(sizeof(int)*p))){
                      ^^^^^^^^^^^

그게 다야. 몇 시간 동안 친구를 혼란스럽게하는 버그를 찾는 데 30 분도 채 걸리지 않았습니다. 그는 실패를 찾을 malloc()수 있었지만 이전 코드에서이 오류를 발견하지 못한 채 실패한 후속 호출입니다.

요약 : -fsanitize=addressGCC 또는 Clang을 사용해보십시오 . 메모리 문제를 디버깅 할 때 매우 유용 할 수 있습니다.


1
당신은 내 생명을 구했습니다.
Nate Symer


2

귀하의 메시지와 유사한 다음 메시지를 받았습니다.

    프로그램 : malloc.c : 2372 : sysmalloc : Assertion`(old_top == (((mbinptr) (((char *) & ((av)-> bins [((1)-1) * 2])))-__builtin_offsetof (구조체 malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size)> = (unsigned long) ((((__ builtin_offsetof (struct malloc_chunk, fd_nextsize)) + ((2 * (sizeof (size_t)))-1)) & ~ ((2 * (sizeof (size_t)))-1))) && ((old_top)-> size & 0x1) && ((unsigned long) old_end & pagemask) == 0) '실패했습니다.

malloc을 사용할 때 이전에 일부 메서드 호출을 실수했습니다. 부호없는 char 배열에 필드를 추가 할 때 sizeof ()-연산자 이후에 인수를 업데이트 할 때 곱셈 기호 '*'를 '+'로 잘못 덮어 썼습니다.

내 경우 오류를 담당하는 코드는 다음과 같습니다.

    UCHAR * b = (UCHAR *) malloc (sizeof (UCHAR) +5);
    b [INTBITS] = (일부 계산);
    b [BUFSPC] = (일부 계산);
    b [BUFOVR] = (일부 계산);
    b [BUFMEM] = (일부 계산);
    b [MATCHBITS] = (일부 계산);

나중에 다른 방법으로 malloc을 다시 사용했는데 위에 표시된 오류 메시지가 생성되었습니다. 전화는 (충분히 간단합니다) :

    UCHAR * b = (UCHAR *) malloc (sizeof (UCHAR) * 50);

첫 번째 호출에서 '+'기호를 사용하면 배열의 즉각적인 초기화 (배열에 할당되지 않은 메모리 덮어 쓰기)와 결합하여 잘못된 미적분으로 이어져 malloc의 메모리 맵에 약간의 혼란이 생겼습니다. 따라서 두 번째 호출이 잘못되었습니다.


0

sizeof (int)로 곱하는 것을 잊었 기 때문에이 오류가 발생했습니다. malloc (..)에 대한 인수는 기계 단어 수가 아니라 바이트 수입니다.


0

나는 같은 문제가 생겼다. 나는 새로운 char * string 데이터를 추가하기 위해 루프에서 n을 통해 malloc을 다시 사용했다. 나는 같은 문제에 직면했지만 할당 된 메모리 void free()문제가 해결 된 후 정렬되었습니다.


-2

Visual C에서 Linux를 통해 gcc로 하나의 응용 프로그램을 포팅하고 있었고 동일한 문제가 발생했습니다.

malloc.c : 3096 : sYSMALLOc : UBUNTU 11에서 gcc를 사용한 어설 션.

동일한 코드를 Suse 배포 (다른 컴퓨터)로 옮겼는데 아무런 문제가 없습니다.

나는 문제가 우리 프로그램이 아니라 자체 libc에 있다고 생각합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.