Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replacing checked-in OBJ files with /ALTERNATENAME broke linker compatibility #2655

Closed
StephanTLavavej opened this issue Apr 14, 2022 · 9 comments · Fixed by #2734
Closed
Labels
bug Something isn't working fixed Something works now, yay! high priority Important!

Comments

@StephanTLavavej
Copy link
Member

StephanTLavavej commented Apr 14, 2022

For supply chain security, #2381 replaced checked-in OBJ files (generated by an internal tool aliasobj) with the linker's /ALTERNATENAME option (which is strictly more reproducible, although not officially documented).

We had never done this before, and although I ensured that the mangled names were identical, I didn't consider all possible scenarios. In certain situations, using a third-party library compiled with an older MSVC toolset, and performing the final link with a newer MSVC toolset, can emit "unresolved external symbol" linker errors that look like:

[x86]
error LNK2001: unresolved external symbol __imp____std_init_once_begin_initialize@16
error LNK2001: unresolved external symbol __imp____std_init_once_complete@12

[x64, ARM, ARM64]
error LNK2019: unresolved external symbol __imp___std_init_once_begin_initialize
error LNK2019: unresolved external symbol __imp___std_init_once_complete

I apologize for breaking linker compatibility here. Due to the supply chain security impact (and the fact that the aliasobj tool is still not yet publicly available), we can't undo this change. There are a couple of options to resolve these errors:

  1. Permanent fix: Rebuild the third-party library with VS 2022 17.2 or newer.
  2. Build system workaround: Add the following linker options, depending on the target architecture:
    • For x86: /ALTERNATENAME:__imp____std_init_once_begin_initialize@16=__imp__InitOnceBeginInitialize@16 /ALTERNATENAME:__imp____std_init_once_complete@12=__imp__InitOnceComplete@12
    • For x64, ARM, and ARM64: /ALTERNATENAME:__imp___std_init_once_begin_initialize=__imp_InitOnceBeginInitialize /ALTERNATENAME:__imp___std_init_once_complete=__imp_InitOnceComplete

I've filed this issue so that the error messages are searchable. I can also answer further questions if you've encountered these errors (I may not see GitHub notifications, so you may need to get my attention in the STL's Discord server.)

Also tracked by DevCom-1684365 / internal VSO-1495049 / AB#1495049 .

@StephanTLavavej StephanTLavavej added bug Something isn't working resolved Successfully resolved without a commit labels Apr 14, 2022
@akoeplinger
Copy link
Member

@StephanTLavavej we hit this and tried the #include <mutex> workaround but it did NOT work.

Adding the linker options worked fine though 😄 In our case we used the pragmas like you do here:

STL/stl/src/xonce2.cpp

Lines 33 to 43 in dd5be88

#if defined(_M_ARM64EC) || defined(_M_HYBRID)
// <mutex> uses the forwarder fallbacks for ARM64EC and CHPE.
#elif defined(_M_IX86)
#pragma comment(linker, "/ALTERNATENAME:__imp____std_init_once_begin_initialize@16=__imp__InitOnceBeginInitialize@16")
#pragma comment(linker, "/ALTERNATENAME:__imp____std_init_once_complete@12=__imp__InitOnceComplete@12")
#elif defined(_M_X64) || defined(_M_ARM) || defined(_M_ARM64)
#pragma comment(linker, "/ALTERNATENAME:__imp___std_init_once_begin_initialize=__imp_InitOnceBeginInitialize")
#pragma comment(linker, "/ALTERNATENAME:__imp___std_init_once_complete=__imp_InitOnceComplete")
#else // ^^^ known architecture / unknown architecture vvv
#error Unknown architecture
#endif // ^^^ unknown architecture ^^^

@akoeplinger
Copy link
Member

ah and one difference I just noticed: we're building for x64 but still got the error LNK2001: unresolved external symbol __imp___std_init_once_begin_initialize, not the LNK2019 error code

@StephanTLavavej
Copy link
Member Author

Thanks, I've updated the workaround list. I'm not sure what the difference is between the LNK2001 and LNK2019 numbers - thanks again for reporting what you observed.

@walbourn
Copy link
Member

walbourn commented May 19, 2022

We have reports of this with our static library C++ built with VS 2019 being used with VS 2022 17.2 per forward compatibility, but none of our samples, regression validations, or tests broke.

Turns out the samples all built utility code that itself used <future> which in turn pulls in init once. Since the utility code was built with the current toolset, it pulls in __std_init_once_link_alternate_names_and_abort and then the otherwise breaking static C++ library finds it's symbols there without having to use the explicit /linker workaround above.

Therefore, another workaround is: "Use more of the C++ features in your code." :)

@StephanTLavavej StephanTLavavej removed the resolved Successfully resolved without a commit label May 19, 2022
@StephanTLavavej StephanTLavavej added the high priority Important! label May 19, 2022
@StephanTLavavej
Copy link
Member Author

We'll look into ways to fully fix this, as many customers are encountering this break.

@StephanTLavavej
Copy link
Member Author

Merged for VS 2022 17.3 Preview 3. I'll begin the process to port this to 17.2.x (no promises yet).

@camptatopenmars
Copy link

camptatopenmars commented Jun 7, 2022

Whatever the change was... it seems to have found its way into an update for VS2019 as well and my build is b0rked.

1>libprotobufd.lib(any.cc.obj) : error LNK2001: unresolved external symbol __std_init_once_link_alternate_names_and_abort
.... etc.

Which seems to be a bit different of an error than initially reported here. What lib am I now missing?

@CaseyCarter
Copy link
Contributor

Whatever the change was... it seems to have found its way into an update for VS2019 as well and my build is b0rked.

That doesn't seem to be the case; findstr std_init_once_link_alternate "c:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30133\include" finds nothing, indicating the change in question ins't part of VS2019.

1>libprotobufd.lib(any.cc.obj) : error LNK2001: unresolved external symbol __std_init_once_link_alternate_names_and_abort

Are you certain you aren't using an older (VS2019) toolset to link to a library built with a newer (VS2022) toolset? That's not a supported configuration; the toolset used to link must be at as new as the newest toolset used to compile any object file/DLL.

@camptatopenmars
Copy link

You are indeed correct! We are using vcpkg... which apparently by design has been causing us to be linking with vs2022 toolchain artifacts since we installed it since we certainly didn't expect it to select a toolchain other than what msbuild was using.... This change being apparently the first breaking ABI change between vs2019 and vs2022... microsoft/vcpkg#23308. Thanks for the clue/apologies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working fixed Something works now, yay! high priority Important!
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants