Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/9: Рейтинг темы: голосов - 9, средняя оценка - 4.67
1 / 1 / 0
Регистрация: 29.10.2013
Сообщений: 74

Динамическое изменение типа переменной в конструкторе и деструкторе - как это вообще возможно?

24.06.2021, 20:21. Показов 2037. Ответов 11

Студворк — интернет-сервис помощи студентам
Собрал в Debian Linux программу Bonzomatic из git-репозитария https://github.com/Gargaj/Bonzomatic

Если ее запустить, переключиться на русскую раскладку, и нажать любую русскую букву, то произойдет сегфолт:

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
*** Error in `./bonzomatic': free(): invalid next size (fast): 0x000056048520f980 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x70bfb)[0x7fa3c7f6ebfb]
/lib/x86_64-linux-gnu/libc.so.6(+0x76fc6)[0x7fa3c7f74fc6]
/lib/x86_64-linux-gnu/libc.so.6(+0x7780e)[0x7fa3c7f7580e]
./bonzomatic(_ZN9Scintilla10LineLayout4FreeEv+0x7b)[0x56048373ba39]
./bonzomatic(_ZN9Scintilla10LineLayoutD2Ev+0x26)[0x56048373b8ea]
./bonzomatic(_ZN9Scintilla10LineLayoutD0Ev+0x18)[0x56048373b906]
./bonzomatic(_ZN9Scintilla15LineLayoutCache8RetrieveEiiiiii+0x21c)[0x56048373c920]
./bonzomatic(_ZN9Scintilla8EditView18RetrieveLineLayoutEiRKNS_9EditModelE+0x143)[0x56048372377f]
./bonzomatic(_ZN9Scintilla6Editor11WrapOneLineEPNS_7SurfaceEi+0x30)[0x560483702c9c]
./bonzomatic(_ZN9Scintilla6Editor9WrapLinesENS0_9wrapScopeE+0x487)[0x56048370323f]
./bonzomatic(_ZN9Scintilla6Editor5PaintEPNS_7SurfaceENS_10PRectangleE+0x10e)[0x560483703e88]
./bonzomatic(_ZN12ShaderEditor5PaintEv+0xa5)[0x56048363edc5]
./bonzomatic(main+0x463e)[0x56048364641e]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7fa3c7f1e2e1]
./bonzomatic(_start+0x2a)[0x56048362adaa]
======= Memory map: ========
В этой программе есть простейший тип:

C++
1
typedef float XYPOSITION;
И у класса LineLayout есть публичное свойство, в виде указателя на этот тип:

C++
1
2
3
4
5
class LineLayout {
  ...
  XYPOSITION *positions;
  ...
}
И вот с этим свойством в дебаггере творится лютая дичь: у него меняется тип. В конструкторе у этой переменной тип правильный, такой, какой объявлен в заголовке. А в деструкторе у этой же переменной тип становится "простым", то есть без указателя. Я специально сделал GIF-анимацию из двух скриншотов:

Картинка с GIF-анимацией

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

Ну и дальше, сегфолт появляется на строчке:

C++
1
2
3
4
5
6
7
8
9
10
void LineLayout::Free() {
    delete []chars;
    chars = 0;
    delete []styles;
    styles = 0;
    delete []positions; // <-- Тут сегфолт
    positions = 0;
    delete []lineStarts;
    lineStarts = 0;
}
Примечательно, что во время сегфолта, если просмотреть скоуп сегфолта, то у переменных chars, styles, lineStarts тип остается тем же, а у positions - слетает.

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

Поможите пофиксить этот баг.
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
24.06.2021, 20:21
Ответы с готовыми решениями:

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

Нужно расшифровать, если это вообще как-то возможно
yadi.sk/i/7/3/100000,(big)9/1/010,9/5/1000000,(big)7/5/100,_,7/3/100000,(big)1/3/00100000000,9/5/1000000,2/4/000100,(big)2/3/000100,6/1/0000...

Как найти правильные числа. И возможно ли это вообще?
Дано такое условие a &gt; b b &gt; c a &lt; c Какие простые числа подходят для выполнение такого условия? Как вообще такое решить, и...

11
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
24.06.2021, 23:07
xintrea, добавьте в этот класс две строки:
C++
1
2
LineLayout(LineLayout const &) = delete;
LineLayout & operator=(LineLayout const &) = delete;
увидите где в коде пытаются копировать этот объект. Там же увидите место первого освобождения. Если это действительно верная причина проблемы.

Цитата Сообщение от xintrea Посмотреть сообщение
Как это вообще возможно, я понять не могу.
Никаких типов на рантайме уже нет. Это скорее всего глюк дебаггера\отладочной информации.
0
1 / 1 / 0
Регистрация: 29.10.2013
Сообщений: 74
25.06.2021, 00:13  [ТС]
Не до конца понял что надо делать. Значит, добавляем в заголовок класса LineLayout следующие строки:

C++
1
2
LineLayout(LineLayout const &) = delete;
LineLayout & operator=(LineLayout const &) = delete;
И дальше что с ними делать? Ставить на эти строки брекпоинты?
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
25.06.2021, 00:21
Лучший ответ Сообщение было отмечено xintrea как решение

Решение

xintrea, нет, пробуем пересобрать код. Компилятор ругнется в тех местах, где происходит копирование объекта типа LineLayout, если таковое есть в коде.
Копирование для этого класса должно быть запрещено, либо написан соответствующий конструктор копирования. Ни того ни другого в коде не было. Это может быть причиной вашей ошибки (а может и не быть, но я бы начал с этого).
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
25.06.2021, 01:33
Цитата Сообщение от xintrea Посмотреть сообщение
В общем, по всей видимости, происходит двойное высвобождение ресурса positions
Очень маловероятно. Тем более что там присваивание 0 указателям, так что код

C++
1
2
3
4
    lineStarts = new float[10];
    delete []lineStarts;
    lineStarts = 0;
    delete []lineStarts;
вполне выполнится без ошибок.

Более вероятно, что идёт обращение наподобие positions[i] где i- больше длины динамического массива, который был выделен и записан в указатель positions . После этого при попытке очистить кучу от этой динамич. выделенной памяти обнаруживается обращение/изменение там, где ничего изменяться не должно. Итого-вылет.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12938 / 6805 / 1821
Регистрация: 18.10.2014
Сообщений: 17,224
25.06.2021, 04:43
Цитата Сообщение от TRam_ Посмотреть сообщение
Очень маловероятно. Тем более что там присваивание 0 указателям, так что код
99 случаев двойного освобождения из 100 - это двойные освобождения через разные указатели с одним и тем же значением. По этой причине "присваивание 0 указателям" практически не имеет никакого эффекта и никак не предотвращает двойные освобождения.

Проверить теорию о двойном освобождении стоит. Хотя "invalid next size" может скорее означать запись в освобожденную память после освобождения.

Обе проблемы вполне могут быть выявлены предложенным DrOffset способом.

Цитата Сообщение от xintrea Посмотреть сообщение
Я специально сделал GIF-анимацию из двух скриншотов:
GIF-анимация без котэ - пиксели на ветер.
0
Неэпический
 Аватар для Croessmah
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 1
25.06.2021, 08:59
Что-то странное, но это не точно
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12938 / 6805 / 1821
Регистрация: 18.10.2014
Сообщений: 17,224
25.06.2021, 10:02
Цитата Сообщение от Croessmah Посмотреть сообщение
Что-то странное, но это не точно
Itanium ABI предполагает генерацию как минимум двух деструкторов для каждого класса: деструктор динамического объекта (вызывает operator delete) и деструктор нединамического объекта (не вызывает operator delete). При этом первый может вызывать из себя второй.

Например

https://godbolt.org/z/3bcWhj91r

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
 
struct S
{
  void operator delete(void *p) {}
  virtual ~S() {}
};
 
int main()
{
  S* ps = new S;
  delete ps;
}
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
S::~S() [base object destructor]:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     edx, OFFSET FLAT:vtable for S+16
        mov     rax, QWORD PTR [rbp-8]
        mov     QWORD PTR [rax], rdx
        nop
        pop     rbp
        ret
S::~S() [deleting destructor]:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     QWORD PTR [rbp-8], rdi
        mov     rax, QWORD PTR [rbp-8]
        mov     rdi, rax
        call    S::~S() [complete object destructor] ; <-- вызов одного деструктора из другого деструктора
        mov     rax, QWORD PTR [rbp-8]
        mov     rdi, rax
        call    S::operator delete(void*)
        leave
        ret
Возможно здесь мы как раз видим что-то подобное.
1
25.06.2021, 14:02

Не по теме:

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Itanium ABI предполагает генерацию как минимум двух деструкторов
Да, я в курсе, поэтому и написал, что это не точно.
Я почему-то думал, что отладчик не будет показывать, но проверил, действительно, показывает два деструктора.
Спасибо.

0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
25.06.2021, 23:06
Цитата Сообщение от DrOffset Посмотреть сообщение
Значит, добавляем в заголовок класса LineLayout следующие строки:
Строки ничего не меняют, ошибок компиляции или предупреждений при включенном С++11 нет.
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
25.06.2021, 23:30
TRam_, ну не меняют и не меняют.
0
1 / 1 / 0
Регистрация: 29.10.2013
Сообщений: 74
26.06.2021, 12:46  [ТС]
Я добавил вот так:

C++
1
2
3
4
5
6
7
8
9
10
11
12
class LineLayout {
private:
    friend class LineLayoutCache;
    int *lineStarts;
    int lenLineStarts;
    /// Drawing is only performed for @a maxLineLength characters on each line.
    int lineNumber;
    bool inCache;
public:
 
    LineLayout(LineLayout const &) = delete;
    LineLayout & operator=(LineLayout const &) = delete;
Компиляция идет без ошибок.

Я открыл баг на странице проекта, может быть авторы смогут исправить: https://github.com/Gargaj/Bonzomatic/issues/160
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
26.06.2021, 12:46
Помогаю со студенческими работами здесь

Как записать в вектор структуру? Это вообще возможно сделать?
Привет всем! Как записать в вектор структуру? Это вообще возможно сделать? Надо, чтоб первая строка из файла записывалась в вектор,...

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

как можно сделать это? если вообще возможно (не задача)
есть задача, на двумерный массив... вывел массив 5х5 с рандомными числами, нужно найти числа локального минимума, т.е. чтоб число было...

Как в конструкторе и деструкторе узнать какой он по счету
Пусть у меня есть класс, в котором я сам указываю конструктор и деструктор. class Solution{ private: int x; public: ...

Как три разных метода синхронно запустить и вообще возможно ли это?
Решаю задачу о ферзях: Найти все мирные расстановки N ферзей на шахматной доске N на N. Занимаюсь оптимизацией моего решения. private...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru