llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.1k stars 11.6k forks source link

Three AddressSanitizer-x86_64-windows-dynamic coverage tests fail when building with CMAKE_LINKER=lld-link.exe #41419

Closed nico closed 5 years ago

nico commented 5 years ago
Bugzilla Link 42074
Resolution FIXED
Resolved on Jun 11, 2019 04:40
Version unspecified
OS Linux
CC @compnerd,@mstorsjo,@rnk,@rui314
Fixed by commit(s) r362849

Extended Description

When doing build of LLVM on Windows with CMAKE_LINKER set to lld-link, 3 tests fail.

I don't immediately see how the failures are related to things building with lld -- the test doesn't use lld.

Maybe the shared libasan linked by lld is missing symbols or something?

Full cmake invocation below.

-- Testing: 49878 tests, 32 threads -- Testing: 0 .. FAIL: AddressSanitizer-x86_64-windows-dynamic :: TestCases/Windows/coverage-basic.cc (4634 of 49878) **** TEST 'AddressSanitizer-x86_64-windows-dynamic :: TestCases/Windows/coverage-basic.cc' FAILED **** Script:

: 'RUN: at line 1'; rm -rf C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Windows\Output\coverage-basic.cc.tmp-dir : 'RUN: at line 2'; mkdir C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Windows\Output\coverage-basic.cc.tmp-dir && cd C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Windows\Output\coverage-basic.cc.tmp-dir : 'RUN: at line 3'; C:/b/s/w/ir/k/src/third_party/llvm-build/Release+Asserts/./bin/clang.exe -fsanitize=address -mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -fno-optimize-sibling-calls -gline-tables-only -gcodeview -gcolumn-info -shared-libasan -D_MT -D_DLL -Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames -fsanitize-coverage=func C:\b\s\w\ir\k\src\third_party\llvm\compiler-rt\test\asan\TestCases\Windows\coverage-basic.cc -o test.exe : 'RUN: at line 4'; env ASAN_OPTIONS=coverage=1 ./test.exe : 'RUN: at line 6'; C:/b/s/w/ir/cache/vpython/21a792/Scripts/python.exe C:/b/s/w/ir/k/src/third_party/llvm/compiler-rt\lib\sanitizer_common\scripts\sancov.py print *.sancov | FileCheck C:\b\s\w\ir\k\src\third_party\llvm\compiler-rt\test\asan\TestCases\Windows\coverage-basic.cc

Exit Code: 1120

Command Output (stdout):

$ ":" "RUN: at line 1" $ "rm" "-rf" "C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Windows\Output\coverage-basic.cc.tmp-dir" $ ":" "RUN: at line 2" $ "mkdir" "C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Windows\Output\coverage-basic.cc.tmp-dir" $ ":" "RUN: at line 3" $ "C:/b/s/w/ir/k/src/third_party/llvm-build/Release+Asserts/./bin/clang.exe" "-fsanitize=address" "-mno-omit-leaf-frame-pointer" "-fno-omit-frame-pointer" "-fno-optimize-sibling-calls" "-gline-tables-only" "-gcodeview" "-gcolumn-info" "-shared-libasan" "-D_MT" "-D_DLL" "-Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames" "-fsanitize-coverage=func" "C:\b\s\w\ir\k\src\third_party\llvm\compiler-rt\test\asan\TestCases\Windows\coverage-basic.cc" "-o" "test.exe"

command output:

coverage-basic-ce3187.o : error LNK2019: unresolved external symbol sanitizer_cov_trace_pc_guard referenced in function "void cdecl foo(void)" (?foo@@YAXXZ) coverage-basic-ce3187.o : error LNK2019: unresolved external symbol __sanitizer_cov_trace_pc_guard_init referenced in function sancov.module_ctor_trace_pc_guard test.exe : fatal error LNK1120: 2 unresolved externals

command stderr:

clang: warning: argument '-fsanitize-coverage=[func|bb|edge]' is deprecated, use '-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]' instead [-Wdeprecated] clang: error: linker command failed with exit code 1120 (use -v to see invocation)

error: command failed with exit status: 1120

--


