Почему C иногда справляется с перезаписью памяти? Неустранимая ошибка glibc: ошибка утверждения malloc в sysmalloc

Почему код А работает нормально, а код Б выдает ошибку? Единственная разница — это printf. Также обратите внимание, что я обращаюсь к памяти за пределами диапазона. И GCC с этим согласен. В примере А я даже легко перезаписал ОЗУ.

Ошибка компилятора:

Fatal glibc error: malloc assertion failure in sysmalloc: (old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)

Мой код мира:

#include <stdio.h>
#include <stdlib.h>

int main()
{
#if 1
    // A
    int *items = malloc(10 * sizeof(int));
    printf("allocated: %lu bytes\n", 10 * sizeof(int));
    items = items;
    items[0] = 5;
    items[9] = 5;
    items[10] = 5;
    printf("[");
    for (size_t i = 0; i <= 10; i++)
    {
        printf(" %d", items[i]);
    }
    printf(" ]\n");
#else
    // B
    int *items = malloc(10 * sizeof(int));
    items = items;
    items[0] = 5;
    items[9] = 5;
    items[10] = 5;
    printf("[");
    for (size_t i = 0; i <= 10; i++)
    {
        printf(" %d", items[i]);
    }
    printf(" ]\n");
#endif
    return 0;
}

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

Запись за пределами вашего распределения приводит к неопределенному поведению. Должно быть объяснено на первых страницах любого введения в использование динамической памяти в C. Компилятор никоим образом не обязан следить за тем, чтобы ваша программа работала разумным образом. Чего вы ожидаете вместо этого и почему?

user17732522 17.08.2024 15:06

"Я пытался спросить в чатгпте, почему он работает, он говорит, что это потому, что у меня не хватает оперативной памяти, а это нонсенс.": Да, и хорошо, что вы это здесь заметили. Проблема с ChatGPT заключается в том, что он также может дать вам более убедительный ответ, который по-прежнему бессмысленен, и тогда, особенно тот, кто еще не является экспертом в этом вопросе, может ему поверить. Так что не используйте ChatGPT для чего-либо большего, чем получение указаний для исследования более надежных источников.

user17732522 17.08.2024 15:09

Кстати. как ты думаешь, чего items = items; собирается достичь? Кроме того, спецификатор формата `%lu` неверен. Спецификатор формата для sizte_t (тип sizeof(/*...*/)%zu).

user17732522 17.08.2024 15:11

ок, понял, я думаю, что в обоих примерах есть ошибка сегментации.

aoa 17.08.2024 15:11

этот код вырван из контекста, я забыл удалить эти строки.

aoa 17.08.2024 15:12

@ user17732522 Тсс, никому этого не говори! Это часть естественного отбора: теперь некоторые жадные менеджеры увольняют половину своей команды, веря в шумиху вокруг ИИ ;)

BitTickler 17.08.2024 15:12

Я не знаю, это работает только с lu, но спасибо, я буду использовать zu!

aoa 17.08.2024 15:14

Ошибка сегментации возникает только в том случае, если виртуальный адрес, к которому вы пытаетесь получить доступ, не сопоставлен вашему процессу (или сопоставлен с неправильными разрешениями). Длина страницы обычно составляет 4 КБ, и ваше выделение malloc находится где-то в ней. После него могут быть сопоставлены и другие страницы. Пока вы не выходите за пределы сопоставленных страниц, вы не получите ошибку сегментации. Какие страницы будут отображаться, зависит от того, что malloc решит сделать. Никаких гарантий, так или иначе, нет. Если страницы сопоставлены, но находятся за пределами вашего распределения, вы просто перезаписываете все, что там есть.

user17732522 17.08.2024 15:14

Этот вопрос похож на: Насколько опасно получать доступ к массиву за пределами его границ?. Если вы считаете, что это другое, отредактируйте вопрос, поясните, чем он отличается и/или как ответы на этот вопрос не помогают решить вашу проблему.

BoP 17.08.2024 19:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Я ожидаю сегментированных ошибок в обоих примерах.

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

Как правило, невозможно гарантировать нарушение доступа к памяти, поскольку аппаратное обеспечение обычно обрабатывает память блоками, называемыми страницами, обычно по 4096 или 8192 байта, но malloc выделяет память меньшими блоками, часто блоками по 16 байт. (Даже если вы запрашиваете меньшую сумму или сумму, которая не кратна 16 байтам, malloc все равно может выполнять свою работу блоками по 16 байт.) Итак, если вы выделите 40 байтов для десяти int, нет никакой возможности чтобы пометить память сразу после этих 40 байт как недоступную. Аппаратное обеспечение предоставляет страницу размером 4096 байт, и оно не может сказать, что к 40 из этих байт можно получить доступ, а к остальным — нет.

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

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

«Невозможно пометить память сразу после этих 40 байт как недоступную». -- точно есть (электрический забор). Просто нет практического способа сделать это.

Employed Russian 17.08.2024 16:30

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