aboutsummaryrefslogtreecommitdiff
path: root/lib/sanitizer_common
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-07-13 19:25:48 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-07-13 19:25:48 +0000
commit1992b790c2c12b7850bdf86662b67302052ec2fe (patch)
tree623c69b5fbf527bba17ecb9431ae5189871cecd4 /lib/sanitizer_common
parent50aa32eff79f252ab05a0c0a589cf2ca37cd9923 (diff)
downloadsrc-1992b790c2c12b7850bdf86662b67302052ec2fe.tar.gz
src-1992b790c2c12b7850bdf86662b67302052ec2fe.zip
Vendor import of compiler-rt trunk r307894:vendor/compiler-rt/compiler-rt-trunk-r307894
Notes
Notes: svn path=/vendor/compiler-rt/dist/; revision=320961 svn path=/vendor/compiler-rt/compiler-rt-trunk-r307894/; revision=320962; tag=vendor/compiler-rt/compiler-rt-trunk-r307894
Diffstat (limited to 'lib/sanitizer_common')
-rw-r--r--lib/sanitizer_common/CMakeLists.txt4
-rw-r--r--lib/sanitizer_common/sanitizer_common.h3
-rw-r--r--lib/sanitizer_common/sanitizer_common_interceptors.inc1
-rw-r--r--lib/sanitizer_common/sanitizer_errno.cc35
-rw-r--r--lib/sanitizer_common/sanitizer_errno.h35
-rw-r--r--lib/sanitizer_common/sanitizer_errno_codes.h34
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc79
-rw-r--r--lib/sanitizer_common/sanitizer_linux_libcdep.cc19
-rw-r--r--lib/sanitizer_common/sanitizer_mac.cc58
-rw-r--r--lib/sanitizer_common/sanitizer_mac.h2
-rw-r--r--lib/sanitizer_common/sanitizer_mac_libcdep.cc30
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.cc9
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.h3
-rw-r--r--lib/sanitizer_common/sanitizer_posix.cc119
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps.h41
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_common.cc14
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_freebsd.cc33
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_linux.cc43
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_mac.cc191
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc3
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc3
21 files changed, 441 insertions, 318 deletions
diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt
index bf8459ef5e91..a17bd1299a2c 100644
--- a/lib/sanitizer_common/CMakeLists.txt
+++ b/lib/sanitizer_common/CMakeLists.txt
@@ -6,6 +6,7 @@ set(SANITIZER_SOURCES_NOTERMINATION
sanitizer_common.cc
sanitizer_deadlock_detector1.cc
sanitizer_deadlock_detector2.cc
+ sanitizer_errno.cc
sanitizer_flags.cc
sanitizer_flag_parser.cc
sanitizer_libc.cc
@@ -57,6 +58,7 @@ set(SANITIZER_LIBCDEP_SOURCES
sanitizer_coverage_libcdep_new.cc
sanitizer_coverage_win_sections.cc
sanitizer_linux_libcdep.cc
+ sanitizer_mac_libcdep.cc
sanitizer_posix_libcdep.cc
sanitizer_stacktrace_libcdep.cc
sanitizer_stoptheworld_linux_libcdep.cc
@@ -92,6 +94,8 @@ set(SANITIZER_HEADERS
sanitizer_common_syscalls.inc
sanitizer_deadlock_detector.h
sanitizer_deadlock_detector_interface.h
+ sanitizer_errno.h
+ sanitizer_errno_codes.h
sanitizer_flag_parser.h
sanitizer_flags.h
sanitizer_flags.inc
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index d44c71513896..89aae579856a 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -107,7 +107,8 @@ bool MprotectNoAccess(uptr addr, uptr size);
bool MprotectReadOnly(uptr addr, uptr size);
// Find an available address space.
-uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding);
+uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
+ uptr *largest_gap_found);
// Used to check if we can map shadow memory to a fixed location.
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end);
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 459530aa95ba..8607bf44902d 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -40,6 +40,7 @@
#include "interception/interception.h"
#include "sanitizer_addrhashmap.h"
+#include "sanitizer_errno.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_platform_interceptors.h"
#include "sanitizer_tls_get_addr.h"
diff --git a/lib/sanitizer_common/sanitizer_errno.cc b/lib/sanitizer_common/sanitizer_errno.cc
new file mode 100644
index 000000000000..a6f9fc6125eb
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_errno.cc
@@ -0,0 +1,35 @@
+//===-- sanitizer_errno.cc --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between sanitizers run-time libraries.
+//
+// Defines errno to avoid including errno.h and its dependencies into other
+// files (e.g. interceptors are not supposed to include any system headers).
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_errno_codes.h"
+#include "sanitizer_internal_defs.h"
+
+#include <errno.h>
+
+namespace __sanitizer {
+
+COMPILER_CHECK(errno_ENOMEM == ENOMEM);
+COMPILER_CHECK(errno_EBUSY == EBUSY);
+COMPILER_CHECK(errno_EINVAL == EINVAL);
+
+// EOWNERDEAD is not present in some older platforms.
+#if defined(EOWNERDEAD)
+extern const int errno_EOWNERDEAD = EOWNERDEAD;
+#else
+extern const int errno_EOWNERDEAD = -1;
+#endif
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_errno.h b/lib/sanitizer_common/sanitizer_errno.h
new file mode 100644
index 000000000000..c405307ba8ec
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_errno.h
@@ -0,0 +1,35 @@
+//===-- sanitizer_errno.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between sanitizers run-time libraries.
+//
+// Defines errno to avoid including errno.h and its dependencies into sensitive
+// files (e.g. interceptors are not supposed to include any system headers).
+// It's ok to use errno.h directly when your file already depend on other system
+// includes though.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ERRNO_H
+#define SANITIZER_ERRNO_H
+
+#include "sanitizer_errno_codes.h"
+#include "sanitizer_platform.h"
+
+#if SANITIZER_FREEBSD || SANITIZER_MAC
+# define __errno_location __error
+#elif SANITIZER_ANDROID
+# define __errno_location __errno
+#endif
+
+extern "C" int *__errno_location();
+
+#define errno (*__errno_location())
+
+#endif // SANITIZER_ERRNO_H
diff --git a/lib/sanitizer_common/sanitizer_errno_codes.h b/lib/sanitizer_common/sanitizer_errno_codes.h
new file mode 100644
index 000000000000..dba774c5b6c5
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_errno_codes.h
@@ -0,0 +1,34 @@
+//===-- sanitizer_errno_codes.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between sanitizers run-time libraries.
+//
+// Defines errno codes to avoid including errno.h and its dependencies into
+// sensitive files (e.g. interceptors are not supposed to include any system
+// headers).
+// It's ok to use errno.h directly when your file already depend on other system
+// includes though.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ERRNO_CODES_H
+#define SANITIZER_ERRNO_CODES_H
+
+namespace __sanitizer {
+
+#define errno_ENOMEM 12
+#define errno_EBUSY 16
+#define errno_EINVAL 22
+
+// Those might not present or their value differ on different platforms.
+extern const int errno_EOWNERDEAD;
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_ERRNO_CODES_H
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index a94a63c7f16d..a79a2a155db9 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -59,6 +59,14 @@
#include <ucontext.h>
#include <unistd.h>
+#if SANITIZER_LINUX
+#include <sys/utsname.h>
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#include <sys/personality.h>
+#endif
+
#if SANITIZER_FREEBSD
#include <sys/exec.h>
#include <sys/sysctl.h>
@@ -209,7 +217,6 @@ static void stat64_to_stat(struct stat64 *in, struct stat *out) {
out->st_atime = in->st_atime;
out->st_mtime = in->st_mtime;
out->st_ctime = in->st_ctime;
- out->st_ino = in->st_ino;
}
#endif
@@ -229,7 +236,6 @@ static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) {
out->st_atime = in->st_atime_nsec;
out->st_mtime = in->st_mtime_nsec;
out->st_ctime = in->st_ctime_nsec;
- out->st_ino = in->st_ino;
}
#endif
@@ -815,6 +821,72 @@ bool ThreadLister::GetDirectoryEntries() {
return true;
}
+#if SANITIZER_WORDSIZE == 32
+// Take care of unusable kernel area in top gigabyte.
+static uptr GetKernelAreaSize() {
+#if SANITIZER_LINUX && !SANITIZER_X32
+ const uptr gbyte = 1UL << 30;
+
+ // Firstly check if there are writable segments
+ // mapped to top gigabyte (e.g. stack).
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ MemoryMappedSegment segment;
+ while (proc_maps.Next(&segment)) {
+ if ((segment.end >= 3 * gbyte) && segment.IsWritable()) return 0;
+ }
+
+#if !SANITIZER_ANDROID
+ // Even if nothing is mapped, top Gb may still be accessible
+ // if we are running on 64-bit kernel.
+ // Uname may report misleading results if personality type
+ // is modified (e.g. under schroot) so check this as well.
+ struct utsname uname_info;
+ int pers = personality(0xffffffffUL);
+ if (!(pers & PER_MASK)
+ && uname(&uname_info) == 0
+ && internal_strstr(uname_info.machine, "64"))
+ return 0;
+#endif // SANITIZER_ANDROID
+
+ // Top gigabyte is reserved for kernel.
+ return gbyte;
+#else
+ return 0;
+#endif // SANITIZER_LINUX && !SANITIZER_X32
+}
+#endif // SANITIZER_WORDSIZE == 32
+
+uptr GetMaxVirtualAddress() {
+#if SANITIZER_WORDSIZE == 64
+# if defined(__powerpc64__) || defined(__aarch64__)
+ // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
+ // We somehow need to figure out which one we are using now and choose
+ // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
+ // Note that with 'ulimit -s unlimited' the stack is moved away from the top
+ // of the address space, so simply checking the stack address is not enough.
+ // This should (does) work for both PowerPC64 Endian modes.
+ // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit.
+ return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
+# elif defined(__mips64)
+ return (1ULL << 40) - 1; // 0x000000ffffffffffUL;
+# elif defined(__s390x__)
+ return (1ULL << 53) - 1; // 0x001fffffffffffffUL;
+# else
+ return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
+# endif
+#else // SANITIZER_WORDSIZE == 32
+# if defined(__s390__)
+ return (1ULL << 31) - 1; // 0x7fffffff;
+# else
+ uptr res = (1ULL << 32) - 1; // 0xffffffff;
+ if (!common_flags()->full_address_space)
+ res -= GetKernelAreaSize();
+ CHECK_LT(reinterpret_cast<uptr>(&res), res);
+ return res;
+# endif
+#endif // SANITIZER_WORDSIZE
+}
+
uptr GetPageSize() {
// Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array.
#if SANITIZER_ANDROID
@@ -1599,7 +1671,8 @@ void CheckNoDeepBind(const char *filename, int flag) {
#endif
}
-uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding) {
+uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
+ uptr *largest_gap_found) {
UNREACHABLE("FindAvailableMemoryRange is not available");
return 0;
}
diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
index b9a48a1e496b..52196db12731 100644
--- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -81,28 +81,25 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
// Find the mapping that contains a stack variable.
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
- uptr start, end, offset;
+ MemoryMappedSegment segment;
uptr prev_end = 0;
- while (proc_maps.Next(&start, &end, &offset, nullptr, 0,
- /* protection */nullptr)) {
- if ((uptr)&rl < end)
- break;
- prev_end = end;
+ while (proc_maps.Next(&segment)) {
+ if ((uptr)&rl < segment.end) break;
+ prev_end = segment.end;
}
- CHECK((uptr)&rl >= start && (uptr)&rl < end);
+ CHECK((uptr)&rl >= segment.start && (uptr)&rl < segment.end);
// Get stacksize from rlimit, but clip it so that it does not overlap
// with other mappings.
uptr stacksize = rl.rlim_cur;
- if (stacksize > end - prev_end)
- stacksize = end - prev_end;
+ if (stacksize > segment.end - prev_end) stacksize = segment.end - prev_end;
// When running with unlimited stack size, we still want to set some limit.
// The unlimited stack size is caused by 'ulimit -s unlimited'.
// Also, for some reason, GNU make spawns subprocesses with unlimited stack.
if (stacksize > kMaxThreadStackSize)
stacksize = kMaxThreadStackSize;
- *stack_top = end;
- *stack_bottom = end - stacksize;
+ *stack_top = segment.end;
+ *stack_bottom = segment.end - stacksize;
return;
}
pthread_attr_t attr;
diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc
index b48238106dd9..8df01815f9f7 100644
--- a/lib/sanitizer_common/sanitizer_mac.cc
+++ b/lib/sanitizer_common/sanitizer_mac.cc
@@ -191,7 +191,8 @@ void internal_sigfillset(__sanitizer_sigset_t *set) { sigfillset(set); }
uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
__sanitizer_sigset_t *oldset) {
- return sigprocmask(how, set, oldset);
+ // Don't use sigprocmask here, because it affects all threads.
+ return pthread_sigmask(how, set, oldset);
}
// Doesn't call pthread_atfork() handlers (but not available on 10.6).
@@ -799,9 +800,48 @@ char **GetArgv() {
return *_NSGetArgv();
}
+#if defined(__aarch64__) && SANITIZER_IOS && !SANITIZER_IOSSIM
+// The task_vm_info struct is normally provided by the macOS SDK, but we need
+// fields only available in 10.12+. Declare the struct manually to be able to
+// build against older SDKs.
+struct __sanitizer_task_vm_info {
+ uptr _unused[(SANITIZER_WORDSIZE == 32) ? 20 : 19];
+ uptr min_address;
+ uptr max_address;
+};
+
+uptr GetTaskInfoMaxAddress() {
+ __sanitizer_task_vm_info vm_info = {{0}, 0, 0};
+ mach_msg_type_number_t count = sizeof(vm_info) / sizeof(int);
+ int err = task_info(mach_task_self(), TASK_VM_INFO, (int *)&vm_info, &count);
+ if (err == 0) {
+ return vm_info.max_address - 1;
+ } else {
+ // xnu cannot provide vm address limit
+ return 0x200000000 - 1;
+ }
+}
+#endif
+
+uptr GetMaxVirtualAddress() {
+#if SANITIZER_WORDSIZE == 64
+# if defined(__aarch64__) && SANITIZER_IOS && !SANITIZER_IOSSIM
+ // Get the maximum VM address
+ static uptr max_vm = GetTaskInfoMaxAddress();
+ CHECK(max_vm);
+ return max_vm;
+# else
+ return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
+# endif
+#else // SANITIZER_WORDSIZE == 32
+ return (1ULL << 32) - 1; // 0xffffffff;
+#endif // SANITIZER_WORDSIZE
+}
+
uptr FindAvailableMemoryRange(uptr shadow_size,
uptr alignment,
- uptr left_padding) {
+ uptr left_padding,
+ uptr *largest_gap_found) {
typedef vm_region_submap_short_info_data_64_t RegionInfo;
enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 };
// Start searching for available memory region past PAGEZERO, which is
@@ -812,6 +852,7 @@ uptr FindAvailableMemoryRange(uptr shadow_size,
mach_vm_address_t address = start_address;
mach_vm_address_t free_begin = start_address;
kern_return_t kr = KERN_SUCCESS;
+ if (largest_gap_found) *largest_gap_found = 0;
while (kr == KERN_SUCCESS) {
mach_vm_size_t vmsize = 0;
natural_t depth = 0;
@@ -821,10 +862,15 @@ uptr FindAvailableMemoryRange(uptr shadow_size,
(vm_region_info_t)&vminfo, &count);
if (free_begin != address) {
// We found a free region [free_begin..address-1].
- uptr shadow_address = RoundUpTo((uptr)free_begin + left_padding,
- alignment);
- if (shadow_address + shadow_size < (uptr)address) {
- return shadow_address;
+ uptr gap_start = RoundUpTo((uptr)free_begin + left_padding, alignment);
+ uptr gap_end = RoundDownTo((uptr)address, alignment);
+ uptr gap_size = gap_end > gap_start ? gap_end - gap_start : 0;
+ if (shadow_size < gap_size) {
+ return gap_start;
+ }
+
+ if (largest_gap_found && *largest_gap_found < gap_size) {
+ *largest_gap_found = gap_size;
}
}
// Move to the next region.
diff --git a/lib/sanitizer_common/sanitizer_mac.h b/lib/sanitizer_common/sanitizer_mac.h
index 636d9bfeac8c..3f1c68c8610a 100644
--- a/lib/sanitizer_common/sanitizer_mac.h
+++ b/lib/sanitizer_common/sanitizer_mac.h
@@ -36,6 +36,8 @@ MacosVersion GetMacosVersion();
char **GetEnviron();
+void RestrictMemoryToMaxAddress(uptr max_address);
+
} // namespace __sanitizer
extern "C" {
diff --git a/lib/sanitizer_common/sanitizer_mac_libcdep.cc b/lib/sanitizer_common/sanitizer_mac_libcdep.cc
new file mode 100644
index 000000000000..c95daa9372ad
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_mac_libcdep.cc
@@ -0,0 +1,30 @@
+//===-- sanitizer_mac_libcdep.cc ------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between various sanitizers' runtime libraries and
+// implements OSX-specific functions.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_MAC
+#include "sanitizer_mac.h"
+
+#include <sys/mman.h>
+
+namespace __sanitizer {
+
+void RestrictMemoryToMaxAddress(uptr max_address) {
+ uptr size_to_mmap = GetMaxVirtualAddress() + 1 - max_address;
+ void *res = MmapFixedNoAccess(max_address, size_to_mmap, "high gap");
+ CHECK(res != MAP_FAILED);
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
index 683f019d70c3..83f4fd22f623 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -25,7 +25,6 @@
#endif
#include <arpa/inet.h>
#include <dirent.h>
-#include <errno.h>
#include <grp.h>
#include <limits.h>
#include <net/if.h>
@@ -931,14 +930,6 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE;
#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
- const int errno_EINVAL = EINVAL;
-// EOWNERDEAD is not present in some older platforms.
-#if defined(EOWNERDEAD)
- const int errno_EOWNERDEAD = EOWNERDEAD;
-#else
- const int errno_EOWNERDEAD = -1;
-#endif
-
const int si_SEGV_MAPERR = SEGV_MAPERR;
const int si_SEGV_ACCERR = SEGV_ACCERR;
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
index 24ffcd7d94f4..63dcd2a6d683 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -1464,9 +1464,6 @@ struct __sanitizer_cookie_io_functions_t {
extern unsigned IOCTL_PIO_SCRNMAP;
#endif
- extern const int errno_EINVAL;
- extern const int errno_EOWNERDEAD;
-
extern const int si_SEGV_MAPERR;
extern const int si_SEGV_ACCERR;
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc
index 63f1bf713b24..8d3128ae199d 100644
--- a/lib/sanitizer_common/sanitizer_posix.cc
+++ b/lib/sanitizer_common/sanitizer_posix.cc
@@ -27,14 +27,6 @@
#include <signal.h>
#include <sys/mman.h>
-#if SANITIZER_LINUX
-#include <sys/utsname.h>
-#endif
-
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
-#include <sys/personality.h>
-#endif
-
#if SANITIZER_FREEBSD
// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
// that, it was never implemented. So just define it to zero.
@@ -49,80 +41,6 @@ uptr GetMmapGranularity() {
return GetPageSize();
}
-#if SANITIZER_WORDSIZE == 32
-// Take care of unusable kernel area in top gigabyte.
-static uptr GetKernelAreaSize() {
-#if SANITIZER_LINUX && !SANITIZER_X32
- const uptr gbyte = 1UL << 30;
-
- // Firstly check if there are writable segments
- // mapped to top gigabyte (e.g. stack).
- MemoryMappingLayout proc_maps(/*cache_enabled*/true);
- uptr end, prot;
- while (proc_maps.Next(/*start*/nullptr, &end,
- /*offset*/nullptr, /*filename*/nullptr,
- /*filename_size*/0, &prot)) {
- if ((end >= 3 * gbyte)
- && (prot & MemoryMappingLayout::kProtectionWrite) != 0)
- return 0;
- }
-
-#if !SANITIZER_ANDROID
- // Even if nothing is mapped, top Gb may still be accessible
- // if we are running on 64-bit kernel.
- // Uname may report misleading results if personality type
- // is modified (e.g. under schroot) so check this as well.
- struct utsname uname_info;
- int pers = personality(0xffffffffUL);
- if (!(pers & PER_MASK)
- && uname(&uname_info) == 0
- && internal_strstr(uname_info.machine, "64"))
- return 0;
-#endif // SANITIZER_ANDROID
-
- // Top gigabyte is reserved for kernel.
- return gbyte;
-#else
- return 0;
-#endif // SANITIZER_LINUX && !SANITIZER_X32
-}
-#endif // SANITIZER_WORDSIZE == 32
-
-uptr GetMaxVirtualAddress() {
-#if SANITIZER_WORDSIZE == 64
-# if defined(__aarch64__) && SANITIZER_IOS && !SANITIZER_IOSSIM
- // Ideally, we would derive the upper bound from MACH_VM_MAX_ADDRESS. The
- // upper bound can change depending on the device.
- return 0x200000000 - 1;
-# elif defined(__powerpc64__) || defined(__aarch64__)
- // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
- // We somehow need to figure out which one we are using now and choose
- // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
- // Note that with 'ulimit -s unlimited' the stack is moved away from the top
- // of the address space, so simply checking the stack address is not enough.
- // This should (does) work for both PowerPC64 Endian modes.
- // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit.
- return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
-# elif defined(__mips64)
- return (1ULL << 40) - 1; // 0x000000ffffffffffUL;
-# elif defined(__s390x__)
- return (1ULL << 53) - 1; // 0x001fffffffffffffUL;
-# else
- return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
-# endif
-#else // SANITIZER_WORDSIZE == 32
-# if defined(__s390__)
- return (1ULL << 31) - 1; // 0x7fffffff;
-# else
- uptr res = (1ULL << 32) - 1; // 0xffffffff;
- if (!common_flags()->full_address_space)
- res -= GetKernelAreaSize();
- CHECK_LT(reinterpret_cast<uptr>(&res), res);
- return res;
-# endif
-#endif // SANITIZER_WORDSIZE
-}
-
void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
size = RoundUpTo(size, GetPageSizeCached());
uptr res = internal_mmap(nullptr, size,
@@ -162,7 +80,7 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
}
// We want to map a chunk of address space aligned to 'alignment'.
-// We do it by maping a bit more and then unmaping redundant pieces.
+// We do it by mapping a bit more and then unmapping redundant pieces.
// We probably can do it with fewer syscalls in some OS-dependent way.
void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
const char *mem_type) {
@@ -313,13 +231,12 @@ static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
// memory).
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
- uptr start, end;
- while (proc_maps.Next(&start, &end,
- /*offset*/nullptr, /*filename*/nullptr,
- /*filename_size*/0, /*protection*/nullptr)) {
- if (start == end) continue; // Empty range.
- CHECK_NE(0, end);
- if (!IntervalsAreSeparate(start, end - 1, range_start, range_end))
+ MemoryMappedSegment segment;
+ while (proc_maps.Next(&segment)) {
+ if (segment.start == segment.end) continue; // Empty range.
+ CHECK_NE(0, segment.end);
+ if (!IntervalsAreSeparate(segment.start, segment.end - 1, range_start,
+ range_end))
return false;
}
return true;
@@ -327,13 +244,13 @@ bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
void DumpProcessMap() {
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
- uptr start, end;
const sptr kBufSize = 4095;
char *filename = (char*)MmapOrDie(kBufSize, __func__);
+ MemoryMappedSegment segment(filename, kBufSize);
Report("Process memory map follows:\n");
- while (proc_maps.Next(&start, &end, /* file_offset */nullptr,
- filename, kBufSize, /* protection */nullptr)) {
- Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename);
+ while (proc_maps.Next(&segment)) {
+ Printf("\t%p-%p\t%s\n", (void *)segment.start, (void *)segment.end,
+ segment.filename);
}
Report("End of process memory map.\n");
UnmapOrDie(filename, kBufSize);
@@ -363,14 +280,14 @@ void ReportFile::Write(const char *buffer, uptr length) {
}
bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
- uptr s, e, off, prot;
- InternalScopedString buff(kMaxPathLength);
MemoryMappingLayout proc_maps(/*cache_enabled*/false);
- while (proc_maps.Next(&s, &e, &off, buff.data(), buff.size(), &prot)) {
- if ((prot & MemoryMappingLayout::kProtectionExecute) != 0
- && internal_strcmp(module, buff.data()) == 0) {
- *start = s;
- *end = e;
+ InternalScopedString buff(kMaxPathLength);
+ MemoryMappedSegment segment(buff.data(), kMaxPathLength);
+ while (proc_maps.Next(&segment)) {
+ if (segment.IsExecutable() &&
+ internal_strcmp(module, segment.filename) == 0) {
+ *start = segment.start;
+ *end = segment.end;
return true;
}
}
diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h
index 5aad6b959ad4..06d072b4dc77 100644
--- a/lib/sanitizer_common/sanitizer_procmaps.h
+++ b/lib/sanitizer_common/sanitizer_procmaps.h
@@ -31,13 +31,37 @@ struct ProcSelfMapsBuff {
void ReadProcMaps(ProcSelfMapsBuff *proc_maps);
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+// Memory protection masks.
+static const uptr kProtectionRead = 1;
+static const uptr kProtectionWrite = 2;
+static const uptr kProtectionExecute = 4;
+static const uptr kProtectionShared = 8;
+
+struct MemoryMappedSegment {
+ MemoryMappedSegment(char *buff = nullptr, uptr size = 0)
+ : filename(buff), filename_size(size) {}
+ ~MemoryMappedSegment() {}
+
+ bool IsReadable() { return protection & kProtectionRead; }
+ bool IsWritable() { return protection & kProtectionWrite; }
+ bool IsExecutable() { return protection & kProtectionExecute; }
+ bool IsShared() { return protection & kProtectionShared; }
+
+ uptr start;
+ uptr end;
+ uptr offset;
+ char *filename; // owned by caller
+ uptr filename_size;
+ uptr protection;
+ ModuleArch arch;
+ u8 uuid[kModuleUUIDSize];
+};
+
class MemoryMappingLayout {
public:
explicit MemoryMappingLayout(bool cache_enabled);
~MemoryMappingLayout();
- bool Next(uptr *start, uptr *end, uptr *offset, char filename[],
- uptr filename_size, uptr *protection, ModuleArch *arch = nullptr,
- u8 *uuid = nullptr);
+ bool Next(MemoryMappedSegment *segment);
void Reset();
// In some cases, e.g. when running under a sandbox on Linux, ASan is unable
// to obtain the memory mappings. It should fall back to pre-cached data
@@ -47,12 +71,6 @@ class MemoryMappingLayout {
// Adds all mapped objects into a vector.
void DumpListOfModules(InternalMmapVector<LoadedModule> *modules);
- // Memory protection masks.
- static const uptr kProtectionRead = 1;
- static const uptr kProtectionWrite = 2;
- static const uptr kProtectionExecute = 4;
- static const uptr kProtectionShared = 8;
-
private:
void LoadFromCache();
@@ -67,10 +85,7 @@ class MemoryMappingLayout {
static StaticSpinMutex cache_lock_; // protects cached_proc_self_maps_.
# elif SANITIZER_MAC
template <u32 kLCSegment, typename SegmentCommand>
- bool NextSegmentLoad(uptr *start, uptr *end, uptr *offset, char filename[],
- uptr filename_size, ModuleArch *arch, u8 *uuid,
- uptr *protection);
- void GetSegmentAddrRange(uptr *start, uptr *end, uptr vmaddr, uptr vmsize);
+ bool NextSegmentLoad(MemoryMappedSegment *segment);
int current_image_;
u32 current_magic_;
u32 current_filetype_;
diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc
index c583f42f25d8..b95f301a437d 100644
--- a/lib/sanitizer_common/sanitizer_procmaps_common.cc
+++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc
@@ -119,12 +119,10 @@ void MemoryMappingLayout::LoadFromCache() {
void MemoryMappingLayout::DumpListOfModules(
InternalMmapVector<LoadedModule> *modules) {
Reset();
- uptr cur_beg, cur_end, cur_offset, prot;
InternalScopedString module_name(kMaxPathLength);
- for (uptr i = 0; Next(&cur_beg, &cur_end, &cur_offset, module_name.data(),
- module_name.size(), &prot);
- i++) {
- const char *cur_name = module_name.data();
+ MemoryMappedSegment segment(module_name.data(), module_name.size());
+ for (uptr i = 0; Next(&segment); i++) {
+ const char *cur_name = segment.filename;
if (cur_name[0] == '\0')
continue;
// Don't subtract 'cur_beg' from the first entry:
@@ -138,11 +136,11 @@ void MemoryMappingLayout::DumpListOfModules(
// mapped high at address space (in particular, higher than
// shadow memory of the tool), so the module can't be the
// first entry.
- uptr base_address = (i ? cur_beg : 0) - cur_offset;
+ uptr base_address = (i ? segment.start : 0) - segment.offset;
LoadedModule cur_module;
cur_module.set(cur_name, base_address);
- cur_module.addAddressRange(cur_beg, cur_end, prot & kProtectionExecute,
- prot & kProtectionWrite);
+ cur_module.addAddressRange(segment.start, segment.end,
+ segment.IsExecutable(), segment.IsWritable());
modules->push_back(cur_module);
}
}
diff --git a/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc b/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc
index 30216456330e..f0cdbeb4483a 100644
--- a/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc
+++ b/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc
@@ -48,36 +48,27 @@ void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
proc_maps->len = Size;
}
-bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
- char filename[], uptr filename_size,
- uptr *protection, ModuleArch *arch, u8 *uuid) {
- CHECK(!arch && "not implemented");
- CHECK(!uuid && "not implemented");
+bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
char *last = proc_self_maps_.data + proc_self_maps_.len;
if (current_ >= last) return false;
- uptr dummy;
- if (!start) start = &dummy;
- if (!end) end = &dummy;
- if (!offset) offset = &dummy;
- if (!protection) protection = &dummy;
struct kinfo_vmentry *VmEntry = (struct kinfo_vmentry*)current_;
- *start = (uptr)VmEntry->kve_start;
- *end = (uptr)VmEntry->kve_end;
- *offset = (uptr)VmEntry->kve_offset;
+ segment->start = (uptr)VmEntry->kve_start;
+ segment->end = (uptr)VmEntry->kve_end;
+ segment->offset = (uptr)VmEntry->kve_offset;
- *protection = 0;
+ segment->protection = 0;
if ((VmEntry->kve_protection & KVME_PROT_READ) != 0)
- *protection |= kProtectionRead;
+ segment->protection |= kProtectionRead;
if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0)
- *protection |= kProtectionWrite;
+ segment->protection |= kProtectionWrite;
if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0)
- *protection |= kProtectionExecute;
+ segment->protection |= kProtectionExecute;
- if (filename != NULL && filename_size > 0) {
- internal_snprintf(filename,
- Min(filename_size, (uptr)PATH_MAX),
- "%s", VmEntry->kve_path);
+ if (segment->filename != NULL && segment->filename_size > 0) {
+ internal_snprintf(segment->filename,
+ Min(segment->filename_size, (uptr)PATH_MAX), "%s",
+ VmEntry->kve_path);
}
current_ += VmEntry->kve_structsize;
diff --git a/lib/sanitizer_common/sanitizer_procmaps_linux.cc b/lib/sanitizer_common/sanitizer_procmaps_linux.cc
index 7e4a44be95b6..1bcad2bf70e6 100644
--- a/lib/sanitizer_common/sanitizer_procmaps_linux.cc
+++ b/lib/sanitizer_common/sanitizer_procmaps_linux.cc
@@ -26,41 +26,28 @@ static bool IsOneOf(char c, char c1, char c2) {
return c == c1 || c == c2;
}
-bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
- char filename[], uptr filename_size,
- uptr *protection, ModuleArch *arch, u8 *uuid) {
- CHECK(!arch && "not implemented");
- CHECK(!uuid && "not implemented");
+bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
char *last = proc_self_maps_.data + proc_self_maps_.len;
if (current_ >= last) return false;
- uptr dummy;
- if (!start) start = &dummy;
- if (!end) end = &dummy;
- if (!offset) offset = &dummy;
- if (!protection) protection = &dummy;
char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
if (next_line == 0)
next_line = last;
// Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar
- *start = ParseHex(&current_);
+ segment->start = ParseHex(&current_);
CHECK_EQ(*current_++, '-');
- *end = ParseHex(&current_);
+ segment->end = ParseHex(&current_);
CHECK_EQ(*current_++, ' ');
CHECK(IsOneOf(*current_, '-', 'r'));
- *protection = 0;
- if (*current_++ == 'r')
- *protection |= kProtectionRead;
+ segment->protection = 0;
+ if (*current_++ == 'r') segment->protection |= kProtectionRead;
CHECK(IsOneOf(*current_, '-', 'w'));
- if (*current_++ == 'w')
- *protection |= kProtectionWrite;
+ if (*current_++ == 'w') segment->protection |= kProtectionWrite;
CHECK(IsOneOf(*current_, '-', 'x'));
- if (*current_++ == 'x')
- *protection |= kProtectionExecute;
+ if (*current_++ == 'x') segment->protection |= kProtectionExecute;
CHECK(IsOneOf(*current_, 's', 'p'));
- if (*current_++ == 's')
- *protection |= kProtectionShared;
+ if (*current_++ == 's') segment->protection |= kProtectionShared;
CHECK_EQ(*current_++, ' ');
- *offset = ParseHex(&current_);
+ segment->offset = ParseHex(&current_);
CHECK_EQ(*current_++, ' ');
ParseHex(&current_);
CHECK_EQ(*current_++, ':');
@@ -75,14 +62,12 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
while (current_ < next_line && *current_ == ' ')
current_++;
// Fill in the filename.
- uptr i = 0;
- while (current_ < next_line) {
- if (filename && i < filename_size - 1)
- filename[i++] = *current_;
- current_++;
+ if (segment->filename) {
+ uptr len = Min((uptr)(next_line - current_), segment->filename_size - 1);
+ internal_strncpy(segment->filename, current_, len);
+ segment->filename[len] = 0;
}
- if (filename && i < filename_size)
- filename[i] = 0;
+
current_ = next_line + 1;
return true;
}
diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc
index 131017458d4c..560451a16d90 100644
--- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc
+++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc
@@ -88,6 +88,48 @@ void MemoryMappingLayout::LoadFromCache() {
// No-op on Mac for now.
}
+// _dyld_get_image_header() and related APIs don't report dyld itself.
+// We work around this by manually recursing through the memory map
+// until we hit a Mach header matching dyld instead. These recurse
+// calls are expensive, but the first memory map generation occurs
+// early in the process, when dyld is one of the only images loaded,
+// so it will be hit after only a few iterations.
+static mach_header *get_dyld_image_header() {
+ mach_port_name_t port;
+ if (task_for_pid(mach_task_self(), internal_getpid(), &port) !=
+ KERN_SUCCESS) {
+ return nullptr;
+ }
+
+ unsigned depth = 1;
+ vm_size_t size = 0;
+ vm_address_t address = 0;
+ kern_return_t err = KERN_SUCCESS;
+ mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
+
+ while (true) {
+ struct vm_region_submap_info_64 info;
+ err = vm_region_recurse_64(port, &address, &size, &depth,
+ (vm_region_info_t)&info, &count);
+ if (err != KERN_SUCCESS) return nullptr;
+
+ if (size >= sizeof(mach_header) && info.protection & kProtectionRead) {
+ mach_header *hdr = (mach_header *)address;
+ if ((hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) &&
+ hdr->filetype == MH_DYLINKER) {
+ return hdr;
+ }
+ }
+ address += size;
+ }
+}
+
+const mach_header *get_dyld_hdr() {
+ if (!dyld_hdr) dyld_hdr = get_dyld_image_header();
+
+ return dyld_hdr;
+}
+
// Next and NextSegmentLoad were inspired by base/sysinfo.cc in
// Google Perftools, https://github.com/gperftools/gperftools.
@@ -96,40 +138,39 @@ void MemoryMappingLayout::LoadFromCache() {
// segment.
// Note that the segment addresses are not necessarily sorted.
template <u32 kLCSegment, typename SegmentCommand>
-bool MemoryMappingLayout::NextSegmentLoad(uptr *start, uptr *end, uptr *offset,
- char filename[], uptr filename_size,
- ModuleArch *arch, u8 *uuid,
- uptr *protection) {
+bool MemoryMappingLayout::NextSegmentLoad(MemoryMappedSegment *segment) {
const char *lc = current_load_cmd_addr_;
current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
if (((const load_command *)lc)->cmd == kLCSegment) {
const SegmentCommand* sc = (const SegmentCommand *)lc;
- GetSegmentAddrRange(start, end, sc->vmaddr, sc->vmsize);
- if (protection) {
- // Return the initial protection.
- *protection = sc->initprot;
- }
- if (offset) {
- if (current_filetype_ == /*MH_EXECUTE*/ 0x2) {
- *offset = sc->vmaddr;
- } else {
- *offset = sc->fileoff;
- }
- }
- if (filename) {
- if (current_image_ == kDyldImageIdx) {
- internal_strncpy(filename, kDyldPath, filename_size);
- } else {
- internal_strncpy(filename, _dyld_get_image_name(current_image_),
- filename_size);
- }
- }
- if (arch) {
- *arch = current_arch_;
+
+ if (current_image_ == kDyldImageIdx) {
+ // vmaddr is masked with 0xfffff because on macOS versions < 10.12,
+ // it contains an absolute address rather than an offset for dyld.
+ // To make matters even more complicated, this absolute address
+ // isn't actually the absolute segment address, but the offset portion
+ // of the address is accurate when combined with the dyld base address,
+ // and the mask will give just this offset.
+ segment->start = (sc->vmaddr & 0xfffff) + (uptr)get_dyld_hdr();
+ segment->end = (sc->vmaddr & 0xfffff) + sc->vmsize + (uptr)get_dyld_hdr();
+ } else {
+ const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
+ segment->start = sc->vmaddr + dlloff;
+ segment->end = sc->vmaddr + sc->vmsize + dlloff;
}
- if (uuid) {
- internal_memcpy(uuid, current_uuid_, kModuleUUIDSize);
+
+ // Return the initial protection.
+ segment->protection = sc->initprot;
+ segment->offset =
+ (current_filetype_ == /*MH_EXECUTE*/ 0x2) ? sc->vmaddr : sc->fileoff;
+ if (segment->filename) {
+ const char *src = (current_image_ == kDyldImageIdx)
+ ? kDyldPath
+ : _dyld_get_image_name(current_image_);
+ internal_strncpy(segment->filename, src, segment->filename_size);
}
+ segment->arch = current_arch_;
+ internal_memcpy(segment->uuid, current_uuid_, kModuleUUIDSize);
return true;
}
return false;
@@ -190,70 +231,7 @@ static bool IsModuleInstrumented(const load_command *first_lc) {
return false;
}
-// _dyld_get_image_header() and related APIs don't report dyld itself.
-// We work around this by manually recursing through the memory map
-// until we hit a Mach header matching dyld instead. These recurse
-// calls are expensive, but the first memory map generation occurs
-// early in the process, when dyld is one of the only images loaded,
-// so it will be hit after only a few iterations.
-static mach_header *get_dyld_image_header() {
- mach_port_name_t port;
- if (task_for_pid(mach_task_self(), internal_getpid(), &port) !=
- KERN_SUCCESS) {
- return nullptr;
- }
-
- unsigned depth = 1;
- vm_size_t size = 0;
- vm_address_t address = 0;
- kern_return_t err = KERN_SUCCESS;
- mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
-
- while (true) {
- struct vm_region_submap_info_64 info;
- err = vm_region_recurse_64(port, &address, &size, &depth,
- (vm_region_info_t)&info, &count);
- if (err != KERN_SUCCESS) return nullptr;
-
- if (size >= sizeof(mach_header) &&
- info.protection & MemoryMappingLayout::kProtectionRead) {
- mach_header *hdr = (mach_header *)address;
- if ((hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) &&
- hdr->filetype == MH_DYLINKER) {
- return hdr;
- }
- }
- address += size;
- }
-}
-
-const mach_header *get_dyld_hdr() {
- if (!dyld_hdr) dyld_hdr = get_dyld_image_header();
-
- return dyld_hdr;
-}
-
-void MemoryMappingLayout::GetSegmentAddrRange(uptr *start, uptr *end,
- uptr vmaddr, uptr vmsize) {
- if (current_image_ == kDyldImageIdx) {
- // vmaddr is masked with 0xfffff because on macOS versions < 10.12,
- // it contains an absolute address rather than an offset for dyld.
- // To make matters even more complicated, this absolute address
- // isn't actually the absolute segment address, but the offset portion
- // of the address is accurate when combined with the dyld base address,
- // and the mask will give just this offset.
- if (start) *start = (vmaddr & 0xfffff) + (uptr)get_dyld_hdr();
- if (end) *end = (vmaddr & 0xfffff) + vmsize + (uptr)get_dyld_hdr();
- } else {
- const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
- if (start) *start = vmaddr + dlloff;
- if (end) *end = vmaddr + vmsize + dlloff;
- }
-}
-
-bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
- char filename[], uptr filename_size,
- uptr *protection, ModuleArch *arch, u8 *uuid) {
+bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
for (; current_image_ >= kDyldImageIdx; current_image_--) {
const mach_header *hdr = (current_image_ == kDyldImageIdx)
? get_dyld_hdr()
@@ -291,16 +269,13 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
#ifdef MH_MAGIC_64
case MH_MAGIC_64: {
if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
- start, end, offset, filename, filename_size, arch, uuid,
- protection))
+ segment))
return true;
break;
}
#endif
case MH_MAGIC: {
- if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
- start, end, offset, filename, filename_size, arch, uuid,
- protection))
+ if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(segment))
return true;
break;
}
@@ -315,28 +290,22 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
void MemoryMappingLayout::DumpListOfModules(
InternalMmapVector<LoadedModule> *modules) {
Reset();
- uptr cur_beg, cur_end, prot;
- ModuleArch cur_arch;
- u8 cur_uuid[kModuleUUIDSize];
InternalScopedString module_name(kMaxPathLength);
- for (uptr i = 0; Next(&cur_beg, &cur_end, 0, module_name.data(),
- module_name.size(), &prot, &cur_arch, &cur_uuid[0]);
- i++) {
- const char *cur_name = module_name.data();
- if (cur_name[0] == '\0')
- continue;
+ MemoryMappedSegment segment(module_name.data(), kMaxPathLength);
+ for (uptr i = 0; Next(&segment); i++) {
+ if (segment.filename[0] == '\0') continue;
LoadedModule *cur_module = nullptr;
if (!modules->empty() &&
- 0 == internal_strcmp(cur_name, modules->back().full_name())) {
+ 0 == internal_strcmp(segment.filename, modules->back().full_name())) {
cur_module = &modules->back();
} else {
modules->push_back(LoadedModule());
cur_module = &modules->back();
- cur_module->set(cur_name, cur_beg, cur_arch, cur_uuid,
- current_instrumented_);
+ cur_module->set(segment.filename, segment.start, segment.arch,
+ segment.uuid, current_instrumented_);
}
- cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute,
- prot & kProtectionWrite);
+ cur_module->addAddressRange(segment.start, segment.end,
+ segment.IsExecutable(), segment.IsWritable());
}
}
diff --git a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
index 36c98d057bd3..747a4a701728 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
@@ -43,7 +43,8 @@ void StackTrace::Print() const {
if (dedup_frames-- > 0) {
if (dedup_token.length())
dedup_token.append("--");
- dedup_token.append(cur->info.function);
+ if (cur->info.function != nullptr)
+ dedup_token.append(cur->info.function);
}
}
frames->ClearAll();
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index 89d9cf61c3e4..de01e8d119a1 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -291,7 +291,8 @@ void DontDumpShadowMemory(uptr addr, uptr length) {
// FIXME: add madvise-analog when we move to 64-bits.
}
-uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding) {
+uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
+ uptr *largest_gap_found) {
uptr address = 0;
while (true) {
MEMORY_BASIC_INFORMATION info;