Testing: 0 .. FAIL: AddressSanitizer-x86_64-windows-dynamic :: TestCases/Windows/coverage-dll-stdio.cc (4672 of 49878) **** TEST 'AddressSanitizer-x86_64-windows-dynamic :: TestCases/Windows/coverage-dll-stdio.cc' FAILED **** Script:

: 'RUN: at line 4'; rm -rf C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Windows\Output\coverage-dll-stdio.cc.tmp && mkdir C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Windows\Output\coverage-dll-stdio.cc.tmp && cd C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Windows\Output\coverage-dll-stdio.cc.tmp : 'RUN: at line 5'; C:/b/s/w/ir/k/src/third_party/llvm-build/Release+Asserts/./bin/clang-cl.exe -fsanitize=address -Wno-deprecated-declarations -WX -D_HAS_EXCEPTIONS=0 -Zi -MD -fsanitize-coverage=func,trace-pc-guard -O0 C:\b\s\w\ir\k\src\third_party\llvm\compiler-rt\test\asan\TestCases\Windows/dll_host.cc -Fet.exe : 'RUN: at line 6'; C:/b/s/w/ir/k/src/third_party/llvm-build/Release+Asserts/./bin/clang-cl.exe -fsanitize=address -Wno-deprecated-declarations -WX -D_HAS_EXCEPTIONS=0 -Zi -MD -fsanitize-coverage=func,trace-pc-guard -LD -O0 C:\b\s\w\ir\k\src\third_party\llvm\compiler-rt\test\asan\TestCases\Windows\coverage-dll-stdio.cc -Fet.dll : 'RUN: at line 7'; ./t.exe t.dll 2>&1 | FileCheck C:\b\s\w\ir\k\src\third_party\llvm\compiler-rt\test\asan\TestCases\Windows\coverage-dll-stdio.cc

Exit Code: 1120

Command Output (stdout):

$ ":" "RUN: at line 4" $ "rm" "-rf" "C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Windows\Output\coverage-dll-stdio.cc.tmp" $ "mkdir" "C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Windows\Output\coverage-dll-stdio.cc.tmp" $ ":" "RUN: at line 5" $ "C:/b/s/w/ir/k/src/third_party/llvm-build/Release+Asserts/./bin/clang-cl.exe" "-fsanitize=address" "-Wno-deprecated-declarations" "-WX" "-D_HAS_EXCEPTIONS=0" "-Zi" "-MD" "-fsanitize-coverage=func,trace-pc-guard" "-O0" "C:\b\s\w\ir\k\src\third_party\llvm\compiler-rt\test\asan\TestCases\Windows/dll_host.cc" "-Fet.exe"

command output:

dll_host-bea811.obj : error LNK2019: unresolved external symbol __sanitizer_cov_trace_pc_guard referenced in function main dll_host-bea811.obj : error LNK2019: unresolved external symbol __sanitizer_cov_trace_pc_guard_init referenced in function sancov.module_ctor_trace_pc_guard t.exe : fatal error LNK1120: 2 unresolved externals

command stderr:

clang-cl: error: linker command failed with exit code 1120 (use -v to see invocation)

error: command failed with exit status: 1120

--


Testing: 0 .. FAIL: AddressSanitizer-x86_64-windows-dynamic :: TestCases/coverage-disabled.cc (4747 of 49878) **** TEST 'AddressSanitizer-x86_64-windows-dynamic :: TestCases/coverage-disabled.cc' FAILED **** Script:

