Skip to content

DLL load order of ASan causes false reports on realloc calls during DLL initialization #61685

@alvinhochun

Description

@alvinhochun

Short version: If the program tries to realloc a block of memory that had been malloc-ed before the ASan runtime was initialized, ASan reports an error for "attempting free on address which was not malloc()-ed". Making ASan load earlier can fix this.

Long version:

When building an EXE with ASan enabled, even if it depends on other user library DLLs which have not been rebuilt with ASan, it should still work fine because ASan intercepts allocation functions to capture allocations across all DLLs. However, ASan misses any allocations made before libclang_rt.asan_dynamic-x86_64.dll is loaded.

https://reviews.llvm.org/D25946 implemented a change to ignore such allocations made by ucrt when deallocating. In practice, this also ignores any allocations made by other user DLLs. This generally includes C++ dynamic initialization (e.g. global static variables). (This slightly reduces ASan coverage, but at least the program still runs and ASan is able to instrument the rest of the program, which to me is acceptable.) However, this only happens for Deallocate; Reallocate does not contain the same checks. If an uninstrumented DLL allocates a pointer during initialization and this pointer is later reallocated, ASan will report "attempting free on address which was not malloc()-ed".

Reproducer

asan_load_test.zip

I tested this with llvm-mingw-20230320-ucrt-x86_64 from https://github.com/mstorsjo/llvm-mingw/releases/tag/20230320 .

To build it, change Makefile to point CXX to clang++, then run mingw32-make to build. Set ASAN_OPTIONS=verbosity=1 (optional) and run main.exe to test.

Proposed Fix 1: Reordering link flags from the Clang driver**

I realized that it is possible to influence the Windows library loader to load the ASan DLL earlier than most other user DLLs, by making it the first entry in the Import Directory Table, earlier than other DLLs. When linking with LLD, the order in which the import libraries are specified affects how the Import Directory Table is arranged. This can be verified with the reproducer with these steps:

  1. Run the command to build main.exe manually with --verbose
  2. Run the printed build command manually
  3. Edit the link command (ld.lld) to move libclang_rt.asan_dynamic-x86_64.dll.a before other input files, then run it manually
  4. Run llvm-readobj --coff-imports main.exe to verify that the ASan dll is listed first
  5. Run main.exe should no longer trigger an ASan report.

For the MinGW Clang driver, these link flags are added in:

if (Sanitize.needsAsanRt()) {
// MinGW always links against a shared MSVCRT.
CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dynamic",
ToolChain::FT_Shared));
CmdArgs.push_back(
TC.getCompilerRTArgString(Args, "asan_dynamic_runtime_thunk"));
CmdArgs.push_back("--require-defined");
CmdArgs.push_back(TC.getArch() == llvm::Triple::x86
? "___asan_seh_interceptor"
: "__asan_seh_interceptor");
// Make sure the linker consider all object files from the dynamic
// runtime thunk.
CmdArgs.push_back("--whole-archive");
CmdArgs.push_back(
TC.getCompilerRTArgString(Args, "asan_dynamic_runtime_thunk"));
CmdArgs.push_back("--no-whole-archive");
}

I presume the solution is as simple as moving this block of code further up. (MSVC might also need the same fix, but I haven't checked.)

Downside: This only works when linking through Clang. If LLD is invoked directly, the user needs to be aware of the ordering of the ASan link flags.

Proposed Fix 2: Teach LLD to always put the ASan DLL in first**

This fixes the issue for both linking through Clang or by the user invoking LLD directly. However, this introduces a special case so I don't really think this is a good idea.

Proposed Fix 3: Teach ASan Reallocate to not report on uninstrumented allocations**

We can probably apply the same thing in https://reviews.llvm.org/D25946 to Reallocate and not bother with trying to change the DLL load order. However, this reduces ASan coverage so I think this should be avoided if possible.


cc @mstorsjo

Metadata

Metadata

Assignees

Labels

bugIndicates an unexpected problem or unintended behaviorclang:driver'clang' and 'clang++' user-facing binaries. Not 'clang-cl'compiler-rt:asanAddress sanitizerplatform:windows

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions