Следующая программа не вызывает ошибку подтверждения:
int main(int argc, char **argv)
{
int * n = (int *)malloc(100);
//malloc_stats_print(nullptr, nullptr, "gablh");
free(n);
*n += 1;
std::cerr << *n << std::endl;
for (int i = 0; i != 10; ++i) {
std::cerr << *(n+i) << std::endl;
}
}
Когда я запускаю программу
MALLOC_CONF="quarantine:32,abort:true,stats_print:true" ex_stats_pr
Я получил:
1515870811
1515870811
1515870810
1515870810
1515870810
1515870810
1515870810
1515870810
1515870810
1515870810
1515870810
Есть ли способ вызвать сбой прерывания с Jemalloc?
Это не совсем прямой ответ на ваш вопрос, но …
Неопределенное поведение не определено. Игра с памятью, которая была освобождена, попадает в этот лагерь. В зависимости от вашей реализации ваших обработчиков памяти, у вас может быть функция типа «проверить память», которая просматривает ваш список свободной памяти, чтобы увидеть, было ли какое-то повреждение, но даже это не поймает все (не знаком с jemalloc
в частности я). Может случиться так, что ваш код выше попадет в память, о которой никто не заботится, поэтому не будет пойман. Черт возьми, твой std::cerr
оператор также выполняет неопределенное поведение, так что вы даже не можете доверять его значениям (например, потоки и захват ОС, изменение памяти и т. д.)
Это одна из причин того, что вы не используете указатель напрямую в C ++, когда это возможно. Умные указатели и контейнеры, которые управляют временем жизни, автоматически предотвращают почти все эти типы ошибок.
Вы ожидаете, что jemalloc обнаруживает одну запись в освобожденную память и некоторые чтения освобожденной памяти.
Но у библиотеки jemalloc такой возможности нет. Его режим отладки обнаруживает только ограниченный набор ошибок, которые приводят к повреждению памяти. Например, двойное освобождение.
Это не произвольное ограничение, поскольку библиотека вроде jemalloc просто не может обнаружить какую-либо ошибку доступа к памяти. Это означает, что как библиотека, она может легко перегрузить malloc () / free () и т. Д. И установить обработчик выхода. Реализация режима отладки, таким образом, может эффективно реализовывать ограниченный набор проверок. И, конечно же, каждая реализация режима отладки выбирает свои собственные компромиссы. Например, jemalloc также не обнаруживает простых переполнений буфера во время свободных, хотя другие библиотеки с возможностями отладки (например, Solaris ‘ libumem) реализовать легкий механизм, где проверяется целостность некоторых специальных конечных байтов.
Чтобы библиотека типа jemalloc обнаруживала чтение / запись в освобожденную память, она должна была бы устанавливать часы в стиле отладчика в каждую освобожденную область, что было бы довольно сложно и приводило к значительным накладным расходам времени выполнения — если это вообще масштабировалось бы для многих и больших выделений.
Дело в том, что jemalloc — неподходящий инструмент для обнаружения операций записи в освобожденную память (A) и чтения свободной памяти (B).
Например, Адрес Санитайзер (-fsanitize=address
), который поставляется с GCC и Clang способен обнаружить (A), но не (B). А также Valgrind (valgrind --tool=memcheck
) способен обнаруживать как (A), так и (B) и сообщает об этих проблемах как недопустимые операции чтения / записи в освобожденный блок. Оба инструмента, безусловно, имеют больше времени выполнения, чем простой режим отладки библиотеки-распределителя. А поскольку подход valgrind заключается в эмуляции процессора, его издержки намного выше, чем у Address Sanitizer.