Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / ACHTUNG Баг в linker'e msvc!!

ACHTUNG Баг в linker'e msvc!!

Поделиться

Страницы: 1 2 Следующая

fsmokeПостоялецwww7 ноя. 201712:11#0
присказка
Ребятааа.. кажись я нашел древний баг в студии. Ну строго говоря нашел эту ситуацию мой сотрудник, а я подтвердил, что что-то тут не так. Может конечно я глючу и это какая-то странная особенность. Но баг на студию уже влепил на всякий

сказка
А дело вот в чем: начали смотреть один интересный код и увидели, что одна статическая переменная инициализируется 2 раза! ШОК! Сенсация! Ну да ладно - начали копать. Сначала думали дело в темплейтах - ну мож там 2 класса генерятся - ...та нет вроде один. Сделали тестовый бранч и начали корежить ... корежили корежили - и в результате выпилили всё и темплейты и прочую ересь - осталось пара детсадовских классов с парой методов. Ситуация эмулируется. Хм.. сделали тестовый проект - написали пару таких же тестовых классов - НЕ ЭМУЛИРУЕТСЯ. Бред. Привели оба проекта к одному виду - включая ключи настройки, дефайны и пр .. даже названия классов и методов ради прикола поменяли. Я уже побежал за пирацетаном :) чтоб с ума не сойти. Итого: 2 абсолютно одинаковых проджекта -  в одном из них 2 раза вызывается конструктор класса, переменная которого как раз статик. В другом один раз. Мы уже плывем и судорожно стираем пот со лба - решаем мерджилкой проверить vcxproj'ы. И тут.... БИНГО мы понимаем в чём разница. Меняем, проверяем - и вот уже в обоих проектах конструктор начинает вызываться 2 раза.

А суть вот в чем - ИМЕЕТ ЗНАЧЕНИЕ В КАКОМ ПОРЯДКЕ ДОБАВЛЕНЫ ФАЙЛЫ В ПРОЕКТ. Да да я понимаю, что это бред... но вот так как-то

т.е. если так писать - баг

<ItemGroup>
    <ClCompile Include="someone.cpp" />
    <ClCompile Include="main.cpp" />
</ItemGroup>

а если так - то всё ок

<ItemGroup>
    <ClCompile Include="main.cpp" />
    <ClCompile Include="someone.cpp" />
</ItemGroup>

и самое жуткое, что от этого зависит поведение программы

Еще момент : синглтон (который статик) внутри someone.cpp написан - но никогда не вызывается - он просто там есть - и это всё портит.

Вывод: я так понимаю, что баг в линкере - т.е. от порядка передачи обж в линкер - меняется поведение слинкованной проги - капец..

послесловие
И 2017 и 2015 и 2013 тулчейны подвержены. Мы даже откопали 2008ю студию на виртуалке - таже фигня, т.е. видимо это древнее зло.
Как именно надо написать, чтоб проявился баг - объяснять не буду, т.к. всё есть в тестовом проекте, лучше один раз увидеть имхо

тестовый проект
linker BUG
test_app.vcxproj - наблюдается баг
test_app_solved.vcxproj - не наблюдается бага

bodjaПостоялецwww7 ноя. 201712:22#1
fsmoke
> ШОК! Сенсация!
А не кто не додумался, что майн должен запускаться первым, не ? :)
WraithПостоялецwww7 ноя. 201712:27#2
Это не баг линкера ,а нарушение ODR. У тебя object_helper& get_helper() определена в хедере.
Edit: в каждом инклудящем хедер translation unit будет своя копия.

Правка: 7 ноя. 2017 12:29

fsmokeПостоялецwww7 ноя. 201712:49#3
Wraith
> в каждом инклудящем хедер translation unit будет своя копия.
>
инициализация локальных статиков происходит при первом вызове. Если бы в someone.cpp был бы вызов - тогда было бы очевидно, но в нем вызова нет. И даже если бы так было - то это всё равно не правильно - линкер должен это всё слить в один экземпляр имхо. никаких 2х экземпляров в конечном бинарнике быть не должно
fsmokeПостоялецwww7 ноя. 201712:51#4
и уж точно такое не должно происходить при вызове 2х методов одного и того же класса
fsmokeПостоялецwww7 ноя. 201712:53#5
bodja
> А не кто не додумался, что майн должен запускаться первым, не ? :)

вопроса не понял - при чем тут маин? это тестовый проект в реальном проекте 100500 файлов и подобный код выполняется фиг знает откуда 

WraithПостоялецwww7 ноя. 201713:29#6
fsmoke
> и уж точно такое не должно происходить при вызове 2х методов одного и того же класса
Так те методы объявлены инлайн, поэтому компилятся в каждом translation unit, где и видят определение статика get_helper().
fsmokeПостоялецwww7 ноя. 201713:39#7
Wraith
> Так те методы объявлены инлайн, поэтому компилятся в каждом translation unit,
> где и видят определение статика get_helper().

дык они скомпилены в юните main и вызывать они должны get_helper - который в юните main - здесь двоякости не должно быть. А получается что init вызывает экземпляр из main, а free вызывает экземпляр который уже в someone - бред

кстати сейчас проверили адрес фции get_helper - адрес у вызовов одинаковый(я полагаю всегда вызывается копия из юнита main как и должно быть) - а вот именно на free(2й вызов), таже самая фция с тем же самым адресом, почему-то решает проинитить вторую переменную -  я хз как так происходит

Правка: 7 ноя. 2017 13:46

PANDAПостоялецwww7 ноя. 201713:48#8
В someone.cpp идет вызов foo -> get_object. Если он заинлайнился, то у тебя и статическая локальная переменная заинлайнится и окажется в еще одной единице трасляции (someone.cpp). Короче, нефиг локальные статики юзать для серьезного функционала. Они помимо прочего и для производительности фиговые.

Правка: 7 ноя. 2017 13:50

-Eugene-Постоялецwww7 ноя. 201714:33#9
Что, как обычно кто-то нарвался на UB, и жалуется на баг компилятора линкера?
return [](){};Участникwww7 ноя. 201714:46#10
Линкер мержит (вернее выкидывает все кроме одной) только inline функции (в т.ч. inline методы класса), static функции всегда будет свой экземпляр в каждом translation unit. Порядок, в котором объектники передаются в линкер, влияет на то, из каких объектников inline функции будут взяты. Тоже вангую нарушение ODR, но в коде разбираться лень.
-Eugene-Постоялецwww7 ноя. 201714:52#11
return [](){};
Да там разбираться нечего. За каким-то хреном функция объявлена как static в хидере. Предвижу, что замена static на inline все вылечит. Хотя я не знаю точно, почему.
fsmokeПостоялецwww7 ноя. 201715:14#12
-Eugene-
> static на inline
всё верно - так вчера и поправили.
fsmokeПостоялецwww7 ноя. 201715:21#13

return [](){};
> Порядок, в котором объектники передаются в линкер, влияет на то, из каких
> объектников inline функции будут взяты.
ты хотел сказать, static функции
StiXПостоялецwww7 ноя. 201715:46#14
TL;DR можно?
Как всегда баг оказался в программисте, а не в компиляторе?

Страницы: 1 2 Следующая

/ Форум / Программирование игр / Общее

2001—2017 © GameDev.ru — Разработка игр