: 'RUN: at line 3'; rm -rf C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Output\coverage-disabled.cc.tmp-dir : 'RUN: at line 4'; mkdir -p C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Output\coverage-disabled.cc.tmp-dir : 'RUN: at line 6'; C:/b/s/w/ir/k/src/third_party/llvm-build/Release+Asserts/./bin/clang.exe -fsanitize=address -mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -fno-optimize-sibling-calls -gline-tables-only -gcodeview -gcolumn-info -shared-libasan -D_MT -D_DLL -Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames -fsanitize-coverage=func C:\b\s\w\ir\k\src\third_party\llvm\compiler-rt\test\asan\TestCases\coverage-disabled.cc -o C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Output\coverage-disabled.cc.tmp : 'RUN: at line 8'; env ASAN_OPTIONS=coverage_direct=0:coverage_dir='"C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Output\coverage-disabled.cc.tmp-dir"':verbosity=1 C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Output\coverage-disabled.cc.tmp : 'RUN: at line 9'; not C:/b/s/w/ir/cache/vpython/21a792/Scripts/python.exe C:/b/s/w/ir/k/src/third_party/llvm/compiler-rt\lib\sanitizer_common\scripts\sancov.py print C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Output\coverage-disabled.cc.tmp-dir/*.sancov 2>&1

Exit Code: 1120

Command Output (stdout):

$ ":" "RUN: at line 3" $ "rm" "-rf" "C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Output\coverage-disabled.cc.tmp-dir" $ ":" "RUN: at line 4" $ "mkdir" "-p" "C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Output\coverage-disabled.cc.tmp-dir" $ ":" "RUN: at line 6" $ "C:/b/s/w/ir/k/src/third_party/llvm-build/Release+Asserts/./bin/clang.exe" "-fsanitize=address" "-mno-omit-leaf-frame-pointer" "-fno-omit-frame-pointer" "-fno-optimize-sibling-calls" "-gline-tables-only" "-gcodeview" "-gcolumn-info" "-shared-libasan" "-D_MT" "-D_DLL" "-Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames" "-fsanitize-coverage=func" "C:\b\s\w\ir\k\src\third_party\llvm\compiler-rt\test\asan\TestCases\coverage-disabled.cc" "-o" "C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Output\coverage-disabled.cc.tmp"

command output:

coverage-disabled-865ee1.o : error LNK2019: unresolved external symbol sanitizer_cov_trace_pc_guard referenced in function main coverage-disabled-865ee1.o : error LNK2019: unresolved external symbol sanitizer_cov_trace_pc_guard_init referenced in function sancov.module_ctor_trace_pc_guard C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts\projects\compiler-rt\test\asan\X86_64WindowsDynamicConfig\TestCases\Output\coverage-disabled.cc.tmp : fatal error LNK1120: 2 unresolved externals

command stderr:

clang: warning: argument '-fsanitize-coverage=[func|bb|edge]' is deprecated, use '-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]' instead [-Wdeprecated] clang: error: linker command failed with exit code 1120 (use -v to see invocation)

error: command failed with exit status: 1120

--


Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90.. Testing Time: 294.36s


Failing Tests (3): AddressSanitizer-x86_64-windows-dynamic :: TestCases/Windows/coverage-basic.cc AddressSanitizer-x86_64-windows-dynamic :: TestCases/Windows/coverage-dll-stdio.cc AddressSanitizer-x86_64-windows-dynamic :: TestCases/coverage-disabled.cc

Expected Passes : 42784 Expected Failures : 217 Unsupported Tests : 6874 Unexpected Failures: 3

CMake invocation: Running [u'C:\b\s\w\ir\k\src\third_party\depot_tools\win_toolchain\vs_files\818a152b3f1da991c1725d85be19a0f27af6bab4\win_sdk\bin\SetEnv.cmd', '/x64', '&&', 'cmake', '-GNinja', '-DCMAKE_BUILD_TYPE=Release', '-DLLVM_ENABLE_ASSERTIONS=OFF', '-DLLVM_ENABLE_PROJECTS=clang;compiler-rt;lld;chrometools', '-DLLVM_TARGETS_TO_BUILD=AArch64;ARM;Mips;PowerPC;SystemZ;WebAssembly;X86', '-DLLVM_ENABLE_PIC=OFF', '-DLLVM_ENABLE_UNWIND_TABLES=OFF', '-DLLVM_ENABLE_TERMINFO=OFF', '-DCLANG_PLUGIN_SUPPORT=OFF', '-DCLANG_ENABLE_STATIC_ANALYZER=OFF', '-DCLANG_ENABLE_ARCMT=OFF', '-DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON', '-DBUG_REPORT_URL=https://crbug.com and run tools/clang/scripts/upload_crash.py (only works inside Google) which will upload a report', '-DCOMPILER_RT_USE_LIBCXX=NO', '-DLLVM_USE_CRT_RELEASE=MT', '-DCMAKE_C_COMPILER=C:/b/s/w/ir/k/src/third_party/llvm-bootstrap-install/bin/clang-cl.exe', '-DCMAKE_CXX_COMPILER=C:/b/s/w/ir/k/src/third_party/llvm-bootstrap-install/bin/clang-cl.exe', '-DCMAKE_LINKER=C:/b/s/w/ir/k/src/third_party/llvm-bootstrap-install/bin/lld-link.exe', '-DCOMPILER_RT_BUILD_CRT=OFF', '-DCOMPILER_RT_BUILD_LIBFUZZER=ON', '-DCOMPILER_RT_BUILD_PROFILE=ON', '-DCOMPILER_RT_BUILD_SANITIZERS=ON', '-DCOMPILER_RT_BUILD_XRAY=OFF', '-DCOMPILER_RT_BUILD_BUILTINS=OFF', '-DLLVM_ENABLE_THREADS=OFF', '-DCMAKE_C_FLAGS=/Zi /GS-', '-DCMAKE_CXX_FLAGS=/Zi /GS-', '-DCMAKE_EXE_LINKER_FLAGS=/DEBUG /OPT:REF /OPT:ICF', '-DCMAKE_SHARED_LINKER_FLAGS=/DEBUG /OPT:REF /OPT:ICF', '-DCMAKE_MODULE_LINKER_FLAGS=/DEBUG /OPT:REF /OPT:ICF', '-DCMAKE_INSTALL_PREFIX=C:\b\s\w\ir\k\src\third_party\llvm-build\Release+Asserts', '-DCHROMIUM_TOOLS_SRC=C:\b\s\w\ir\k\src\tools\clang', '-DCHROMIUM_TOOLS=blink_gc_plugin;translation_unit;plugins', 'C:\b\s\w\ir\k\src\third_party\llvm\llvm']

This is from https://chromium-review.googlesource.com/c/chromium/src/+/1636672

nico commented 5 years ago

Nevermind comment 14. These lib files are import files written by the linker when it creates a dll.

nico commented 5 years ago

Does setting CMAKE_LINKER imply that we use lld-link /lib instead of lib.exe for static libraries? If not, lld-link isn't even creating the .lib file, right?

rnk commented 5 years ago

That became r362970.

There is an open question of why VC link.exe pulls in these objects when the archive is produced by link.exe instead of LLD, but I think we can leave that unanswered for now.

rnk commented 5 years ago

My comment there was the wrong way round. lld-link /wholearchive adds all .obj files from a .lib file but link.exe only adds .obj files that are referenced from the static library's symbol index (i.e. only .obj files with public symbols).

That's true, I kept debugging the problem, and I realized that the ASan tests actually do RUN: %clangxx_asan %s, and this doesn't pass -fuse-ld=lld, so they get VC link, and that's when I observed this behavior.

I'll add an otherwise unused external symbol to these object files with some comments and call it a day.

nico commented 5 years ago

My comment there was the wrong way round. lld-link /wholearchive adds all .obj files from a .lib file but link.exe only adds .obj files that are referenced from the static library's symbol index (i.e. only .obj files with public symbols).

rnk commented 5 years ago

Coincidentally, Nico ran into the relevant wholearchive behavior at the same time: llvm/llvm-bugzilla-archive#42180

rnk commented 5 years ago

That became r362849, but it still doesn't fix the bug. It looks like LLD doesn't handle -wholearchive: the way that MSVC does. LLD only seems to add object files that define symbols to the link, and we have an object (sanitizer_coverage_win_dynamic_runtime_thunk.cc) that defines no symbols and just contains .drective options.

rnk commented 5 years ago

I tried to come up with a proper fix that preserves our behavior and adds new tests: https://reviews.llvm.org/D62984

mstorsjo commented 5 years ago

I don't recall running into any project that needed/used that feature yet, so I don't mind if you change it, especially if it doesn't break any existing tests. (Although, it might have worked and relied on with the existing behaviour that isn't covered by tests.) All variants of exporting with various mangling, with different behaviour between msvc and mingw, is a huge mess. The cases I've worked on should at least have test cases (mostly in lld).

In case it does break any of my usecases, I have pretty frequent testing so it should be noticed soon.

nico commented 5 years ago

Looks like this code used to live in lld before it moved to llvm.

See e.g. https://reviews.llvm.org/rL297357 -- so it's covered by lld's tests. If those don't fail, then all's good I think.

(git blame 72fbd346c62f3c2bf30ffa99dd4ee55430ac995a lld/COFF/Librarian.cpp)

nico commented 5 years ago

Regressing functionality not covered by tests is fair game in my book :)

rnk commented 5 years ago

So, I've determined that the following patch fixes the bug, and it does so without breaking any tests:


diff --git a/llvm/lib/Object/COFFImportFile.cpp b/llvm/lib/Object/COFFImportFile.cpp index ff4a799be60..96c5427e936 100644 --- a/llvm/lib/Object/COFFImportFile.cpp +++ b/llvm/lib/Object/COFFImportFile.cpp @@ -106,26 +106,6 @@ static ImportNameType getNameType(StringRef Sym, StringRef ExtName, return IMPORT_NAME; }

-static Expected replace(StringRef S, StringRef From,

@@ -599,21 +579,16 @@ Error writeImportLibrary(StringRef ImportName, StringRef Path, ? IMPORT_ORDINAL : getNameType(SymbolName, E.Name, Machine, MinGW);


However, it regresses some functionality. Suppose we have -export:foo=bar on the command line, but bar is stdcall, so it is decorated as _bar@8, and the export of "foo" should really be an export of "_foo@8" once decorated. That's what this "replace" code above implements, but there are no tests for it. I've been trying to do some experiments to determine the correct behavior, but it's been difficult.

rnk commented 5 years ago

Here's a reduced example:

$ cat t.c

pragma comment(linker, "/alternatename:foo=foo_def")

pragma comment(linker, "/export:foo_dll=foo")

int foo_def() { return 42; }

$ cl -c t.c

$ lld-link -nodefaultlib -noentry -dll t.obj && llvm-nm t.lib ... t.dll: 00000000 T __imp_foo_dll_def 00000000 T foo_dll_def

$ link -nodefaultlib -noentry -dll t.obj && llvm-nm t.lib ... t.dll: 00000000 T __imp_foo_dll 00000000 T foo_dll

I wonder how we got to foo_dll_def, since that requires inventing a new string that isn't present in the source.

rnk commented 5 years ago

I started looking at this. I can reproduce it with check-asan-dynamic, but I don't understand it yet.

Marcos's implementation of weak symbols for COFF is very complicated and hard to understand. We had that conversation the other week about how they aren't well supported on COFF.

I suppose it'll be faster to directly compare the .libs.


I noticed that the clang_rt.asan_dynamic-x86-64.lib produced by MSVC has different symbols than one produced by LLD.

Specifically, I see this:

--- asan-dynamic-syms-lld.txt 2019-06-03 13:45:20.060940200 -0700 +++ asan-dynamic-syms-msvc.txt 2019-06-03 13:45:30.273437100 -0700 ... clang_rt.asan_dynamic-x86_64.dll: -00000000 T imp_sanitizer_cov_trace_pc_guarddlldef -00000000 T sanitizer_cov_trace_pc_guarddlldef +00000000 T _impsanitizer_cov_trace_pc_guarddll +00000000 T sanitizer_cov_trace_pc_guard__dll

But, we're supposed to export ${sym}dll, not ${sym}dll__def. This is supposed to be controlled by these /export:alias=aliasee directives in sanitizer_coverage_libcdep_new.cc, dumped here:

$ dumpbin -directives projects/compiler-rt/lib/sanitizer_common/CMakeFiles/RTSanitizerCommonCoverage.x86_64.dir/sanitizer_coverage_libcdep_new.cc.obj ... /alternatename:sanitizer_cov_trace_pc_guard=sanitizer_cov_trace_pc_guarddef /export:sanitizer_cov_trace_pc_guarddll=sanitizer_cov_trace_pc_guard

So, LLD seems to have a bug in its implementation of -export:foo=bar. Maybe I can make a small repro.

nico commented 5 years ago

I have to run for today. Will look tomorrow. +rnk in case it's obvious to him what's wrong.