Недавно я начал программировать на C и столкнулся с проблемой возврата массива. Когда я пытаюсь вернуть массив, я получаю ошибку времени выполнения переполнения буфера кучи.
Вот мой код
int* getConcatenation(int* nums, int numsSize, int* returnSize){
int *ans;
ans=(int*)malloc(numsSize * sizeof(int));
for (int i=0;i<numsSize;i++){
ans[i]=nums[i];
ans[i+numsSize]=nums[i];
}
free(ans);
return ans;
}
Ошибка
AddressSanitizer: heap-buffer-overflow on address 0x60200000003c at pc 0x55780cb25d30 bp 0x7ffd83067af0 sp 0x7ffd83067ae0
WRITE of size 4 at 0x60200000003c thread T0
#2 0x7fabeed390b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
0x60200000003c is located 0 bytes to the right of 12-byte region [0x602000000030,0x60200000003c)
allocated by thread T0 here:
#0 0x7fabef97ebc8 in malloc (/lib/x86_64-linux-gnu/libasan.so.5+0x10dbc8)
#3 0x7fabeed390b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
Shadow bytes around the buggy address:
0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa 00 04 fa fa 00[04]fa fa fa fa fa fa fa fa
0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==44==ABORTING
Измененный код:
Это мой код сейчас, но он все еще не работает
int* getConcatenation(int* nums,
int numsSize,
int* returnSize)
{
int *ans;
ans=malloc(2*numsSize * sizeof(int));
for (int i=0;i<numsSize;i++)
{
ans[i]=nums[i];
ans[i+numsSize]=nums[i];
}
return ans;
}
Как вы думаете, что делает free(ans); return ans;?
@Clifford Это обнадеживает введением интриги :)
;-) @EugeneSh. Сейчас, может быть, но через несколько месяцев, при поиске проблем с AddressSanitizer, менее полезным для сообщества.
Общий заголовок: «Я программирую на C, столкнулся с этой проблемой и был бы рад узнать решение». @Клиффорд
@ Fe2O3 Fe2O3: да, это была моя точка зрения. Не уверен, что вы делаете?
Я не решаюсь исправить заголовок для вас, но предлагаю «ошибка времени выполнения переполнения кучи-буфера при возврате динамически выделенного блока». показать признательность.
@Clifford Немного юмора для медленного дня. К какой горстке вопросов SO [c] это общее название не применимо?
@ Fe2O3: Извини, это был долгий день. Понял.
Для чего нужен параметр returnSize? Вы ничего не делаете с этим. Сообщить нам, что код не работает, недостаточно. Вы должны сказать, что вы ожидали и что произошло на самом деле. Я подозреваю, что рассматриваемая проблема решена, и ваш обновленный код имеет другую проблему (возможно, в вызывающем коде), поэтому не должен быть включен в этот вопрос. Избегайте объявления инициализированного указателя только для его немедленного назначения. Предпочтение: int* ans = malloc(2*numsSize * sizeof(int));
Доступ:
ans[i+numsSize]=nums[i];
Выходит далеко за пределы выделенного пространства. Вам понадобится;
ans = malloc(2 * numsSize * sizeof(int))
Вы можете вернуться ans. Чего вы не можете сделать, так это получить доступ к памяти, на которую он указывает, потому что вы вернули ее в кучу с помощью free(). Это делает его доступным для повторного использования.
Даже если бы free() был удален, в большинстве случаев это опрометчивый шаблон в любом случае. Выделяя память внутри функции, вы будете полагаться на то, что вызывающая сторона знает, что память должна быть free'd. Как правило, лучше иметь распределение в той же области, что и выпуск (как вы сделали, но в неправильной области). Более идиоматический шаблон заключается в том, что вызывающая сторона предоставляет память и передает указатель в функцию. Таким образом, память даже не нужно динамически выделять, она находится под контролем вызывающей стороны.
Malloc() возвращает void* его не нужно приводить, и это плохая практика.
Не согласен с "это опрометчивый шаблон". Многие, многие существующие функции во всех типах библиотек дадут вам указатель на данные, с которыми вы можете играть, и ожидают, что вы освободите их либо напрямую с помощью free(), либо путем вызова функции освобождения. strdup() — это пример чего-то в стандартной libc. malloc() — это ур-пример.
Я изменил распределитель памяти и удалил free(), но мой код все еще не закончен. Ничего не возвращает.
@Dúthomhas Это происходит много раз, что не делает это хорошей идеей, и, конечно, тот факт, что это происходит часто, очевидно, что многие не согласятся (хотя они также могут быть с негерметичным кодом с ошибками). Возможно, мой 33-летний опыт работы со встраиваемыми системами сформировал мою точку зрения. Даstrdup() является примером, а также причиной многочисленных ошибок с утечкой памяти. Дело в том, что malloc() показывает свое поведение в названии, а стандартная библиотека тщательно документирована и неизменна в своем поведении.
@ДенисМороз: я не могу комментировать невидимый код. Все вышеперечисленные проблемы касаются недостатков вашего кода. Если у вас теперь другой код с разными ошибками, то это для другого вопроса. Явно что-то возвращает. Только void функции ничего не возвращают.
Я добавил новый код, но он все еще не работает.
@ДенисМороз Точно так же не получается? Если нет, то это другой вопрос, и его следует опубликовать как новый вопрос с новым поведением.
@Clifford Да, это новый вопрос, к сожалению, я не смогу опубликовать новый вопрос в течение следующих трех дней, поэтому я опубликую его здесь. Код не выдает ошибок, но код не работает, и я не получаю массив.
ans[i+numsSize]=nums[i];
вы пишете за пределами массива