попытаться буферизовать значение переполнения, выделенное malloc()

Я немного запутался в функции malloc().

если sizeof(char) равно 1 byte и функция malloc() принимает N байтов в качестве аргумента для выделения, то, если я это сделаю:

char* buffer = malloc(3);

Я выделяю буфер, который может хранить 3 символа, верно?

char* s = malloc(3);
int i = 0;
while(i < 1024) { s[i] = 'b'; i++; }
s[i++] = '$';
s[i] = '\0';
printf("%s\n",s);

это работает нормально. и сохраняет 1024 b's в s.

bbbb[...]$

почему приведенный выше код не вызывает переполнение буфера? Кто-нибудь может объяснить?


person Jack    schedule 28.03.2012    source источник
comment
Исправьте ошибку, и тайна исчезнет. Код с ошибками делает странные вещи, поэтому мы не пишем код с ошибками.   -  person David Schwartz    schedule 28.03.2012
comment
Это является переполнением буфера; вы просто не делаете ничего, чтобы использовать его. C с радостью позволит вам писать по адресу памяти, если он действительно существует. Это не ракетостроение.   -  person tbert    schedule 28.03.2012
comment
@tbert, пока он действительно существует, не совсем верен - если он находится за пределами адресного пространства вашего процесса, C не позволит вам писать в него.   -  person Timothy Jones    schedule 28.03.2012
comment
@TimothyJones хорошо, на самом деле существует в пространстве вашей виртуальной машины; Я не уверен, что нам нужно быть такими педантичными, учитывая запутанный характер самого вопроса.   -  person tbert    schedule 28.03.2012


Ответы (6)


malloc(size) возвращает место в памяти, где для использования доступно не менее size байтов. Скорее всего, вы сможете писать в байты сразу после s[size], но:

  • Эти байты могут принадлежать другим битам вашей программы, что позже вызовет проблемы при выполнении.
  • Или байты могут подойти для записи — они могут принадлежать странице, которую использует ваша программа, но ни для чего не используются.
  • Или они могут принадлежать структурам, которые malloc() использовал для отслеживания того, что использовала ваша программа. Испортить это очень плохо!
  • Или они могут НЕ принадлежать вашей программе, что приведет к немедленной ошибке сегментации. Это вероятно, если вы получите доступ, скажем, s[size + large_number]

Трудно сказать, что из этого произойдет, потому что доступ за пределами области, которую вы просили malloc(), приведет к неопределенному поведению.

В вашем примере вы переполняете буфер, но не так, чтобы вызвать немедленный сбой. Имейте в виду, что C не проверяет границы при доступе к массиву/указателю.


Кроме того, malloc() создает память в куче, но переполнение буфера обычно связано с памятью в стеке. Если вы хотите создать его в качестве упражнения, используйте

char s[3];

вместо. Это создаст массив из 3 символов в стеке. В большинстве систем после массива не будет свободного места, поэтому пространство после s[2] будет принадлежать стеку. Запись в это пространство может перезаписать другие переменные в стеке и в конечном итоге вызвать ошибки сегментации, например, перезаписав указатель возврата текущего кадра стека.


Еще одна вещь:

если sizeof(char) равно 1 байту

sizeof(char) на самом деле определяется стандартом всегда как 1 байт. Однако размер этого 1 байта может не равняться 8 битам в экзотических системах. Конечно, в большинстве случаев вам не нужно беспокоиться об этом.

person Timothy Jones    schedule 28.03.2012

Это неопределенное поведение (UB) для записи за пределами выделенной памяти.

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

person Alok Save    schedule 28.03.2012

В некотором смысле вы переполнили свой трехсимвольный буфер. Однако вы не переполнили адресное пространство вашей программы (пока). Таким образом, вы выходите за пределы s*, но вы перезаписываете случайные другие данные в своей программе. Поскольку эти данные принадлежат вашей программе, она не падает, но все же делает очень и очень неправильные вещи, и будущее поведение не определено.

person Oleksi    schedule 28.03.2012

На практике это приводит к повреждению кучи. Эффекты могут проявиться не сразу (на самом деле это часть того, что делает такие ошибки PITA для отладки). Однако вы можете удалить все, что окажется в куче или в той части адресного пространства вашей программы, если уж на то пошло. Вполне вероятно, что вы также испортили malloc() внутренние структуры данных, поэтому вполне вероятно, что последующие вызовы malloc() или free() могут привести к сбою вашей программы, заставив многих программистов (ложно) поверить, что они нашли ошибку в malloc().

person FatalError    schedule 28.03.2012

Вы переполняете буфер. Это зависит от того, какую память вы переполняете, чтобы получить сообщение об ошибке.

person Adrian    schedule 28.03.2012

Вы пытались выполнить свой код в режиме выпуска или пытались освободить память, которую вы используете? Это неопределенное поведение.

Это немного языковой хак, и немного сомнительно его использование.

person Jeeva    schedule 28.03.2012