[tsan] Return 0 from malloc_size for non-malloc'd pointers

In http://reviews.llvm.org/D19100, I introduced a bug: On OS X, existing programs rely on malloc_size() to detect whether a pointer comes from heap memory (malloc_size returns non-zero) or not. We have to distinguish between a zero-sized allocation (where we need to return 1 from malloc_size, due to other binary compatibility reasons, see http://reviews.llvm.org/D19100), and pointers that are not returned from malloc at all.

Differential Revision: http://reviews.llvm.org/D19653

llvm-svn: 268157
This commit is contained in:
Kuba Brecka 2016-04-30 07:14:41 +00:00
parent eb5bd02a7e
commit 9ccde5ace4
3 changed files with 49 additions and 14 deletions

View File

@ -53,8 +53,7 @@ using namespace __tsan;
SCOPED_INTERCEPTOR_RAW(free, ptr); \
user_free(thr, pc, ptr)
#define COMMON_MALLOC_SIZE(ptr) \
uptr size = user_alloc_usable_size(ptr); \
if (size == 0) size = 1;
uptr size = user_alloc_usable_size(ptr);
#define COMMON_MALLOC_FILL_STATS(zone, stats)
#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \
(void)zone_name; \

View File

@ -164,7 +164,11 @@ uptr user_alloc_usable_size(const void *p) {
if (p == 0)
return 0;
MBlock *b = ctx->metamap.GetBlock((uptr)p);
return b ? b->siz : 0;
if (!b)
return 0; // Not a valid pointer.
if (b->siz == 0)
return 1; // Zero-sized allocations are actually 1 byte.
return b->siz;
}
void invoke_malloc_hook(void *ptr, uptr size) {

View File

@ -6,18 +6,50 @@
#import <Foundation/Foundation.h>
#include <malloc/malloc.h>
int main() {
void *p = malloc(0);
size_t s = malloc_size(p);
printf("size = 0x%zx\n", s);
int some_global;
void describe_zone(void *p) {
malloc_zone_t *z = malloc_zone_from_ptr(p);
if (z)
printf("z = %p\n", z);
else
printf("no zone\n");
if (z) {
fprintf(stderr, "zone = %p\n", z);
} else {
fprintf(stderr, "zone = no zone\n");
}
}
// CHECK: z = 0x{{[0-9a-f]+}}
// CHECK-NOT: no zone
int main() {
void *p;
size_t s;
p = malloc(0x40);
s = malloc_size(p);
fprintf(stderr, "size = 0x%zx\n", s);
// CHECK: size = 0x40
describe_zone(p);
// CHECK: zone = 0x{{[0-9a-f]+}}
p = malloc(0);
s = malloc_size(p);
fprintf(stderr, "size = 0x%zx\n", s);
// CHECK: size = 0x1
describe_zone(p);
// CHECK: zone = 0x{{[0-9a-f]+}}
p = &some_global;
s = malloc_size(p);
fprintf(stderr, "size = 0x%zx\n", s);
// CHECK: size = 0x0
describe_zone(p);
// CHECK: zone = no zone
p = mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
if (!p) {
fprintf(stderr, "mmap failed\n");
exit(1);
}
s = malloc_size(p);
fprintf(stderr, "size = 0x%zx\n", s);
// CHECK: size = 0x0
describe_zone(p);
// CHECK: zone = no zone
}