Ошибка выполнения переполнения кучи-буфера при возврате динамически выделенного блока

Недавно я начал программировать на 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;
}
ans[i+numsSize]=nums[i]; вы пишете за пределами массива
David Ranieri 10.01.2023 22:49

Как вы думаете, что делает free(ans); return ans;?

Oka 10.01.2023 23:00

@Clifford Это обнадеживает введением интриги :)

Eugene Sh. 10.01.2023 23:12

;-) @EugeneSh. Сейчас, может быть, но через несколько месяцев, при поиске проблем с AddressSanitizer, менее полезным для сообщества.

Clifford 10.01.2023 23:24

Общий заголовок: «Я программирую на C, столкнулся с этой проблемой и был бы рад узнать решение». @Клиффорд

Fe2O3 10.01.2023 23:26

@ Fe2O3 Fe2O3: да, это была моя точка зрения. Не уверен, что вы делаете?

Clifford 10.01.2023 23:45

Я не решаюсь исправить заголовок для вас, но предлагаю «ошибка времени выполнения переполнения кучи-буфера при возврате динамически выделенного блока». показать признательность.

Clifford 10.01.2023 23:51

@Clifford Немного юмора для медленного дня. К какой горстке вопросов SO [c] это общее название не применимо?

Fe2O3 10.01.2023 23:51

@ Fe2O3: Извини, это был долгий день. Понял.

Clifford 10.01.2023 23:52

Для чего нужен параметр returnSize? Вы ничего не делаете с этим. Сообщить нам, что код не работает, недостаточно. Вы должны сказать, что вы ожидали и что произошло на самом деле. Я подозреваю, что рассматриваемая проблема решена, и ваш обновленный код имеет другую проблему (возможно, в вызывающем коде), поэтому не должен быть включен в этот вопрос. Избегайте объявления инициализированного указателя только для его немедленного назначения. Предпочтение: int* ans = malloc(2*numsSize * sizeof(int));

Clifford 11.01.2023 23:35
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
3
10
92
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Доступ:

ans[i+numsSize]=nums[i];

Выходит далеко за пределы выделенного пространства. Вам понадобится;

ans = malloc(2 * numsSize * sizeof(int))

Вы можете вернуться ans. Чего вы не можете сделать, так это получить доступ к памяти, на которую он указывает, потому что вы вернули ее в кучу с помощью free(). Это делает его доступным для повторного использования.

Даже если бы free() был удален, в большинстве случаев это опрометчивый шаблон в любом случае. Выделяя память внутри функции, вы будете полагаться на то, что вызывающая сторона знает, что память должна быть free'd. Как правило, лучше иметь распределение в той же области, что и выпуск (как вы сделали, но в неправильной области). Более идиоматический шаблон заключается в том, что вызывающая сторона предоставляет память и передает указатель в функцию. Таким образом, память даже не нужно динамически выделять, она находится под контролем вызывающей стороны.

Malloc() возвращает void* его не нужно приводить, и это плохая практика.

Не согласен с "это опрометчивый шаблон". Многие, многие существующие функции во всех типах библиотек дадут вам указатель на данные, с которыми вы можете играть, и ожидают, что вы освободите их либо напрямую с помощью free(), либо путем вызова функции освобождения. strdup() — это пример чего-то в стандартной libc. malloc() — это ур-пример.

Dúthomhas 11.01.2023 06:45

Я изменил распределитель памяти и удалил free(), но мой код все еще не закончен. Ничего не возвращает.

Денис Мороз 11.01.2023 11:15

@Dúthomhas Это происходит много раз, что не делает это хорошей идеей, и, конечно, тот факт, что это происходит часто, очевидно, что многие не согласятся (хотя они также могут быть с негерметичным кодом с ошибками). Возможно, мой 33-летний опыт работы со встраиваемыми системами сформировал мою точку зрения. Даstrdup() является примером, а также причиной многочисленных ошибок с утечкой памяти. Дело в том, что malloc() показывает свое поведение в названии, а стандартная библиотека тщательно документирована и неизменна в своем поведении.

Clifford 11.01.2023 20:31

@ДенисМороз: я не могу комментировать невидимый код. Все вышеперечисленные проблемы касаются недостатков вашего кода. Если у вас теперь другой код с разными ошибками, то это для другого вопроса. Явно что-то возвращает. Только void функции ничего не возвращают.

Clifford 11.01.2023 20:33

Я добавил новый код, но он все еще не работает.

Денис Мороз 11.01.2023 21:39

@ДенисМороз Точно так же не получается? Если нет, то это другой вопрос, и его следует опубликовать как новый вопрос с новым поведением.

Clifford 11.01.2023 23:26

@Clifford Да, это новый вопрос, к сожалению, я не смогу опубликовать новый вопрос в течение следующих трех дней, поэтому я опубликую его здесь. Код не выдает ошибок, но код не работает, и я не получаю массив.

Денис Мороз 11.01.2023 23:33

Другие вопросы по теме