2016-12-14 2 views
2

Когда я делаю два последовательных free() на одном и том же указателе, он дает двойную бесплатную ошибку, но когда я пытаюсь освободить один и тот же указатель два раза в промежутке между освобожденным другим указателем, он не дает ошибку.Почему следующий код не дает двойной ошибки?

#include <stdio.h>                
#include <stdlib.h>                
int main(){                    
    long int*ptr;                
    int *ptr1;                 

    ptr = malloc (1);               
    ptr1 = malloc (1);               

    printf ("%ld\n", ptr[-1]);             
    free (ptr);                 
    printf ("%ld\n", ptr[-1]);             
    free (ptr1);                 
    free (ptr);                 
    free (ptr1);                 
    free (ptr);                 
    free (ptr1);                 
    return 0;                 
} 
+6

Двойной бесплатный не должен указывать на ошибку в первую очередь – user3528438

+0

Это просто неопределенное поведение. – George

+0

*** Ошибка в './app ': двойная свобода или коррупция (fasttop): 0x0000563f04897010 *** –

ответ

6

Там нет обещания, что двойное free вызовет ошибку сегментации.

От man page:

free() освобождает пространство памяти, на которую указывает ptr, который должен быть была возвращена предыдущим вызовом malloc(), calloc() или realloc(). В противном случае, или если free(ptr) уже был вызван до этого, происходит неопределенное поведение. Если ptr is NULL, нет операции выполнено.

Undefined behavior означает, что нет гарантий относительно того, что произойдет. Ваша программа может потерпеть крах, может показаться странным поведением или (как вы видели), она может работать правильно. Создание, казалось бы, несвязанного изменения вашего кода может изменить то, как проявляется неопределенное поведение, поэтому он может начать сбой или он может перестать сбой.

EDIT:

Запуск программы с помощью такого инструмента, как Valgrind, как это было предложено Тоби, ставит дополнительные проверки на месте специально искать эти типы ошибок и сказать вам точно, где дела идут не так.

Без такого инструмента, однако, если вы вызываете неопределенное поведение, все ставки отключены.

2

Возможно, вы используете неправильный инструмент для тестирования своей программы. Valgrind безусловно сообщает много ошибок, когда я построил тестовую программу:

gcc -std=c11 -fPIC -g -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds  41147878.c -o 41147878 
valgrind ./41147878 
==30744== Memcheck, a memory error detector 
==30744== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. 
==30744== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info 
==30744== Command: ./41147878 
==30744== 
==30744== Invalid read of size 8 
==30744== at 0x10876C: main (41147878.c:10) 
==30744== Address 0x51d5038 is 8 bytes before a block of size 1 alloc'd 
==30744== at 0x4C2ABAF: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==30744== by 0x108751: main (41147878.c:7) 
==30744== 
0 
==30744== Invalid read of size 8 
==30744== at 0x108797: main (41147878.c:12) 
==30744== Address 0x51d5038 is 8 bytes before a block of size 1 free'd 
==30744== at 0x4C2BDDB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==30744== by 0x10878E: main (41147878.c:11) 
==30744== Block was alloc'd at 
==30744== at 0x4C2ABAF: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==30744== by 0x108751: main (41147878.c:7) 
==30744== 
0 
==30744== Invalid free()/delete/delete[]/realloc() 
==30744== at 0x4C2BDDB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==30744== by 0x1087C5: main (41147878.c:14) 
==30744== Address 0x51d5040 is 0 bytes inside a block of size 1 free'd 
==30744== at 0x4C2BDDB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==30744== by 0x10878E: main (41147878.c:11) 
==30744== Block was alloc'd at 
==30744== at 0x4C2ABAF: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==30744== by 0x108751: main (41147878.c:7) 
==30744== 
==30744== Invalid free()/delete/delete[]/realloc() 
==30744== at 0x4C2BDDB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==30744== by 0x1087D1: main (41147878.c:15) 
==30744== Address 0x51d5090 is 0 bytes inside a block of size 1 free'd 
==30744== at 0x4C2BDDB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==30744== by 0x1087B9: main (41147878.c:13) 
==30744== Block was alloc'd at 
==30744== at 0x4C2ABAF: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==30744== by 0x10875F: main (41147878.c:8) 
==30744== 
==30744== Invalid free()/delete/delete[]/realloc() 
==30744== at 0x4C2BDDB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==30744== by 0x1087DD: main (41147878.c:16) 
==30744== Address 0x51d5040 is 0 bytes inside a block of size 1 free'd 
==30744== at 0x4C2BDDB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==30744== by 0x10878E: main (41147878.c:11) 
==30744== Block was alloc'd at 
==30744== at 0x4C2ABAF: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==30744== by 0x108751: main (41147878.c:7) 
==30744== 
==30744== Invalid free()/delete/delete[]/realloc() 
==30744== at 0x4C2BDDB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==30744== by 0x1087E9: main (41147878.c:17) 
==30744== Address 0x51d5090 is 0 bytes inside a block of size 1 free'd 
==30744== at 0x4C2BDDB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==30744== by 0x1087B9: main (41147878.c:13) 
==30744== Block was alloc'd at 
==30744== at 0x4C2ABAF: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==30744== by 0x10875F: main (41147878.c:8) 
==30744== 
==30744== 
==30744== HEAP SUMMARY: 
==30744==  in use at exit: 0 bytes in 0 blocks 
==30744== total heap usage: 3 allocs, 7 frees, 1,026 bytes allocated 
==30744== 
==30744== All heap blocks were freed -- no leaks are possible 
==30744== 
==30744== For counts of detected and suppressed errors, rerun with: -v 
==30744== ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 0 from 0) 

Если вы использовали какую-либо другую проверку, чтобы провести тест, вы должны изменить этот вопрос более конкретно.

Смежные вопросы