Как правильно выставить интерфейсы из dll при наличии VC ++ 2015 при оптимизации всей программы

недавно мы столкнулись в нашем унаследованном коде, который в настоящее время портирован с VS2010 на VS2015, с интересным эффектом. К сожалению, я не смог создать небольшой пример, демонстрирующий этот эффект, но я постараюсь описать его как можно точнее.

У нас есть 2 dll (я назову их dll A и dll B). Проект для dll A определяет интерфейс IFoo & производный интерфейс IFxFoo

class __declspec(novtable) IFoo {
public:
virtual int GetType() = 0;
virtual ~IFoo() {}
};

class __declspec(novtable) IFxFoo : public IFoo {
public:
virtual int GetSlot() = 0;
};

в dll B используются оба интерфейса.

class CBImpl : public IFxFoo {
public:
...
void processFoo(IFoo* f) {
...
if (f->GetType() == IFXFOO) {
IFxFoo* fx = static_cast<IFxFoo>(f); //downcast
fill(fx);
}
}

void fill(IFxFoo* fx) {
m_slot = fx->GetSlot();
}
private:
int m_slot;
};

processFoo () будет вызываться с различными реализациями IFoo. Некоторые из dll A, а некоторые из dll B.

Теперь произошло следующее:
— если мы включили оптимизацию всей программы при компиляции dll B, вызов виртуальной функции GetSlot () в функции fill () был де-виртуализирован Visual C ++. Это вызвало сбой нашей программы.
мы можем исправить это поведение, если мы либо

  • поворот всей программы оптимизации
  • поворот оптимизации для заполнения
  • или пометьте наши интерфейсы с помощью __declspec (dllimport) / __declspec (dllexport)

У меня есть следующие вопросы:

  • Правильно ли наше предположение, что де-виртуализация произошла потому, что оптимизатор увидел только одну реализацию IFxFoo в dll B и предположил, что это единственная реализация, поскольку IFxFoo не был помечен как принадлежащий другой dll?
  • Каков наилучший способ создания «интерфейсов» в заголовочных файлах? Раньше мы делали их, как описано выше, но это, кажется, приводит к некоторым проблемам.
  • другой компилятор (gcc / clang) демонстрирует подобное поведение?

Спасибо за помощь
Тобиас

0

Решение

Использование LTO приводит к тому, что компилятор вносит радикальные коррективы в любые функции, для которых он может видеть полный список вызовов.

То, что вы видите, ожидается и использует __declspec(dllexport) или же extern на функциях, которые необходимо использовать из отдельного модуля или явно объявить их как часть DLL-файла .def, — это ожидаемый способ решения проблемы, так как компилятор больше не будет считать функции только внутренними.

0

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

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

По вопросам рекламы [email protected]