Есть ли способ обнаружить нарушения ODR встроенной функции?

Итак, у меня есть этот код в двух отдельных единицах перевода:

// a.cpp
#include <stdio.h>
inline int func() { return 5; }
int proxy();
int main() { printf("%d", func() + proxy()); }

// b.cpp
inline int func() { return 6; }
int proxy() { return func(); }

При нормальной компиляции результат 10. При компиляции с -O3 (встраивание) я получаю 11.

Я явно нарушил ODR для func().

Это появилось, когда я начал объединять источники разных dll с меньшим количеством dll.

Я пытался:

  • GCC 5.1 -Wodr (для которого требуется -flto)
  • золотой линкер с -detect-odr-violations
  • установка ASAN_OPTIONS=detect_odr_violation=1 перед запуском инструментированного двоичного файла с дезинфицирующим средством адреса.

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

Это действительно неприятная проблема C++, и я удивлен тем, что нет надежных инструментов для ее обнаружения.

Возможно, я неправильно использовал один из инструментов, которые пробовал? Или для этого есть другой инструмент?

ИЗМЕНИТЬ:

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

Это также влияет на методы класса, определенные внутри тела класса — они неявно встроены.

// a.cpp
struct A { int data; A() : data(5){} };

// b.cpp
struct A { int data; A() : data(6){} };

Устаревший код с большим количеством копий/вставок + незначительные модификации после этого - это радость.


person onqtam    schedule 30.07.2015    source источник
comment
Мне было бы интересно, каков будет вариант использования функций inline в файле .cpp. Я не могу думать ни о каком возможном преимуществе.   -  person sjdowling    schedule 30.07.2015
comment
@sjdowling, почему встроенное ключевое слово? унаследованный код. Также обратите внимание на это: struct A { A(){} }; - здесь конструктор определен внутри определения структуры и неявно встроен. 2 такие структуры могут иметь одинаковый макет, но разные встроенные методы...   -  person onqtam    schedule 30.07.2015
comment
Возможно, самый простой способ найти эти нарушения ODR в этом унаследованном коде — это удалить все спецификаторы inline из функций, определенных в файлах .cpp, и изучить все возникшие ошибки компоновки.   -  person sjdowling    schedule 30.07.2015
comment
Эта статья может оказаться полезной: Девиртуализация в C++ , часть 7 (Применение правила одного определения)   -  person Shafik Yaghmour    schedule 30.07.2015
comment
Мне нравится, как ты используешь слово «наследие» для обозначения «сломанного». Этот код никогда не был хорошей идеей.   -  person Lightness Races in Orbit    schedule 30.07.2015


Ответы (2)


Самый простой способ обнаружить такие проблемы — скопировать все функции в одну единицу компиляции (при необходимости создать ее временно). Тогда любой компилятор C++ сможет обнаруживать повторяющиеся определения и сообщать о них при компиляции этого файла.

person Peter    schedule 30.07.2015
comment
Это мой текущий способ решения таких проблем, но не всегда легко сделать сборку единства — много устаревшего кода + анонимная статика + препроцессор. Также это не помогает с символами из статических библиотек. - person onqtam; 30.07.2015

Инструменты несовершенны.

Я думаю, что проверка Голда заметит только, когда символы имеют разные типы или разные размеры, что здесь неверно (обе функции будут скомпилированы с одинаковым количеством инструкций, просто используя другое непосредственное значение).

Я не уверен, почему -Wodr здесь не работает, но я думаю, что он работает только для типов, а не для функций, т. е. он обнаружит два конфликтующих определения типа класса T, но не ваш func().

Я ничего не знаю о проверке ODR ASan.

person Jonathan Wakely    schedule 30.07.2015