Bug 24129 – ImportC: MS-Link cannot handle multiple COMDATs with the same name

Status
RESOLVED
Resolution
FIXED
Severity
critical
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Windows
Creation time
2023-09-01T18:36:35Z
Last change time
2024-04-10T02:48:38Z
Keywords
pull
Assigned to
No Owner
Creator
Jeffrey H. Johnson

Comments

Comment #0 by trnsz — 2023-09-01T18:36:35Z
fatal error LNK1179: invalid or corrupt file: duplicate COMDAT '__acrt_locale_get_ctype_array_value' with DMD64 on Windows - it seems things are NOT being properly inlined. This is likely a new problem with the current MSVC header, because almost any non-trivial program that ends up including ctypes.h (or many other haders) cannot be linked, so nearly nothing can be built with ImportC. Reproducer: DMD version: DMD64 D Compiler v2.105.0-dirty Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved written by Walter Bright (NOTE: this is the DMD installer from the website, not sure why it reports as dirty - I did not build it myself). Windows 11 with MSVC Community edition. Here is a minimal reproducer: >>>TYPE a.c b.c a.c #include <ctype.h> extern void xa(void) { } b.c #include <ctype.h> int main(void) { void xa(void); xa(); return 0; } >>>dmd -v a.c b.c predefs DigitalMars LittleEndian D_Version2 all D_SIMD Windows Win64 CRuntime_Microsoft CppRuntime_Microsoft D_InlineAsm_X86_64 X86_64 D_LP64 assert D_PreConditions D_PostConditions D_Invarian ts D_ModuleInfo D_Exceptions D_TypeInfo D_HardFloat binary dmd version v2.105.0-dirty config C:\D\dmd2\windows\bin64\sc.ini DFLAGS -IC:\D\dmd2\windows\bin64\..\..\src\phobos -IC:\D\dmd2\windows\bin64\..\..\src\druntime\import include C:\D\dmd2\windows\bin64\..\..\src\druntime\import\importc.h C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\bin\HostX64\x64\cl.exe /P /Zc:preprocessor /PD /nologo a.c /FIC:\D\dmd2\windows\bin64\..\..\src\druntime\import\importc.h /Fia.i include C:\D\dmd2\windows\bin64\..\..\src\druntime\import\importc.h C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\bin\HostX64\x64\cl.exe /P /Zc:preprocessor /PD /nologo b.c /FIC:\D\dmd2\windows\bin64\..\..\src\druntime\import\ importc.h /Fib.i predefs DigitalMars LittleEndian D_Version2 all D_SIMD Windows Win64 CRuntime_Microsoft CppRuntime_Microsoft D_InlineAsm_X86_64 X86_64 D_LP64 assert D_PreConditions D_PostConditions D_Invarian ts D_ModuleInfo D_Exceptions D_TypeInfo D_HardFloat binary dmd version v2.105.0-dirty config C:\D\dmd2\windows\bin64\sc.ini DFLAGS -IC:\D\dmd2\windows\bin64\..\..\src\phobos -IC:\D\dmd2\windows\bin64\..\..\src\druntime\import include C:\D\dmd2\windows\bin64\..\..\src\druntime\import\importc.h C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\bin\HostX64\x64\cl.exe /P /Zc:preprocessor /PD /nologo a.c /FIC:\D\dmd2\windows\bin64\..\..\src\druntime\import\importc.h /Fia.i include C:\D\dmd2\windows\bin64\..\..\src\druntime\import\importc.h C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\bin\HostX64\x64\cl.exe /P /Zc:preprocessor /PD /nologo b.c /FIC:\D\dmd2\windows\bin64\..\..\src\druntime\import\importc.h /Fib.i parse a parse b importall a import __builtins (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\__builtins.di) import object (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\object.d) import core.internal.hash (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\hash.d) import core.internal.traits (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\traits.d) import core.internal.entrypoint (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\entrypoint.d) import core.internal.array.appending (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\array\appending.d) import core.internal.array.comparison (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\array\comparison.d) import core.internal.array.equality (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\array\equality.d) import core.internal.array.casting (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\array\casting.d) import core.internal.array.concatenation (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\array\concatenation.d) import core.internal.array.construction (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\array\construction.d) import core.internal.array.arrayassign (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\array\arrayassign.d) import core.internal.array.capacity (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\array\capacity.d) import core.internal.dassert (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\dassert.d) import core.atomic (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\atomic.d) import core.internal.attributes (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\attributes.d) import core.internal.atomic (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\atomic.d) import core.internal.destruction (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\destruction.d) import core.internal.moving (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\moving.d) import core.internal.postblit (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\postblit.d) import core.internal.switch_ (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\switch_.d) import core.lifetime (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\lifetime.d) import core.builtins (C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\builtins.d) importall b semantic a semantic b semantic2 a semantic2 b semantic3 a semantic3 b inline scan a inlined a.__acrt_locale_get_ctype_array_value => a._chvalidchk_l inlined a.__acrt_locale_get_ctype_array_value => a._chvalidchk_l inlined a._chvalidchk_l => a._ischartype_l inline scan b inlined b.__acrt_locale_get_ctype_array_value => b._chvalidchk_l inlined b.__acrt_locale_get_ctype_array_value => b._chvalidchk_l inlined b._chvalidchk_l => b._ischartype_l code a function a.__acrt_locale_get_ctype_array_value function a.__ascii_tolower function a.__ascii_toupper function a.__ascii_iswalpha function a.__ascii_iswdigit function a.__ascii_towlower function a.__ascii_towupper function a.__acrt_get_locale_data_prefix function a._chvalidchk_l function a._ischartype_l function a.xa code b function b.__acrt_locale_get_ctype_array_value function b.__ascii_tolower function b.__ascii_toupper function b.__ascii_iswalpha function b.__ascii_iswdigit function b.__ascii_towlower function b.__ascii_towupper function b.__acrt_get_locale_data_prefix function b._chvalidchk_l function b._ischartype_l function b.main C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\bin\HostX64\x64\link.exe /NOLOGO "a.obj" /DEFAULTLIB:phobos64 /LIBPATH:"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\lib\x64" legacy_stdio_definitions.lib /LIBPATH:"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\ucrt\x64" /LIBPATH:"C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\um\x64" a.obj : fatal error LNK1179: invalid or corrupt file: duplicate COMDAT '__acrt_locale_get_ctype_array_value' Error: linker exited with status 1179 ------------- This problem does repeat itself for all the functions listed above, if __acrt_locale_get_ctype_array_value is manually mangled appropriately with a hex editor.
Comment #1 by bugzilla — 2023-09-06T07:33:43Z
The problem stems from when a.c and b.c are compiled together, as in: dmd a.c b.c The code from both gets placed in one object file, a.obj. Hence there are two copies of __acrt_local_get_ctype_array value, and they conflict with each other. The workaround is to compile them separately. The same result is exhibited with this simple test case: --- a.c --- inline int test() { return 73; } void *def() { return &test; } int main() { return 0; } ----- b.c ------- inline int test() { return 73; } void *def() { return &test; } --------------- dmd a.c b.c a.obj : fatal error LNK1179: invalid or corrupt file: duplicate COMDAT 'test' Error: linker exited with status 1179
Comment #2 by trnsz — 2023-09-06T23:49:41Z
(In reply to Walter Bright from comment #1) > The problem stems from when a.c and b.c are compiled together, as in: > > dmd a.c b.c > > The code from both gets placed in one object file, a.obj. Hence there are > two copies of __acrt_local_get_ctype_array value, and they conflict with > each other. > > The workaround is to compile them separately. Thanks Walter! Do you think this might be something that can be worked around? The reason is performance, for example, on Linux: $ for i in *.c; do dmd -m64 -fPIC -fPIE -O -release -check=off -boundscheck=off "${i}" -c -of=objout/${i}.o; done $ dmd -m64 -fPIC -fPIE -O -release -check=off -boundscheck=off objout/*.o -of=test1 $ strip test1 $ ls -la test1 885 KB Wed Sep 6 19:29:54 2023 test1* $ rm -rf objout/* $ dmd -m64 -fPIC -fPIE -O -release -check=off -boundscheck=off *.c -of=test2 $ strip test2 $ ls -la test2 838 KB Wed Sep 6 19:30:27 2023 test2* It's quite close, but I can show (with statistical confidence) that the test2 build is a bit faster than test1 (in addition to being smaller and easier to compile). I assume that this is due to some linker optimizations? Does the compiler optimize better, almsot a "poor mans LTO" and treating it as a single translation unit, perhaps? I believe that using -inline (when it works, I made bug #24131 for that) also results in faster binaries when they are all built together, rather than separately. However, as a workaround, this seems acceptable for now, thank you so much. And I assume this is still a bug, so I'll leave this open for now.
Comment #3 by bugzilla — 2023-09-07T03:23:07Z
It's an important problem to fix. It's a problem only seen with the Microsoft linker - the other linkers automatically remove duplicates, even if they are in the same file. So I'd call it a workaround for an unusual behavior in the Microsoft linker :-) But I can't fix MS-LINK, so I'll just have to remove the duplicates in dmd.
Comment #4 by dlang-bot — 2023-09-08T02:28:58Z
@WalterBright created dlang/dmd pull request #15585 "fix Issue 24129 - ImportC: MS-Link cannot handle multiple COMDATs wit…" fixing this issue: - fix Issue 24129 - ImportC: MS-Link cannot handle multiple COMDATs with the same name https://github.com/dlang/dmd/pull/15585
Comment #5 by dlang-bot — 2023-09-20T22:50:56Z
dlang/dmd pull request #15585 "fix Issue 24129 - ImportC: MS-Link cannot handle multiple COMDATs wit…" was merged into master: - a60429f2eeb738195363ed47f2c519113fe62bd8 by Walter Bright: fix Issue 24129 - ImportC: MS-Link cannot handle multiple COMDATs with the same name https://github.com/dlang/dmd/pull/15585
Comment #6 by lance — 2024-04-10T02:48:38Z
This is marked RESOLVED FIXED but I get the same error message with DMD 2.108.0.