-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[TySan] Intercept malloc_size on Apple platforms. #122133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-compiler-rt-sanitizer Author: Florian Hahn (fhahn) ChangesAfter #120563 malloc_size also needs intercepting on Apple platforms, otherwise all type-sanitized binaries crash on startup with an objc error: Full diff: https://github.com/llvm/llvm-project/pull/122133.diff 2 Files Affected:
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_dlsym.h b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_dlsym.h
index b360478a058a54..5465258e6a022d 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_dlsym.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_dlsym.h
@@ -37,7 +37,7 @@ struct DlSymAllocator {
void *ptr = InternalAlloc(size_in_bytes, nullptr, align);
CHECK(internal_allocator()->FromPrimary(ptr));
Details::OnAllocate(ptr,
- internal_allocator()->GetActuallyAllocatedSize(ptr));
+ Size(ptr));
return ptr;
}
@@ -45,12 +45,12 @@ struct DlSymAllocator {
void *ptr = InternalCalloc(nmemb, size);
CHECK(internal_allocator()->FromPrimary(ptr));
Details::OnAllocate(ptr,
- internal_allocator()->GetActuallyAllocatedSize(ptr));
+ Size(ptr));
return ptr;
}
static void Free(void *ptr) {
- uptr size = internal_allocator()->GetActuallyAllocatedSize(ptr);
+ uptr size = Size(ptr);
Details::OnFree(ptr, size);
InternalFree(ptr);
}
@@ -63,7 +63,7 @@ struct DlSymAllocator {
Free(ptr);
return nullptr;
}
- uptr size = internal_allocator()->GetActuallyAllocatedSize(ptr);
+ uptr size = Size(ptr);
uptr memcpy_size = Min(new_size, size);
void *new_ptr = Allocate(new_size);
if (new_ptr)
@@ -77,6 +77,10 @@ struct DlSymAllocator {
return Realloc(ptr, count * size);
}
+ static uptr Size(void *ptr) {
+ return internal_allocator()->GetActuallyAllocatedSize(ptr);
+ }
+
static void OnAllocate(const void *ptr, uptr size) {}
static void OnFree(const void *ptr, uptr size) {}
};
diff --git a/compiler-rt/lib/tysan/tysan_interceptors.cpp b/compiler-rt/lib/tysan/tysan_interceptors.cpp
index 08b1010a48ecf0..4a89f0746230fe 100644
--- a/compiler-rt/lib/tysan/tysan_interceptors.cpp
+++ b/compiler-rt/lib/tysan/tysan_interceptors.cpp
@@ -108,6 +108,14 @@ INTERCEPTOR(void *, malloc, uptr size) {
return res;
}
+#if SANITIZER_APPLE
+INTERCEPTOR(uptr , malloc_size, void *ptr) {
+ if (DlsymAlloc::Use())
+ return DlsymAlloc::Size(ptr);
+ return REAL(malloc_size)(ptr);
+}
+#endif
+
INTERCEPTOR(void *, realloc, void *ptr, uptr size) {
if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
return DlsymAlloc::Realloc(ptr, size);
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
@@ -108,6 +108,14 @@ INTERCEPTOR(void *, malloc, uptr size) { | |||
return res; | |||
} | |||
|
|||
#if SANITIZER_APPLE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
drive by question: how do we decide between TYSAN_INTERCEPT___STRDUP
and SANITIZER_APPLE
style conditions?
@@ -108,6 +108,14 @@ INTERCEPTOR(void *, malloc, uptr size) { | |||
return res; | |||
} | |||
|
|||
#if SANITIZER_APPLE | |||
INTERCEPTOR(uptr, malloc_size, void *ptr) { | |||
if (DlsymAlloc::Use()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we need DlSymAlloc::PointerIsMine
here but we do in realloc
? (undo approval)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Glad you figured out the problem. I think the implementation of malloc_size
interceptor needs to be a little different to avoid a potential bug.
@@ -108,6 +108,14 @@ INTERCEPTOR(void *, malloc, uptr size) { | |||
return res; | |||
} | |||
|
|||
#if SANITIZER_APPLE | |||
INTERCEPTOR(uptr, malloc_size, void *ptr) { | |||
if (DlsymAlloc::Use()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A less fragile implementation here would be ask the DlsymAlloc
allocator if it owns this allocation and if so request the size from it, otherwise call the system malloc_size
. That way the malloc_size
interceptor always reports the right things no matter which allocator actually allocated the memory.
The current implementation means that if malloc_size
is called after TYSan init on an allocation that was allocated during TySan init then we'll call the system malloc_size
which will fail because the system allocator didn't allocator the memory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I think that should be taken care of by checking PointerIsMine
(as mentioned by @fmayer ). Update the code.
@@ -110,7 +110,7 @@ INTERCEPTOR(void *, malloc, uptr size) { | |||
|
|||
#if SANITIZER_APPLE | |||
INTERCEPTOR(uptr, malloc_size, void *ptr) { | |||
if (DlsymAlloc::Use()) | |||
if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question as for realloc
: please document the state transitions we support.
Specifically: could it be that DlSymAlloc::Use
is true but NOT DlsymAlloc::PointerIsMine(ptr)
(e.g. because the pointer was created before DlSymAlloc was enabled? That would be incorrect then I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For realloc
, during TySan init realloc(0, size)
can make DlSymAlloc::Use
is true but DlsymAlloc::PointerIsMine(ptr)
is false.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So do we need DlsymAlloc::Use()
here? To me DlsymAlloc::PointerIsMine(ptr)
sounds like what we actually care about?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep that should do the trick, done ,thanks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the fix!
On Apple platforms, malloc_size also needs intercepting with DlSymAllocator, otherwise all type-sanitized binaries crash on startup with an objc error: realized class 0x12345 has corrupt data pointer: malloc_size(0x567) = 0
8c8f9d9
to
5688643
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a minor nit. Other than that LGTM.
@@ -77,6 +75,10 @@ struct DlSymAllocator { | |||
return Realloc(ptr, count * size); | |||
} | |||
|
|||
static uptr Size(void *ptr) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I'd call this GetSize()
rather than Size()
because other methods have verbs in their name (e.g. Allocate
) but Size
doesn't contain a verb but GetSize()
does.
It's not really that important so feel free to ignore this suggestion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated, thanks!
I've download this patch locally, and can confirm it fixes my issue. Now 94% of cmake's unit tests pass, which is the kind of fraction one might expect using a new stress testing tool. Now to actually take a look at some... |
Actually, looks like most (all?) are some weird linking issue:
|
@seanm Thanks for checking! Not sure what is going on here exactly, I've not seen this locally myself. Could you file an issue with steps to reproduce? |
OK I'll wait until this is merged so as to be using a more proper build of clang. |
After llvm/llvm-project#120563 malloc_size also needs intercepting on Apple platforms, otherwise all type-sanitized binaries crash on startup with an objc error: realized class 0x12345 has corrupt data pointer: malloc_size(0x567) = 0 PR: llvm/llvm-project#122133
After llvm#120563 malloc_size also needs intercepting on Apple platforms, otherwise all type-sanitized binaries crash on startup with an objc error: realized class 0x12345 has corrupt data pointer: malloc_size(0x567) = 0 PR: llvm#122133
After #120563 malloc_size also needs intercepting on Apple platforms, otherwise all type-sanitized binaries crash on startup with an objc error:
realized class 0x12345 has corrupt data pointer: malloc_size(0x567) = 0