Skip to content

Commit bbb90fe

Browse files
authored
[tsan] Fix ASLR edge case, and improve diagnostics (#97125)
In extremely rare cases (estimated 1 in 3 million), minor allocations that happen after the memory layout was checked in InitializePlatformEarly() [1] may result in the memory layout unexpectedly being incompatible in InitializePlatform(). We fix this by adding another memory layout check (and opportunity to re-exec without ASLR) in InitializePlatform(). To improve future debuggability, this patch also dumps the process map if the memory layout is unexpectedly incompatible. [1] ``` __sanitizer::InitializePlatformEarly(); __tsan::InitializePlatformEarly(); #if !SANITIZER_GO InitializeAllocator(); // <-- ~8MB mmap'ed ReplaceSystemMalloc(); #endif if (common_flags()->detect_deadlocks) ctx->dd = DDetector::Create(flags()); // <-- ~4MB mmap'ed Processor *proc = ProcCreate(); // <-- ~1MB mmap'ed ProcWire(proc, thr); InitializeInterceptors(); <-- ~3MB mmap'ed InitializePlatform(); ```
1 parent c026135 commit bbb90fe

File tree

1 file changed

+21
-7
lines changed

1 file changed

+21
-7
lines changed

compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ void InitializeShadowMemoryPlatform() {
215215
#endif // #if !SANITIZER_GO
216216

217217
# if !SANITIZER_GO
218-
static void ReExecIfNeeded() {
218+
static void ReExecIfNeeded(bool ignore_heap) {
219219
// Go maps shadow memory lazily and works fine with limited address space.
220220
// Unlimited stack is not a problem as well, because the executable
221221
// is not compiled with -pie.
@@ -266,7 +266,7 @@ static void ReExecIfNeeded() {
266266

267267
if (reexec) {
268268
// Don't check the address space since we're going to re-exec anyway.
269-
} else if (!CheckAndProtect(false, false, false)) {
269+
} else if (!CheckAndProtect(false, ignore_heap, false)) {
270270
// ASLR personality check.
271271
// N.B. 'personality' is sometimes forbidden by sandboxes, so we only call
272272
// this as a last resort (when the memory mapping is incompatible and TSan
@@ -290,10 +290,11 @@ static void ReExecIfNeeded() {
290290
CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
291291
reexec = true;
292292
} else {
293-
VReport(1,
294-
"FATAL: ThreadSanitizer: memory layout is incompatible, "
295-
"even though ASLR is disabled.\n"
296-
"Please file a bug.\n");
293+
Printf(
294+
"FATAL: ThreadSanitizer: memory layout is incompatible, "
295+
"even though ASLR is disabled.\n"
296+
"Please file a bug.\n");
297+
DumpProcessMap();
297298
Die();
298299
}
299300
}
@@ -376,7 +377,8 @@ void InitializePlatformEarly() {
376377
# endif
377378

378379
# if !SANITIZER_GO
379-
ReExecIfNeeded();
380+
// Heap has not been allocated yet
381+
ReExecIfNeeded(false);
380382
# endif
381383
}
382384

@@ -394,13 +396,25 @@ void InitializePlatform() {
394396
# endif
395397
}
396398

399+
// We called ReExecIfNeeded() in InitializePlatformEarly(), but there are
400+
// intervening allocations that result in an edge case:
401+
// 1) InitializePlatformEarly(): memory layout is compatible
402+
// 2) Intervening allocations happen
403+
// 3) InitializePlatform(): memory layout is incompatible and fails
404+
// CheckAndProtect()
405+
# if !SANITIZER_GO
406+
// Heap has already been allocated
407+
ReExecIfNeeded(true);
408+
# endif
409+
397410
// Earlier initialization steps already re-exec'ed until we got a compatible
398411
// memory layout, so we don't expect any more issues here.
399412
if (!CheckAndProtect(true, true, true)) {
400413
Printf(
401414
"FATAL: ThreadSanitizer: unexpectedly found incompatible memory "
402415
"layout.\n");
403416
Printf("FATAL: Please file a bug.\n");
417+
DumpProcessMap();
404418
Die();
405419
}
406420

0 commit comments

Comments
 (0)