내 (C ++) 프로그램을 실행하면이 오류와 함께 충돌합니다.
* glibc 감지 됨 * ./load : 이중 사용 가능 또는 손상 (! prev) : 0x0000000000c6ed50 ***
오류를 어떻게 추적 할 수 있습니까?
나는 std::cout
성공하지 않고 print ( ) 문을 사용해 보았습니다 . 수 gdb
이 쉽게?
답변
glibc를 사용하는 경우 MALLOC_CHECK_
환경 변수를로 설정할 수 있습니다 2
. 이렇게하면 glibc가 오류 허용 버전을 사용합니다.malloc
하여 이중 해제가 완료되는 지점에서 프로그램이 중단됩니다.
set environment MALLOC_CHECK_ 2
프로그램을 실행하기 전에 명령 을 사용하여 gdb에서 설정할 수 있습니다 . 프로그램이 중단되어야하며 free()
호출이 백 트레이스에 표시됩니다.
자세한 내용은 man 페이지malloc()
를 참조하십시오.
답변
두 가지 이상의 가능한 상황이 있습니다.
- 동일한 항목을 두 번 삭제합니다.
- 할당되지 않은 항목을 삭제하고 있습니다.
첫 번째의 경우 삭제 된 모든 포인터를 NULL로 지정하는 것이 좋습니다.
세 가지 옵션이 있습니다.
- 신규 오버로드 및 할당 삭제 및 추적
- 예, gdb를 사용하십시오. 그러면 충돌에서 역 추적을 얻을 수 있으며 아마도 매우 유용 할 것입니다.
- 제안 된대로-Valgrind를 사용하십시오-시작하기가 쉽지는 않지만 앞으로 수천 배의 시간을 절약 할 수 있습니다.
답변
gdb를 사용할 수 있지만 먼저 Valgrind를 사용해 보겠습니다 . 참고 항목 빠른 시작 가이드 .
간단히 말해서 Valgrind는 프로그램을 계측하여 이중 해제 및 할당 된 메모리 블록의 끝을 지나서 쓰기 (힙을 손상시킬 수 있음)와 같은 동적 할당 메모리를 사용할 때 여러 종류의 오류를 감지 할 수 있습니다. 오류가 발생 하는 즉시이를 감지하고보고 하여 문제의 원인을 직접 가리 킵니다.
답변
세 가지 기본 규칙 :
- 해제
NULL
후 포인터 설정 NULL
해제하기 전에 확인하십시오 .NULL
처음에 포인터를 초기화 하십시오.
이 세 가지의 조합은 아주 잘 작동합니다.
답변
valgrind
디버깅하는 데 사용할 수 있습니다 .
#include<stdio.h>
#include<stdlib.h>
int main()
{
char *x = malloc(100);
free(x);
free(x);
return 0;
}
[sand@PS-CNTOS-64-S11 testbox]$ vim t1.c
[sand@PS-CNTOS-64-S11 testbox]$ cc -g t1.c -o t1
[sand@PS-CNTOS-64-S11 testbox]$ ./t1
*** glibc detected *** ./t1: double free or corruption (top): 0x00000000058f7010 ***
======= Backtrace: =========
/lib64/libc.so.6[0x3a3127245f]
/lib64/libc.so.6(cfree+0x4b)[0x3a312728bb]
./t1[0x400500]
/lib64/libc.so.6(__libc_start_main+0xf4)[0x3a3121d994]
./t1[0x400429]
======= Memory map: ========
00400000-00401000 r-xp 00000000 68:02 30246184 /home/sand/testbox/t1
00600000-00601000 rw-p 00000000 68:02 30246184 /home/sand/testbox/t1
058f7000-05918000 rw-p 058f7000 00:00 0 [heap]
3a30e00000-3a30e1c000 r-xp 00000000 68:03 5308733 /lib64/ld-2.5.so
3a3101b000-3a3101c000 r--p 0001b000 68:03 5308733 /lib64/ld-2.5.so
3a3101c000-3a3101d000 rw-p 0001c000 68:03 5308733 /lib64/ld-2.5.so
3a31200000-3a3134e000 r-xp 00000000 68:03 5310248 /lib64/libc-2.5.so
3a3134e000-3a3154e000 ---p 0014e000 68:03 5310248 /lib64/libc-2.5.so
3a3154e000-3a31552000 r--p 0014e000 68:03 5310248 /lib64/libc-2.5.so
3a31552000-3a31553000 rw-p 00152000 68:03 5310248 /lib64/libc-2.5.so
3a31553000-3a31558000 rw-p 3a31553000 00:00 0
3a41c00000-3a41c0d000 r-xp 00000000 68:03 5310264 /lib64/libgcc_s-4.1.2-20080825.so.1
3a41c0d000-3a41e0d000 ---p 0000d000 68:03 5310264 /lib64/libgcc_s-4.1.2-20080825.so.1
3a41e0d000-3a41e0e000 rw-p 0000d000 68:03 5310264 /lib64/libgcc_s-4.1.2-20080825.so.1
2b1912300000-2b1912302000 rw-p 2b1912300000 00:00 0
2b191231c000-2b191231d000 rw-p 2b191231c000 00:00 0
7ffffe214000-7ffffe229000 rw-p 7ffffffe9000 00:00 0 [stack]
7ffffe2b0000-7ffffe2b4000 r-xp 7ffffe2b0000 00:00 0 [vdso]
ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0 [vsyscall]
Aborted
[sand@PS-CNTOS-64-S11 testbox]$
[sand@PS-CNTOS-64-S11 testbox]$ vim t1.c
[sand@PS-CNTOS-64-S11 testbox]$ cc -g t1.c -o t1
[sand@PS-CNTOS-64-S11 testbox]$ valgrind --tool=memcheck ./t1
==20859== Memcheck, a memory error detector
==20859== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==20859== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==20859== Command: ./t1
==20859==
==20859== Invalid free() / delete / delete[]
==20859== at 0x4A05A31: free (vg_replace_malloc.c:325)
==20859== by 0x4004FF: main (t1.c:8)
==20859== Address 0x4c26040 is 0 bytes inside a block of size 100 free'd
==20859== at 0x4A05A31: free (vg_replace_malloc.c:325)
==20859== by 0x4004F6: main (t1.c:7)
==20859==
==20859==
==20859== HEAP SUMMARY:
==20859== in use at exit: 0 bytes in 0 blocks
==20859== total heap usage: 1 allocs, 2 frees, 100 bytes allocated
==20859==
==20859== All heap blocks were freed -- no leaks are possible
==20859==
==20859== For counts of detected and suppressed errors, rerun with: -v
==20859== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
[sand@PS-CNTOS-64-S11 testbox]$
[sand@PS-CNTOS-64-S11 testbox]$ valgrind --tool=memcheck --leak-check=full ./t1
==20899== Memcheck, a memory error detector
==20899== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==20899== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==20899== Command: ./t1
==20899==
==20899== Invalid free() / delete / delete[]
==20899== at 0x4A05A31: free (vg_replace_malloc.c:325)
==20899== by 0x4004FF: main (t1.c:8)
==20899== Address 0x4c26040 is 0 bytes inside a block of size 100 free'd
==20899== at 0x4A05A31: free (vg_replace_malloc.c:325)
==20899== by 0x4004F6: main (t1.c:7)
==20899==
==20899==
==20899== HEAP SUMMARY:
==20899== in use at exit: 0 bytes in 0 blocks
==20899== total heap usage: 1 allocs, 2 frees, 100 bytes allocated
==20899==
==20899== All heap blocks were freed -- no leaks are possible
==20899==
==20899== For counts of detected and suppressed errors, rerun with: -v
==20899== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
[sand@PS-CNTOS-64-S11 testbox]$
한 가지 가능한 수정 :
#include<stdio.h>
#include<stdlib.h>
int main()
{
char *x = malloc(100);
free(x);
x=NULL;
free(x);
return 0;
}
[sand@PS-CNTOS-64-S11 testbox]$ vim t1.c
[sand@PS-CNTOS-64-S11 testbox]$ cc -g t1.c -o t1
[sand@PS-CNTOS-64-S11 testbox]$ ./t1
[sand@PS-CNTOS-64-S11 testbox]$
[sand@PS-CNTOS-64-S11 testbox]$ valgrind --tool=memcheck --leak-check=full ./t1
==20958== Memcheck, a memory error detector
==20958== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==20958== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==20958== Command: ./t1
==20958==
==20958==
==20958== HEAP SUMMARY:
==20958== in use at exit: 0 bytes in 0 blocks
==20958== total heap usage: 1 allocs, 1 frees, 100 bytes allocated
==20958==
==20958== All heap blocks were freed -- no leaks are possible
==20958==
==20958== For counts of detected and suppressed errors, rerun with: -v
==20958== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
[sand@PS-CNTOS-64-S11 testbox]$
Valgrind Link 사용에 대한 블로그를 확인하십시오.
답변
최신 C ++ 컴파일러를 사용하면 새니 타이 저를 사용할 수 있습니다. 를 하여 추적 .
샘플 예 :
내 프로그램 :
$cat d_free.cxx
#include<iostream>
using namespace std;
int main()
{
int * i = new int();
delete i;
//i = NULL;
delete i;
}
주소 새니 타이 저로 컴파일 :
# g++-7.1 d_free.cxx -Wall -Werror -fsanitize=address -g
실행 :
# ./a.out
=================================================================
==4836==ERROR: AddressSanitizer: attempting double-free on 0x602000000010 in thread T0:
#0 0x7f35b2d7b3c8 in operator delete(void*, unsigned long) /media/sf_shared/gcc-7.1.0/libsanitizer/asan/asan_new_delete.cc:140
#1 0x400b2c in main /media/sf_shared/jkr/cpp/d_free/d_free.cxx:11
#2 0x7f35b2050c04 in __libc_start_main (/lib64/libc.so.6+0x21c04)
#3 0x400a08 (/media/sf_shared/jkr/cpp/d_free/a.out+0x400a08)
0x602000000010 is located 0 bytes inside of 4-byte region [0x602000000010,0x602000000014)
freed by thread T0 here:
#0 0x7f35b2d7b3c8 in operator delete(void*, unsigned long) /media/sf_shared/gcc-7.1.0/libsanitizer/asan/asan_new_delete.cc:140
#1 0x400b1b in main /media/sf_shared/jkr/cpp/d_free/d_free.cxx:9
#2 0x7f35b2050c04 in __libc_start_main (/lib64/libc.so.6+0x21c04)
previously allocated by thread T0 here:
#0 0x7f35b2d7a040 in operator new(unsigned long) /media/sf_shared/gcc-7.1.0/libsanitizer/asan/asan_new_delete.cc:80
#1 0x400ac9 in main /media/sf_shared/jkr/cpp/d_free/d_free.cxx:8
#2 0x7f35b2050c04 in __libc_start_main (/lib64/libc.so.6+0x21c04)
SUMMARY: AddressSanitizer: double-free /media/sf_shared/gcc-7.1.0/libsanitizer/asan/asan_new_delete.cc:140 in operator delete(void*, unsigned long)
==4836==ABORTING
새니 타이 저에 대해 자세히 알아 보려면 this 또는 this 또는 최신 C ++ 컴파일러 (예 : gcc, clang 등) 문서를 확인하세요.
답변
Boost와 같은 스마트 포인터를 사용하고 shared_ptr
있습니까? 그렇다면 다음을 호출하여 어디에서나 원시 포인터를 직접 사용하고 있는지 확인하십시오.get()
. 나는 이것이 매우 일반적인 문제라는 것을 발견했습니다.
예를 들어 원시 포인터가 코드에 전달되는 시나리오 (예 : 콜백 핸들러)를 상상해보십시오. 참조 카운팅 등에 대처하기 위해 이것을 스마트 포인터에 할당하기로 결정할 수 있습니다. 큰 실수 : 깊은 복사를하지 않는 한 코드는이 포인터를 소유하지 않습니다. 스마트 포인터로 코드가 완료되면 다른 사람이 필요하지 않다고 생각 하기 때문에 그것을 파괴하고 가리키는 메모리를 파괴하려고 시도 하지만 호출 코드는 그것을 삭제하려고 시도하고 두 배의 무료 문제.
물론 그것은 여기서 당신의 문제가 아닐 수도 있습니다. 가장 간단합니다. 여기에 그것이 어떻게 일어날 수 있는지 보여주는 예가 있습니다. 첫 번째 삭제는 괜찮지 만 컴파일러는 이미 해당 메모리가 삭제되어 문제를 일으킨다는 것을 감지합니다. 그렇기 때문에 삭제 직후 포인터에 0을 할당하는 것이 좋습니다.
int main(int argc, char* argv[])
{
char* ptr = new char[20];
delete[] ptr;
ptr = 0; // Comment me out and watch me crash and burn.
delete[] ptr;
}
편집 : 변경 delete
에 delete[]
PTR은 문자의 배열이기 때문에.