Почему куча не испортилась раньше? - PullRequest
0 голосов
/ 18 апреля 2019

Я пытаюсь понять на более низком уровне, как С управляет памятью.Я нашел код на веб-странице, цель которого - научить вас, как плохо может быть плохое управление памятью - поэтому я скопировал и вставил его и скомпилировал:

int main(int argc, char **argv) {
        char *p, *q;
        p = malloc(1024);
        q = malloc(1024);
        if (argc >= 2)
                strcpy(p, argv[1]);
        free(q);
        free(p);
        return 0;
}

Тестовые случаи были выполнены с помощью универсальной команды

/development/heapbug$ ./heapbug `perl -e 'print "A"x$K'`

Для $K < 1023 я не ожидал проблем, но для $K = 1024 я ожидал дамп ядра, который не состоялся.Короче говоря, у меня начались ошибки по $K > 1033.

Два вопроса: 1) почему это произошло?2) существует ли формула, в которой указывается «допуск» системы?

Ответы [ 4 ]

6 голосов
/ 18 апреля 2019

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

Кроме того, внесение, казалось бы, несвязанных изменений, таких как добавление неиспользуемой локальной переменной или вызов printf для отладки, может изменить то, как проявляется неопределенное поведение, как и компиляция с другим компилятором или с тем же компилятором с другимнастройки оптимизации.

То, что программа может аварийно завершить работу, не означает, что будет .

При этом, что , вероятно, произошло связано с тем, как malloc реализован в вашей системе.Это, вероятно, откладывает на несколько больше байтов, чем было запрошено для выравнивания и учета.Без агрессивной оптимизации эти дополнительные байты для выравнивания, вероятно, не будут использоваться ни для чего другого, поэтому у вас не возникнет проблем с записью в них, но тогда у вас возникают проблемы, когда вы пишете дальше в байты, которые могут содержать внутренние структуры, используемые malloc и freeчто вы испортили.

Но опять же, вы не можете зависеть от этого поведения.C зависит от разработчика, который будет следовать правилам, и если вы не сделаете ничего плохого.

3 голосов
/ 18 апреля 2019

Неопределенное поведение - это просто так. Это может привести к сбою. Возможно, нет. Это может работать без нареканий. Это может выпить все молоко в вашем холодильнике. Это может украсть вашу любимую пару туфель и растоптать их в грязи.

То, что поведение не определено, не означает, что оно сразу станет очевидным. Вы переполнили буфер здесь, но последствия не наблюдались. Вероятно, потому, что вы фактически не используете второй буфер, который вы выделяете, поэтому, если вы начали записывать данные, это никак не повлияет на код.

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

1 голос
/ 18 апреля 2019

Запись в нераспределенную память - неопределенное поведение. Результат не указан. Это может или не может вызвать сбой. переполнение кучи может повредить содержимое других адресов памяти, но как это повлияет на программу, неизвестно.

1 голос
/ 18 апреля 2019

Насколько я понимаю, если вы переполнитесь в памяти, контролируемой в пользовательском пространстве вашего приложения (код / ​​стек / и т. Д.), Это не обязательно вызовет coredump и может действительно перезаписать часть этой памяти, что является риском, определяемымнепреднамеренное переполнение буфера.

Как только вы начнете пытаться перезаписать данные за пределами этих границ, ОС, скорее всего, заблокирует их.

...