Я провел немало часов сегодня пытаясь понять, почему этот код segfaults на g++6.2
и g++7.0
, в то же время с удовольствием работая по clang++3.9
(и 4.0
).
Я уменьшил проблему до 85 строк самодостаточного фрагмента кода, который не выполняет segfault при нормальном но всегда сообщает об ошибке в UBSAN.
Проблема воспроизводится на wandbox путем компиляции с g++7
, что позволяет оптимизировать и передавать -fsanitize=undefined
как дополнительный флаг.
Вот что сообщает UBSAN:
prog.cc: In function 'int main()':
prog.cc:61:49: warning: 'ns#0' is used uninitialized in this function [-Wuninitialized]
([&] { ([&] { n.execute(ns...); })(); })();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
prog.cc:28:10: note: 'ns#0' was declared here
auto execute(TNode& n, TNodes&... ns)
^~~~~~~
prog.cc:30:9: runtime error: member call on null pointer of type 'struct node_then'
g++
утверждает, что ns#0
неинициализируется внутри "lambda gibberish" (который имитирует for_tuple
из исходного фрагмента). Теперь происходят некоторые очень интересные вещи:
-
Если я удалю "lambda gibberish", трансформируя строку 61 в
n.execute(ns...);
то UBSAN перестает жаловаться.
-
Если я меняю список захвата с
[&]
на[&n, &ns...]
, UBSAN также перестает жаловаться:([&](auto) { ([&n, &ns...] { n.execute(ns...); })(); })(0);
... подождите, что? Как это отличается от
[&]
?
Применение вышеуказанных открытий к исходному фрагменту кода исправляет segfaults.
Является ли это ошибкой g++
? Или есть ли в моем коде поведение undefined?