memcpy вызывает странную ошибку сегментации - PullRequest
0 голосов
/ 05 мая 2018

Я получаю ошибку сегментации, хотя моя программа на С, кажется, ИДЕАЛЬНАЯ! Вот как это работает:

Предполагается, что у нас есть структура Heap, содержащая 6 int и 1 int *. (размер 32 байта)

struct Heap
{
  int* a;
  int  b;
  int  c;
  int  d; 
  int  e;
  bool f; // Trust me it's int
  bool g; // Trust me it's int
};

В main () я звоню:

examine(heap, enable_cloning);

Что экзамен () делает:

...
    if(!enable_cloning)
    {
        Heap* my_clone = new_Heap_from_clone(heap); // A clone is being made ...
...

Теперь перейдем к сложной части (внутри new_Heap_from_clone () )

Heap* new_Heap_from_clone(Heap const* the_original_or_clone_heap)
{
    Heap* heap = malloc(sizeof(Heap));
    if(heap == NULL)
        return NULL;

    memcpy(heap, the_original_or_clone_heap, sizeof(Heap)); //Happy Segmentation Fault !!!
    ...

Запуск GDB я получаю:

(gdb) step
174     memcpy(heap, the_original_or_clone_heap, sizeof(the_original_or_clone_heap));
(gdb) step

Program received signal SIGSEGV, Segmentation fault.
0x0000555555554dae in new_Heap_from_clone (the_original_or_clone_heap=0xb) at ./Heap.c:174
174     memcpy(heap, the_original_or_clone_heap, sizeof(the_original_or_clone_heap));
(gdb) sizeof *heap
Undefined command: "sizeof".  Try "help".
(gdb) print sizeof *heap
$5 = 32
(gdb) print sizeof *the_original_or_clone_heap
$6 = 32

Примечание: что я включил размеры того, что memcpy () , чтобы я мог получить от вас больше ценной информации! Посмотрим, что скажет об этом Вальгринд:

==6244== Use of uninitialised value of size 8
==6244==    at 0x108DAE: new_Heap_from_clone (Heap.c:174)
==6244==    by 0x1095ED: heapSort (Heap.c:481)
==6244==    by 0x10915F: sort (Heap.c:330)
==6244==    by 0x10A897: ds_bench (main.c:90)
==6244==    by 0x10A9B4: main (main.c:106)
==6244== 
==6244== Invalid read of size 8
==6244==    at 0x108DAE: new_Heap_from_clone (Heap.c:174)
==6244==    by 0x1095ED: heapSort (Heap.c:481)
==6244==    by 0x10915F: sort (Heap.c:330)
==6244==    by 0x10A897: ds_bench (main.c:90)
==6244==    by 0x10A9B4: main (main.c:106)
==6244==  Address 0xb is not stack'd, malloc'd or (recently) free'd
==6244== 
==6244== 
==6244== Process terminating with default action of signal 11 (SIGSEGV)
==6244==  Access not within mapped region at address 0xB
==6244==    at 0x108DAE: new_Heap_from_clone (Heap.c:174)
==6244==    by 0x1095ED: heapSort (Heap.c:481)
==6244==    by 0x10915F: sort (Heap.c:330)
==6244==    by 0x10A897: ds_bench (main.c:90)
==6244==    by 0x10A9B4: main (main.c:106)
==6244==  If you believe this happened as a result of a stack
==6244==  overflow in your program's main thread (unlikely but
==6244==  possible), you can try to increase the size of the
==6244==  main thread stack using the --main-stacksize= flag.
==6244==  The main thread stack size used in this run was 12001280.
==6244== 
==6244== HEAP SUMMARY:
==6244==     in use at exit: 1,648 bytes in 31 blocks
==6244==   total heap usage: 32 allocs, 1 frees, 2,672 bytes allocated
==6244== 
==6244== LEAK SUMMARY:
==6244==    definitely lost: 0 bytes in 0 blocks
==6244==    indirectly lost: 0 bytes in 0 blocks
==6244==      possibly lost: 0 bytes in 0 blocks
==6244==    still reachable: 1,648 bytes in 31 blocks
==6244==         suppressed: 0 bytes in 0 blocks
==6244== Reachable blocks (those to which a pointer was found) are not shown.
==6244== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==6244== 
==6244== For counts of detected and suppressed errors, rerun with: -v
==6244== Use --track-origins=yes to see where uninitialised values come from
==6244== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

Имейте в виду, что у меня нет предыдущего опыта работы с valgrind, но он говорит очевидное:

== 6244 == Доступ не в сопоставленном регионе по адресу 0xB

НО я не думаю, что есть такая проблема ... Есть ли какая-либо возможность запустить (как-то) из стека пространство? НО ДАЖЕ в таком случае запустите valgrind с:

valgrind --leak-check = yes --main-stacksize=12000000 ./hxn это больше, чем по умолчанию (8388608), и получил тот же ответ, что и вы.

Так, ЧТО НА ЗЕМЛЕ СЧИТАЕТСЯ ТОЧКОЙ ТОЧКИ?

1 Ответ

0 голосов
/ 05 мая 2018

Вы передаете неинициализированный указатель на new_Heap_from_clone(). И GDB, и Valgrind пытаются сказать вам, что:

  • GDB говорит вам, что указатель равен 0xb, что является классическим значением неинициализированного указателя в GDB; и
  • valgrind не может быть более очевидным, когда говорит: Use of uninitialised value of size 8.

Это проходит проверку, потому что 0xb не равно нулю; 0x0 есть. Таким образом, когда вы вызываете new_Heap_from_clone(heap), вы не должны инициализировать этот конкретный heap значением null, когда это необходимо.

Используйте способности обратного отслеживания GDB (up, чтобы подняться в стек вызовов, down, чтобы спуститься), чтобы точно выяснить, где это идет не так.

...