Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Раскладка мемберов в дочерней структуре


Автор: drug007 1.8.2018, 11:11
Всем привет!
Работаю над старым проектом с кучей легаси. В процессе рефакторинга перестал работать код, который не менялся и работает уже несколько лет. Выяснилось, что в базовой структуре поле инициализируется как положено, а в дочерней структуре это же поле имеет адрес со смещением 4 байта относительно адреса в базовой структуре и соответственно при первой же записи в это поле происходит повреждение памяти с дальнейшим сегфолтом. Ошибка наблюдается под gcc 4.7.2 и gcc 6.3.0. Куда копать пока не знаю, может кто что подскажет?

Автор: drug007 1.8.2018, 12:35
По всей видимости проблемы в том, что кто-то портит память, так как изменил порядок членов структуры и сегфолт в совершенно другом месте. Поздравляю себя с увлекательнейшей отладкой на ближайшее время...

Автор: xvr 1.8.2018, 15:27
Цитата(drug007 @  1.8.2018,  11:11 Найти цитируемый пост)
а в дочерней структуре это же поле имеет адрес со смещением 4 байта относительно адреса в базовой структуре

Имеет право

Цитата(drug007 @  1.8.2018,  11:11 Найти цитируемый пост)
и соответственно при первой же записи в это поле происходит повреждение памяти

А вот этого быть не должно. При приведении типов между указателями на базовый и производный класс они (указатели) должны автоматически корректироваться. Покажите код (как пишете в поле)

Автор: drug007 5.8.2018, 18:22
Спасибо что ответили!
Цитата(xvr @  1.8.2018,  15:27 Найти цитируемый пост)
Имеет право

Я не совсем ясно выразился. Из конструктора дочернего класса вызывается конструктор базового и в конструкторе базового класса мембер имеет один адрес, а когда из конструктора базового класса управление возвращается обратно в конструктор дочернего - уже другой адрес. Архитектура 64 битная, т.е. смещение на 4 байта не объяснить каким-то скрытым указателем, т.к. указателя - 8 байт. Ну и не должна изменятся раскладка в таком случае. Я же не привожу указатель.

На данный момент баг пофиксен, точнее обойден. Если вкратце причиной оказалось то, что была взаимное включение заголовочников. Причем оно жило в коде уже лет несколько, а проблема проявилась только когда я в один из этих заголовочников включил еще один, msgpack.hpp - это проявляло проблему и приводило к неправильной генерации машинного кода. Там еще была ситуация, что при вызове функции передавался указатель, но внутри функции этот указатель также брался со смещением 4 байта и то же приложение сегфолтилось.

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

Автор: xvr 6.8.2018, 11:08
Цитата(drug007 @  5.8.2018,  18:22 Найти цитируемый пост)
Из конструктора дочернего класса вызывается конструктор базового и в конструкторе базового класса мембер имеет один адрес, а когда из конструктора базового класса управление возвращается обратно в конструктор дочернего - уже другой адрес. 

Как вызывали конструктор? Если через ':' - то должно работать, если явно - base(), то это не работает:
Код

class Child: public Base {
  Child() : Base() {}  // Так должно работать
  Child() { Base(); } // Так не будет работать
};


Цитата(drug007 @  5.8.2018,  18:22 Найти цитируемый пост)
 Если вкратце причиной оказалось то, что была взаимное включение заголовочников. Причем оно жило в коде уже лет несколько, а проблема проявилась только когда я в один из этих заголовочников включил еще один, msgpack.hpp - это проявляло проблему и приводило к неправильной генерации машинного кода. 

Очень похоже на залипший объектный файл. Вы поменяли описание класса (в хидере), а какой то объектник не пересобрался (либо зависимостей не хватило, либо были проблемы со временем на компе).
Лечится полной пересборкой проекта

Автор: drug007 6.8.2018, 23:12
Цитата(xvr @  6.8.2018,  11:08 Найти цитируемый пост)
Как вызывали конструктор? Если через ':' - то должно работать, если явно - base(), то это не работает:

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

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

Цитата(xvr @  6.8.2018,  11:08 Найти цитируемый пост)
Очень похоже на залипший объектный файл. Вы поменяли описание класса (в хидере), а какой то объектник не пересобрался (либо зависимостей не хватило, либо были проблемы со временем на компе).
Лечится полной пересборкой проекта

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

Автор: xvr 7.8.2018, 14:06
Очень и очень странно. Код не покажете?

Автор: drug007 13.8.2018, 12:43
Цитата(xvr @  7.8.2018,  14:06 Найти цитируемый пост)
Код не покажете?

Нельзя. Да и не стоит смотреть на этот код  smile 
Это в лучших традициях типичный "энтерпрайз" - многолетний код с кучей легаси, лапши и прочих костылей добавленных чтобы работало и в котором сам черт ногу сломит.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)