Skip to content

Instantly share code, notes, and snippets.

@pervognsen
Last active June 21, 2023 16:57
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save pervognsen/6b3c7f02c6e7db4b776bf92e0bb09d1b to your computer and use it in GitHub Desktop.
Save pervognsen/6b3c7f02c6e7db4b776bf92e0bb09d1b to your computer and use it in GitHub Desktop.

I was told by @mmozeiko that Address Sanitizer (ASAN) works on Windows now. I'd tried it a few years ago with no luck, so this was exciting news to hear.

It was a pretty smooth experience, but with a few gotchas I wanted to document.

First, download and run the LLVM installer for Windows: https://llvm.org/builds/

Then download and install the VS extension if you're a Visual Studio 2017 user like I am.

It's now very easy to use Clang to build your existing MSVC projects since there's a cl compatible frontend:

To use the LLVM toolchain from Visual Studio after running the installer above, install the LLVM Compiler Toolchain Visual Studio extension (supports Visual Studio 2017 and later), select a project in Solution Explorer, open its Property Page (Alt+F7 by default), and in the "General" section of "Configuration Properties" change "Platform Toolset" to "llvm". Alternatively, invoke MSBuild with /p:PlatformToolset=llvm to try out the toolchain without modifying the project files.

You're probably going to run into some cl settings that it doesn't accept but you can easily change those. Then it's probably going to swamp you in Clang/GCC specific warnings, so you'll want to disable or clean those up.

Now you're ready to actually compile and run ASAN against your code. This is a little more awkward using the VS flow. Most pages recommend compiling and linking with clang in a single invocation with the -fsanitize=address command line flag. However, the VS flow insists on using lld-link to separately link, and this does not take an -fsanitize=address option. Hence you have to do the following:

  • Add -fsanitize=address under Additional Compiler Options in the LLVM page of your VS project properties.
  • Add the path C:\Program Files\LLVM\lib\clang\9.0.0\lib\windows\clang_rt.asan-x86_64.lib to your linked libraries.

When you first compile with -fsanitize=address you're probably going to get complaints about compiler/linker settings you weren't getting complaints about previously. E.g. you can't use /debug:fastlink or the debug CRT and a few other things. Just fix those as recommended: use /debug:full and use a non-debug CRT.

OK, moment of truth. You launch the ASAN-compiled program from the VS debugger... and it crashes deep in a memset during initialization for some low-level custom allocator code in AsanInitInternal. However, @mmozeiko points out the issue is that ASAN wants to catch Win32 memory access violations, so the debugger can't be intercepting it. You can disable break-on-exception for memory access violations (0xC0000005) under Debug -> Windows -> Exception Settings. Once you do this, you can launch ASAN-compiled programs from the debugger and everything is fine. However, during normal debugging workflow it's essential to have break-on-exception enabled for memory access violations, so you'll have to remember to toggle this on and off when switching between ASAN and non-ASAN debugging.

Since debug settings are saved to the per-solution .vcxproj.user file, it might make sense to write a simple script that launches devenv with a copy of an existing solution with that break-on-exception setting disabled, and with the changes for -fsanitize=address and linking against the ASAN runtime library applied to the project settings. That is, write a generic devenv-asan script that when launched in a directory makes all the requisite setting changes to a temp copy of the solution-related files in that directory and then launches devenv.exe with it.

The Windows and VS integration for Clang and ASAN is already a pretty smooth experience compared to just a year or two ago. If they removed the above mentioned pain points in the VS integration, it would be damn near perfect. You should be able to just right-click a project in the solution explorer and select 'Compile and run with Address Sanitizer' so that you don't have to mess around with the runtime library path or make temporary stateful changes to the project settings and debug settings.

@JustAndreww
Copy link

JustAndreww commented Feb 19, 2019

Great article, thanks! :)

What should I do to get rid of the following errors:

Error		duplicate symbol: calloc in clang_rt.asan-x86_64.lib(asan_malloc_win.cc.obj) and in api-ms-win-crt-heap-l1-1-0.dll
Error		duplicate symbol: free in clang_rt.asan-x86_64.lib(asan_malloc_win.cc.obj) and in api-ms-win-crt-heap-l1-1-0.dll
Error		duplicate symbol: malloc in clang_rt.asan-x86_64.lib(asan_malloc_win.cc.obj) and in api-ms-win-crt-heap-l1-1-0.dll
Error		duplicate symbol: realloc in clang_rt.asan-x86_64.lib(asan_malloc_win.cc.obj) and in api-ms-win-crt-heap-l1-1-0.dll

Initially my library was compiled with /MDd flag set, but apparently asan is not working with that flag set. I've tried to change it to /MD, but now I get duplicate symbol (or it's not related)?

@pervognsen
Copy link
Author

pervognsen commented Feb 19, 2019

I got it to work with /MT, could you try that? I think you have to link against a different asan-rt library if you use the DLL CRT, and I didn't try that. If you figure out which one/what to do, write it here and I can incorporate it into the article.

@JustAndreww
Copy link

JustAndreww commented Feb 19, 2019

Yep, just tried to use /MT and got the same errors.

Here is the additional dependencies from Linker -> Input:

axtls.lib;
kernel32.lib;
user32.lib;
gdi32.lib;
comdlg32.lib;
shlwapi.lib;
C:\Program Files\LLVM\lib\clang\9.0.0\lib\windows\clang_rt.asan-x86_64.lib;
%(AdditionalDependencies)

Ignores:

libc.lib;
libcmt.lib;
libcd.lib;
libcmtd.lib;
msvcrt.lib;
%(IgnoreSpecificDefaultLibraries)

So right now I still can't find a solution to this. I feels like something stupid though...

When linking with clang_rt.asan_dynamic-x86_64.lib:

Error		duplicate symbol: "void * __cdecl operator new(unsigned __int64)" (??2@YAPEAX_K@Z) in ..\..\junk\Debug\Memory.obj and in clang_rt.asan_dynamic-x86_64.dll
Error		duplicate symbol: "void __cdecl operator delete(void *)" (??3@YAXPEAX@Z) in ..\..\junk\Debug\Memory.obj and in clang_rt.asan_dynamic-x86_64.dll
Error		duplicate symbol: "void * __cdecl operator new[](unsigned __int64)" (??_U@YAPEAX_K@Z) in ..\..\junk\Debug\Memory.obj and in clang_rt.asan_dynamic-x86_64.dll
Error		duplicate symbol: "void __cdecl operator delete[](void *)" (??_V@YAXPEAX@Z) in ..\..\junk\Debug\Memory.obj and in clang_rt.asan_dynamic-x86_64.dll

@nathankidd
Copy link

https://stackoverflow.com/a/27195090/176800 might help to check what crt types are getting pulled in. Or just run procmon.

@tim-rex
Copy link

tim-rex commented Apr 1, 2019

Similar deal for me, I'm unable to link against a DLL due to duplicate symbols for _expand, _msize, free, malloc, realloc
@rbt2008 i don't suppose you found a workaround?

[EDIT]
I found this which pointed the way...
http://clang-developers.42468.n3.nabble.com/AddressSanitizer-with-MSVC-linker-errors-td4034603.html

Link the DLL against clang_rt.asan-x86-64.lib
And similarly ensure /MT instead of /MD

That gets me a build that links ok, but then fails with this issue:
http://clang-developers.42468.n3.nabble.com/Using-the-AddressSanitizer-under-Windows-td4063720.html

Seems to me that ASAN against DLL's on Windows just isn't quite there yet (that's my way of saying, I'm out of my depth)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment