Динамическое распределение среды выполнения библиотеки классов c ++

Предположим, у меня есть класс интерфейса

class foo_if_t {

};

, первая библиотека libfoo_orig.so с классом foo_t который наследует от foo_if_t и имеет следующий код:

#include "foo_if.h"
class foo_t : public foo_if_t{
private:
int res;
public:
foo_t(){}
virtual ~foo_t(){}
};

и вторая библиотека libfoo_mod.so с классом foo_t переопределено следующим образом:

#include "foo_if.h"
class foo_t : public foo_if_t{
private:
int res[100];
public:
foo_t() {
for (int i=0; i<100; i++)
res[i] = i;
}
virtual ~foo_t(){}
};

Я создаю символическую ссылку libfoo.so --> libfoo_orig.so и скомпилируйте следующее приложение

#include "foo_orig.h"
int main(){
foo_if_t *foo_if = new foo_t();
delete foo_if;
}

с g++ -ggdb -O0 test.cpp -o test -L. -lfoo (следовательно, ссылка на libfoo.so).

С этой точки зрения Я изменяю символическую ссылку на цель libfoo_mod.so и перезапустите код. Это приведет к следующей ошибке:

*** Error in `./test': free(): invalid next size (fast): 0x0000000001ec9010 ***
Aborted (core dumped)

Я верю, что это может произойти из-за того, что foo_t из библиотеки foo_orig.so ест меньше кучи, чем тот, из foo_mod.so, так когда foo_mod.so foo_t вызывается конструктор, он загрязняет память кучи за пределами границ выделения (следовательно, портит кучу next Ссылка на чанк). Это говорит мне о том, что резервирование кучи каким-то образом предварительно вычисляется во время соединения, тогда как я думал, что оно будет разрешено динамически во время выполнения на основе фактического вызова кода конструктора. Я неправильно понял, и, если нет, почему полученный код выхода ведет себя так?

В качестве контр-теста я завернул new foo_t() вызов в рамках реализации static foo_it_t * foo_if_t::new_instance() написано для каждой библиотеки; ссылающееся new_instance из основного кода работает правильно.

2

Решение

Проблема здесь в том, что код вашей библиотеки и код основной программы имеют разное представление о структуре макета foo_t, Хотя они оба распознают существование типа, они оба были скомпилированы с другой версией заголовка, который его определяет. Это всегда приведет к большим неприятностям.

В вашем случае проблема вызвана тем, что фактическое выделение памяти, выполняемое new, скомпилирован из основной программы и поэтому имеет одно представление о размере создаваемого объекта. Между тем, конструктор скомпилирован с библиотечным кодом и имеет совершенно другое представление о размере базового объекта. Таким образом, основная программа создает объект в куче, которая sizeof(foo_t) — который sizeof(int) с его точки зрения. Конструктор, не зная этого, с радостью сокращает память до 100 дюймов, тем самым разрушая кучу.

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

2

Другие решения

Других решений пока нет …