[llvm] [compiler-rt] [sanitizer_common] Add experimental flag to tweak dlopen(<main program>) (PR #71715)
Thurston Dang via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 9 10:13:05 PST 2023
https://github.com/thurstond updated https://github.com/llvm/llvm-project/pull/71715
>From 2a73a5fba63e5dc769fb10166315f3c912bcf9fa Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Wed, 8 Nov 2023 17:50:29 +0000
Subject: [PATCH 1/4] [sanitizer_common] Add experimental flag to tweak
dlopen(<main program>)
This introduces an experimental flag 'test_only_replace_dlopen_main_program'.
When enabled, this will replace dlopen(<main program,...> with dlopen(NULL,...),
which is the correct way to get a handle to the main program.
This can be useful when ASan is statically linked, since dladdr((void*)pthread_join)
or similar will return the path to the main program.
Note that dlopen(<main program>,...) never ends well:
- PIE in recent glibc versions (glibc bugzilla 24323), or non-PIE: return an error
- PIE in current GRTE and older glibc: attempt to load the main program
again, leading to reinitializing ASan and failing to remap the shadow
memory.
---
.../sanitizer_common_interceptors.inc | 30 ++++++++++++++++++-
.../lib/sanitizer_common/sanitizer_flags.inc | 6 ++++
2 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 80efaf54a0607f6..0f7d9da9d148443 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -6304,10 +6304,38 @@ INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) {
#endif
#if SANITIZER_INTERCEPT_DLOPEN_DLCLOSE
+// Returns 1 if key is a suffix of str, 0 otherwise
+static int internal_strcmp_suffix(const char *key, const char *str) {
+ if (!key || !str)
+ return 0;
+
+ if (internal_strlen(key) > internal_strlen(str))
+ return 0;
+
+ return !internal_strcmp(str + internal_strlen(str) - internal_strlen(key),
+ key);
+}
+
+# if SANITIZER_GLIBC
+extern char *__progname;
+# endif
+
INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
void *ctx;
COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlopen, filename, flag);
- if (filename) COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0);
+
+ if (filename) {
+# if SANITIZER_GLIBC
+ if (common_flags()->test_only_replace_dlopen_main_program &&
+ internal_strcmp_suffix(__progname, filename)) {
+ VPrintf(1, "dlopen interceptor: replacing %s because it matches %s\n",
+ filename, __progname);
+ filename = (char *)0; // RTLD_DEFAULT
+ }
+# endif
+ COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0);
+ }
+
void *res = COMMON_INTERCEPTOR_DLOPEN(filename, flag);
Symbolizer::GetOrInit()->InvalidateModuleList();
COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res);
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
index 6148ae56067cae0..949bdbd148b6b89 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
@@ -269,3 +269,9 @@ COMMON_FLAG(bool, detect_write_exec, false,
COMMON_FLAG(bool, test_only_emulate_no_memorymap, false,
"TEST ONLY fail to read memory mappings to emulate sanitized "
"\"init\"")
+// With static linking, dladdr((void*)pthread_join) or similar will return the
+// path to the main program. This flag will replace dlopen(<main program,...>
+// with dlopen(NULL,...), which is the correct way to get a handle to the main
+// program.
+COMMON_FLAG(bool, test_only_replace_dlopen_main_program, false,
+ "TEST ONLY replace dlopen(<main program>,...) with dlopen(NULL)")
>From da65373205833bfd82cd88adf0ed8f796f037d70 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Wed, 8 Nov 2023 18:29:32 +0000
Subject: [PATCH 2/4] Check validity of filename string before reading
---
.../lib/sanitizer_common/sanitizer_common_interceptors.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 0f7d9da9d148443..02167ad4c1c88e6 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -6325,6 +6325,7 @@ INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlopen, filename, flag);
if (filename) {
+ COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0);
# if SANITIZER_GLIBC
if (common_flags()->test_only_replace_dlopen_main_program &&
internal_strcmp_suffix(__progname, filename)) {
@@ -6333,7 +6334,6 @@ INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
filename = (char *)0; // RTLD_DEFAULT
}
# endif
- COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0);
}
void *res = COMMON_INTERCEPTOR_DLOPEN(filename, flag);
>From c798bf13d30f1d6c03b367461eef97c3968b2d90 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Wed, 8 Nov 2023 19:11:50 +0000
Subject: [PATCH 3/4] internal_is_suffix fixes per Kirill's suggestion Added
test case per Vitaly's suggestion
---
.../sanitizer_common_interceptors.inc | 14 ++++-----
.../replace_dlopen_main_program_test.cpp | 29 +++++++++++++++++++
2 files changed, 36 insertions(+), 7 deletions(-)
create mode 100644 compiler-rt/test/sanitizer_common/TestCases/replace_dlopen_main_program_test.cpp
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 02167ad4c1c88e6..f9952a729541a3c 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -6304,16 +6304,16 @@ INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) {
#endif
#if SANITIZER_INTERCEPT_DLOPEN_DLCLOSE
-// Returns 1 if key is a suffix of str, 0 otherwise
-static int internal_strcmp_suffix(const char *key, const char *str) {
- if (!key || !str)
+// Returns 1 if 'suffix' matches the end of 'str', 0 otherwise
+static int internal_is_suffix(const char *suffix, const char *str) {
+ if (!suffix || !str)
return 0;
- if (internal_strlen(key) > internal_strlen(str))
+ if (internal_strlen(suffix) > internal_strlen(str))
return 0;
- return !internal_strcmp(str + internal_strlen(str) - internal_strlen(key),
- key);
+ return internal_strcmp(str + internal_strlen(str) - internal_strlen(suffix),
+ suffix) == 0;
}
# if SANITIZER_GLIBC
@@ -6328,7 +6328,7 @@ INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0);
# if SANITIZER_GLIBC
if (common_flags()->test_only_replace_dlopen_main_program &&
- internal_strcmp_suffix(__progname, filename)) {
+ internal_is_suffix(__progname, filename)) {
VPrintf(1, "dlopen interceptor: replacing %s because it matches %s\n",
filename, __progname);
filename = (char *)0; // RTLD_DEFAULT
diff --git a/compiler-rt/test/sanitizer_common/TestCases/replace_dlopen_main_program_test.cpp b/compiler-rt/test/sanitizer_common/TestCases/replace_dlopen_main_program_test.cpp
new file mode 100644
index 000000000000000..7e9e45836efbe53
--- /dev/null
+++ b/compiler-rt/test/sanitizer_common/TestCases/replace_dlopen_main_program_test.cpp
@@ -0,0 +1,29 @@
+// Test 'test_only_replace_dlopen_main_program' flag
+
+// RUN: %clangxx %s -o %t
+// RUN: env %tool_options='test_only_replace_dlopen_main_program=true' %run %t
+// RUN: env %tool_options='test_only_replace_dlopen_main_program=false' not %run %t
+// REQUIRES: glibc
+
+// Does not intercept dlopen
+// UNSUPPORTED: hwasan, lsan, ubsan
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[]) {
+ // "If filename is NULL, then the returned handle is for the main program."
+ void *correct_handle = dlopen(NULL, RTLD_LAZY);
+
+ // Check that this is equivalent to dlopen(NULL, ...)
+ void *handle = dlopen(argv[0], RTLD_LAZY);
+ printf("dlopen(NULL,...): %p\n", correct_handle);
+ printf("dlopen(<main program>,...): %p\n", handle);
+ fflush(stdout);
+
+ if (handle != correct_handle)
+ return 1;
+
+ return 0;
+}
>From 17be36de8a6a4418fc231a77e2e1c254af5b9bcc Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Thu, 9 Nov 2023 18:06:21 +0000
Subject: [PATCH 4/4] Use dladdr to obtain the name of the main program, and
then compare the canonicalized path against the canonicalized dlopen
parameter.
Also updated test
---
.../lib/sanitizer_common/CMakeLists.txt | 2 +
.../sanitizer_common_interceptors.inc | 70 ++++++++++++++-----
.../lib/sanitizer_common/sanitizer_dl.cpp | 35 ++++++++++
.../lib/sanitizer_common/sanitizer_dl.h | 26 +++++++
.../replace_dlopen_main_program_test.cpp | 59 ++++++++++++++++
.../replace_dlopen_main_program_test.cpp | 29 --------
.../compiler-rt/lib/sanitizer_common/BUILD.gn | 2 +
7 files changed, 175 insertions(+), 48 deletions(-)
create mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp
create mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_dl.h
create mode 100644 compiler-rt/test/sanitizer_common/TestCases/Linux/replace_dlopen_main_program_test.cpp
delete mode 100644 compiler-rt/test/sanitizer_common/TestCases/replace_dlopen_main_program_test.cpp
diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
index 25304b71c0c7061..ce6d4cf80919b25 100644
--- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt
+++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
@@ -59,6 +59,7 @@ set(SANITIZER_NOLIBC_SOURCES
set(SANITIZER_LIBCDEP_SOURCES
sanitizer_common_libcdep.cpp
sanitizer_allocator_checks.cpp
+ sanitizer_dl.cpp
sanitizer_linux_libcdep.cpp
sanitizer_mac_libcdep.cpp
sanitizer_posix_libcdep.cpp
@@ -139,6 +140,7 @@ set(SANITIZER_IMPL_HEADERS
sanitizer_deadlock_detector_interface.h
sanitizer_dense_map.h
sanitizer_dense_map_info.h
+ sanitizer_dl.h
sanitizer_errno.h
sanitizer_errno_codes.h
sanitizer_file.h
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
index f9952a729541a3c..a15da932e6052c0 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -33,16 +33,17 @@
// COMMON_INTERCEPTOR_STRERROR
//===----------------------------------------------------------------------===//
+#include <stdarg.h>
+
#include "interception/interception.h"
#include "sanitizer_addrhashmap.h"
+#include "sanitizer_dl.h"
#include "sanitizer_errno.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_platform_interceptors.h"
#include "sanitizer_symbolizer.h"
#include "sanitizer_tls_get_addr.h"
-#include <stdarg.h>
-
#if SANITIZER_INTERCEPTOR_HOOKS
#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) f(__VA_ARGS__);
#define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \
@@ -6304,21 +6305,24 @@ INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) {
#endif
#if SANITIZER_INTERCEPT_DLOPEN_DLCLOSE
-// Returns 1 if 'suffix' matches the end of 'str', 0 otherwise
-static int internal_is_suffix(const char *suffix, const char *str) {
- if (!suffix || !str)
- return 0;
+// Ordinary internal_readlink does not null-terminate strings.
+static int internal_readlink_with_null(const char *path, char *buf,
+ uptr bufsize) {
+ if (!buf) {
+ return -1;
+ }
- if (internal_strlen(suffix) > internal_strlen(str))
- return 0;
+ // Ensure it is a valid string even if internal_readlink fails
+ buf[0] = '\0';
- return internal_strcmp(str + internal_strlen(str) - internal_strlen(suffix),
- suffix) == 0;
-}
+ int len = internal_readlink(path, buf, bufsize);
+ if (len >= 0 && len < (int)bufsize)
+ buf[len] = '\0';
-# if SANITIZER_GLIBC
-extern char *__progname;
-# endif
+ buf[bufsize - 1] = '\0';
+
+ return len;
+}
INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
void *ctx;
@@ -6326,14 +6330,42 @@ INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
if (filename) {
COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0);
-# if SANITIZER_GLIBC
- if (common_flags()->test_only_replace_dlopen_main_program &&
- internal_is_suffix(__progname, filename)) {
+
+# if !SANITIZER_DYNAMIC
+ VPrintf(1, "dlopen interceptor: filename: %s\n", filename);
+
+ char *filename_canonical = (char *)InternalAlloc(sizeof(char) * 640);
+ if (filename_canonical)
+ internal_readlink_with_null(filename, filename_canonical, 640);
+ VPrintf(1, "dlopen interceptor: filename (canonical): %s\n",
+ filename_canonical);
+
+ // We care about dlopen(<main program>,...), which will only happen
+ // for statically linked ASan.
+ const char *self_fname;
+ int ret = dladdr_self_fname(&self_fname);
+ VPrintf(1, "dlopen interceptor: dladdr_self_fname: %p %s\n",
+ (void *)self_fname, self_fname);
+
+ char *self_fname_canonical = (char *)InternalAlloc(sizeof(char) * 640);
+ if (self_fname_canonical)
+ internal_readlink_with_null(self_fname, self_fname_canonical, 640);
+ VPrintf(1, "dlopen interceptor: dladdr_self_fname (canonical): %s\n",
+ self_fname_canonical);
+
+ if (ret && common_flags()->test_only_replace_dlopen_main_program &&
+ (internal_strcmp(self_fname_canonical, filename_canonical) == 0)) {
+ // Our test (replace_dlopen_main_program_test.cpp) does not obtain the
+ // path name from dladdr(). We therefore need to compare string contents,
+ // not just the filename addresses.
VPrintf(1, "dlopen interceptor: replacing %s because it matches %s\n",
- filename, __progname);
+ filename, self_fname);
filename = (char *)0; // RTLD_DEFAULT
}
-# endif
+
+ InternalFree(filename_canonical);
+ InternalFree(self_fname_canonical);
+# endif // !SANITIZER_DYNAMIC
}
void *res = COMMON_INTERCEPTOR_DLOPEN(filename, flag);
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp
new file mode 100644
index 000000000000000..978714358301035
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp
@@ -0,0 +1,35 @@
+//===-- sanitizer_dl.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file has helper functions that depend on libc's dynamic loading
+// introspection.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_dl.h"
+
+#include <dlfcn.h>
+
+#include "sanitizer_common/sanitizer_platform.h"
+
+namespace __sanitizer {
+extern const char *SanitizerToolName;
+
+int dladdr_self_fname(const char **fname) {
+#if SANITIZER_GLIBC
+ Dl_info info;
+ int ret = dladdr((void *)&SanitizerToolName, &info);
+ *fname = info.dli_fname;
+ return ret;
+#else
+ *fname = nullptr;
+ return 0;
+#endif
+}
+
+} // namespace __sanitizer
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_dl.h b/compiler-rt/lib/sanitizer_common/sanitizer_dl.h
new file mode 100644
index 000000000000000..8e375064267de8e
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_dl.h
@@ -0,0 +1,26 @@
+//===-- sanitizer_dl.h ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file has helper functions that depend on libc's dynamic loading
+// introspection.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_DL_H
+#define SANITIZER_DL_H
+
+namespace __sanitizer {
+
+// Returns the path to the shared object or - in the case of statically linked
+// sanitizers
+// - the main program itself, that contains the sanitizer.
+int dladdr_self_fname(const char **fname);
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_DL_H
diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/replace_dlopen_main_program_test.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/replace_dlopen_main_program_test.cpp
new file mode 100644
index 000000000000000..5750ad7f345c58f
--- /dev/null
+++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/replace_dlopen_main_program_test.cpp
@@ -0,0 +1,59 @@
+// Test 'test_only_replace_dlopen_main_program' flag
+
+// RUN: %clangxx %s -pie -fPIE -o %t
+// RUN: env %tool_options='test_only_replace_dlopen_main_program=true' %run %t
+// RUN: env %tool_options='test_only_replace_dlopen_main_program=false' not %run %t
+
+// dladdr is 'nonstandard GNU extensions that are also present on Solaris'
+// REQUIRES: glibc
+
+// Does not intercept dlopen
+// UNSUPPORTED: hwasan, lsan, ubsan
+
+// Flag has no effect with dynamic runtime
+// UNSUPPORTED: asan-dynamic-runtime
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// We can't use the address of 'main' (error: ISO C++ does not allow 'main' to be used by a program [-Werror,-Wmain]')
+// so we add this function.
+__attribute__((noinline, no_sanitize("address"))) void foo() {
+ printf("Hello World!\n");
+}
+
+int main(int argc, char *argv[]) {
+ foo();
+
+ // "If filename is NULL, then the returned handle is for the main program."
+ void *correct_handle = dlopen(NULL, RTLD_LAZY);
+ printf("dlopen(NULL,...): %p\n", correct_handle);
+
+ Dl_info info;
+ if (dladdr((void *)&foo, &info) == 0) {
+ printf("dladdr failed\n");
+ return 1;
+ }
+ printf("dladdr(&foo): %s\n", info.dli_fname);
+ void *test_handle = dlopen(info.dli_fname, RTLD_LAZY);
+ printf("dlopen(%s,...): %p\n", info.dli_fname, test_handle);
+
+ if (test_handle != correct_handle) {
+ printf("Error: handles do not match\n");
+ return 1;
+ }
+
+ // Check that this is equivalent to dlopen(NULL, ...)
+ test_handle = dlopen(argv[0], RTLD_LAZY);
+ printf("argv[0]: %s\n", argv[0]);
+ printf("dlopen(%s,...): %p\n", argv[0], test_handle);
+ fflush(stdout);
+
+ if (test_handle != correct_handle) {
+ printf("Error: handles do not match\n");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/compiler-rt/test/sanitizer_common/TestCases/replace_dlopen_main_program_test.cpp b/compiler-rt/test/sanitizer_common/TestCases/replace_dlopen_main_program_test.cpp
deleted file mode 100644
index 7e9e45836efbe53..000000000000000
--- a/compiler-rt/test/sanitizer_common/TestCases/replace_dlopen_main_program_test.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-// Test 'test_only_replace_dlopen_main_program' flag
-
-// RUN: %clangxx %s -o %t
-// RUN: env %tool_options='test_only_replace_dlopen_main_program=true' %run %t
-// RUN: env %tool_options='test_only_replace_dlopen_main_program=false' not %run %t
-// REQUIRES: glibc
-
-// Does not intercept dlopen
-// UNSUPPORTED: hwasan, lsan, ubsan
-
-#include <dlfcn.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char *argv[]) {
- // "If filename is NULL, then the returned handle is for the main program."
- void *correct_handle = dlopen(NULL, RTLD_LAZY);
-
- // Check that this is equivalent to dlopen(NULL, ...)
- void *handle = dlopen(argv[0], RTLD_LAZY);
- printf("dlopen(NULL,...): %p\n", correct_handle);
- printf("dlopen(<main program>,...): %p\n", handle);
- fflush(stdout);
-
- if (handle != correct_handle)
- return 1;
-
- return 0;
-}
diff --git a/llvm/utils/gn/secondary/compiler-rt/lib/sanitizer_common/BUILD.gn b/llvm/utils/gn/secondary/compiler-rt/lib/sanitizer_common/BUILD.gn
index d6f18aec9f2113f..5a4a6f17cf311a6 100644
--- a/llvm/utils/gn/secondary/compiler-rt/lib/sanitizer_common/BUILD.gn
+++ b/llvm/utils/gn/secondary/compiler-rt/lib/sanitizer_common/BUILD.gn
@@ -54,6 +54,8 @@ source_set("sources") {
"sanitizer_deadlock_detector_interface.h",
"sanitizer_dense_map.h",
"sanitizer_dense_map_info.h",
+ "sanitizer_dl.cpp",
+ "sanitizer_dl.h",
"sanitizer_errno.cpp",
"sanitizer_errno.h",
"sanitizer_errno_codes.h",
More information about the llvm-commits
mailing list