Index: lib/asan/asan_allocator.cc =================================================================== --- lib/asan/asan_allocator.cc +++ lib/asan/asan_allocator.cc @@ -554,7 +554,17 @@ uptr chunk_beg = p - kChunkHeaderSize; AsanChunk *m = reinterpret_cast(chunk_beg); + // On Windows, uninstrumented DLLs may allocate memory before ASan hooks + // malloc. Don't report an invalid free in this case. + if (SANITIZER_WINDOWS && + !get_allocator().PointerIsMine(ptr)) { + if (!IsSystemHeapAddress(p)) + ReportFreeNotMalloced(p, stack); + return; + } + ASAN_FREE_HOOK(ptr); + // Must mark the chunk as quarantined before any changes to its metadata. // Do not quarantine given chunk if we failed to set CHUNK_QUARANTINE flag. if (!AtomicallySetQuarantineFlagIfAllocated(m, ptr, stack)) return; Index: lib/asan/asan_internal.h =================================================================== --- lib/asan/asan_internal.h +++ lib/asan/asan_internal.h @@ -64,6 +64,9 @@ // asan_win.cc void InitializePlatformExceptionHandlers(); +// Returns whether an address is a valid allocated system heap block. +// 'addr' must point to the beginning of the block. +bool IsSystemHeapAddress(uptr addr); // asan_rtl.cc void NORETURN ShowStatsAndAbort(); Index: lib/asan/asan_linux.cc =================================================================== --- lib/asan/asan_linux.cc +++ lib/asan/asan_linux.cc @@ -70,6 +70,7 @@ void InitializePlatformInterceptors() {} void InitializePlatformExceptionHandlers() {} +bool IsSystemHeapAddress (uptr addr) { return false; } void *AsanDoesNotSupportStaticLinkage() { // This will fail to link with -static. Index: lib/asan/asan_mac.cc =================================================================== --- lib/asan/asan_mac.cc +++ lib/asan/asan_mac.cc @@ -48,6 +48,7 @@ void InitializePlatformInterceptors() {} void InitializePlatformExceptionHandlers() {} +bool IsSystemHeapAddress (uptr addr) { return false; } // No-op. Mac does not support static linkage anyway. void *AsanDoesNotSupportStaticLinkage() { Index: lib/asan/asan_win.cc =================================================================== --- lib/asan/asan_win.cc +++ lib/asan/asan_win.cc @@ -277,6 +277,10 @@ #endif } +bool IsSystemHeapAddress(uptr addr) { + return ::HeapValidate(GetProcessHeap(), 0, (void*)addr) != FALSE; +} + // We want to install our own exception handler (EH) to print helpful reports // on access violations and whatnot. Unfortunately, the CRT initializers assume // they are run before any user code and drop any previously-installed EHs on Index: test/asan/TestCases/Windows/dll_heap_allocation.cc =================================================================== --- /dev/null +++ test/asan/TestCases/Windows/dll_heap_allocation.cc @@ -0,0 +1,30 @@ + +// RUN: %clang_cl -LD %s -Fe%t.dll -DHEAP_LIBRARY -MD +// RUN: %clang_cl %s %t.lib -Fe%t -fsanitize=address -MT +// RUN: %run %t 2>&1 | FileCheck %s + +// Check that ASan does not fail when releasing allocations that occurred within +// an uninstrumented DLL. + +#ifdef HEAP_LIBRARY +#include +#include + +std::unique_ptr __declspec(dllexport) myglobal(new int(42)); +BOOL WINAPI DllMain(PVOID h, DWORD reason, PVOID reserved) { + return TRUE; +} + +#else + +#include +extern std::unique_ptr __declspec(dllimport) myglobal; +int main(int argc, char **argv) { + printf("myglobal: %d\n", *myglobal); + return 0; +} + +#endif + +// CHECK: myglobal: 42 +// CHECK-NOT: ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed Index: test/asan/lit.cfg =================================================================== --- test/asan/lit.cfg +++ test/asan/lit.cfg @@ -132,16 +132,22 @@ # Windows-specific tests might also use the clang-cl.exe driver. if platform.system() == 'Windows': - clang_cl_asan_cxxflags = ["-fsanitize=address", - "-Wno-deprecated-declarations", - "-WX", - "-D_HAS_EXCEPTIONS=0", - "-Zi"] + target_cflags + clang_cl_cxxflags = ["-Wno-deprecated-declarations", + "-WX", + "-D_HAS_EXCEPTIONS=0", + "-Zi"] + target_cflags + clang_cl_asan_cxxflags = ["-fsanitize=address"] + clang_cl_cxxflags if config.asan_dynamic: clang_cl_asan_cxxflags.append("-MD") - clang_invocation = build_invocation(clang_cl_asan_cxxflags) - clang_cl_invocation = clang_invocation.replace("clang.exe","clang-cl.exe") - config.substitutions.append( ("%clang_cl_asan ", clang_cl_invocation) ) + + clang_cl_invocation = build_invocation(clang_cl_cxxflags) + clang_cl_invocation = clang_cl_invocation.replace("clang.exe","clang-cl.exe") + config.substitutions.append( ("%clang_cl ", clang_cl_invocation) ) + + clang_cl_asan_invocation = build_invocation(clang_cl_asan_cxxflags) + clang_cl_asan_invocation = clang_cl_asan_invocation.replace("clang.exe","clang-cl.exe") + config.substitutions.append( ("%clang_cl_asan ", clang_cl_asan_invocation) ) + base_lib = os.path.join(config.compiler_rt_libdir, "clang_rt.asan%%s-%s.lib" % config.target_arch) config.substitutions.append( ("%asan_lib", base_lib % "") ) config.substitutions.append( ("%asan_cxx_lib", base_lib % "_cxx") )