LINUX.ORG.RU

Нет ошибки сегментации при попытке доступа по неинициализированной памяти.

 , ,


0

1

Код (краткое описание):

Есть примитивный класс tmp;

Создаю указатель obj на этот класс (без new).

Вывожу на экран отладочную информацию:
адрес_указателя, адрес_экземпляра, значение_члена_экземпляра. 

Создаю экземпляр класса по этому указателю (new) - вызывается конструктор.
Вывожу на экран отладочную информацию.

Присваиваю члену экземпляра значение.
Вывожу на экран отладочную информацию.

Освобождаю память по указателю obj оператором delete - вызывается деструктор.
Вывожу на экран отладочную информацию.

Снова присваиваю члену экземпляра значение.
Вывожу на экран отладочную информацию.

Снова освобождаю память по указателю obj оператором delete - СНОВА вызывается деструктор.
Вывожу на экран отладочную информацию.

Код:
#include "iostream"

class tmp {
public:
	int ii;
	tmp() : ii(123) {std::cout << "__construct" << std::endl;}
	~tmp() { std::cout << "__destruct" << std::endl; }
};
	
int main(int, char **)
{
	tmp *obj;
	std::cout <<&obj <<" " <<obj <<" " <<obj->ii <<std::endl <<std::endl;
	
	obj = new tmp();
	std::cout <<&obj <<" " <<obj <<" " <<obj->ii <<std::endl <<std::endl;

	obj->ii = 4;
	std::cout <<&obj <<" " <<obj <<" " <<obj->ii <<std::endl <<std::endl;
	
	delete obj;
	std::cout <<&obj <<" " <<obj <<" " <<obj->ii <<std::endl <<std::endl;
	
	obj->ii = 5;
	std::cout <<&obj <<" " <<obj <<" " <<obj->ii <<std::endl <<std::endl;

	delete obj;
	std::cout <<&obj <<" " <<obj <<" " <<obj->ii <<std::endl <<std::endl;
	
	return 0;
}

Собираю под оффтопиком без оптимизации так: g++ test_delete.cpp -Wall -O0

Вывод:

a.exe
0x22fecc 0x22ffe0 -1

__construct
0x22fecc 0x3e25e8 123

0x22fecc 0x3e25e8 4

__destruct
0x22fecc 0x3e25e8 0

0x22fecc 0x3e25e8 5

__destruct
0x22fecc 0x3e25e8 4072936

Я считаю, что segfault должен был произойти еще на первой строчкепри попытке вывести адрес объекта - << obj. Ну, или по крайней мере тут: << obj->ii.

Почему не падает?


Собираю под оффтопиком без оптимизации

А ты форумом не ошибся?

crutch_master ★★★★★ ()

0x22fecc 0x22ffe0

Походу повезло и в стеке остался какой-то адрес локальной переменной. Сделай переменную obj статической и получишь свой сегфолт.

ziemin ★★ ()
Ответ на: комментарий от ziemin

Спасибо! Получилось! При static tmp *obj сегфолится по нормальному!

Тогда два вопроса: а почему вообще при втором delete вызывается деструктор?

Что прочесть чтобы разбираться в подобных вещах? Опираясь на свои текущие знания я был уверен, что будет сегфолт. За плечами K&R и Страуструп.

JANB ()
Ответ на: комментарий от JANB

Потому что delete по определению вызывает деструктор + освобождает память. Почему при повторном освобождении памяти не случилось сегфолта — вопрос хороший; в любом случае это «undefined behavior»: программа имеет право вести себя как угодно, в т. ч. падать через раз и так далее.

intelfx ★★★★★ ()

Я считаю, что segfault должен был произойти

Тебе никто ничего не должен.

Ты сам себе злобный Буратино.

Хочешь получать по соплям с оттяжечкой каждый раз, как обосрешься - используй valgrind и address sanitizer.

anonymous ()
Ответ на: комментарий от JANB

Что прочесть чтобы разбираться в подобных вещах?

Дефолтную реализацию new в конкретно той libstdc++, которой ты пользуешься.

anonymous ()
Ответ на: комментарий от intelfx

Почему при повторном освобождении памяти не случилось сегфолта — вопрос хороший;

Говно вопрос. С какой такой радости вообще будет сегфолт, если ты обращаешься куда-то в пул, честно выданный mmap-ом и совершенно не обязательно освобожденный?

anonymous ()
Ответ на: комментарий от anonymous

Неправильно выразился. Аборт, а не сегфолт. Heap corruption, все дела. ТС говорит, что собирает в дебажном режиме.

intelfx ★★★★★ ()
Ответ на: комментарий от intelfx

И с какой такой радости кто-то должен следить за тем, как именно ты срешь в память? ОС еще может (но не обязана) вломить тебе в хлебало, если ты обратишься к несуществующей или недоступной странице. Все остальное тебе никто не гарантирует, никогда.

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

anonymous ()
Ответ на: комментарий от anonymous

Да в курсе я. Тем не менее, рантаймы в дебажном режиме обычно отслеживают такие вещи (в некоторой степени). Вот я и удивляюсь, why not.

intelfx ★★★★★ ()
Ответ на: комментарий от intelfx

Я тебе уже показал, что чтобы хотя бы минимально отслеживать такие вещи, нужна очень тяжелая и тормозная VM, типа того же valgrind. Никакой такой «рантайм» тебе ничем не поможет.

anonymous ()
Ответ на: комментарий от intelfx

ТС плакал, что не было сегфолта при попытке записи после delete.

anonymous ()
Ответ на: комментарий от intelfx

Double free можно отслеживать и без инструментирования.

Так от libc зависит. Вроде в старой glibc тоже проверки не было (или проверка была, но ничего не выводила на экран).

monk ★★★★★ ()

а какая ОС и какое ядро. За обращениями к памяти должна следить ОС. Возможно у вас какое то очень старое ядро

energyclab ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.