forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			369 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			369 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
// RUN: %clang_cc1           -triple x86_64-apple-darwin -emit-llvm %s -o - 2>&1 | FileCheck %s
 | 
						|
// RUN: %clang_cc1 -DDYNAMIC -triple x86_64-apple-darwin -emit-llvm %s -o - 2>&1 | FileCheck %s
 | 
						|
 | 
						|
#ifdef DYNAMIC
 | 
						|
#define OBJECT_SIZE_BUILTIN __builtin_dynamic_object_size
 | 
						|
#else
 | 
						|
#define OBJECT_SIZE_BUILTIN __builtin_object_size
 | 
						|
#endif
 | 
						|
 | 
						|
#define NULL ((void *)0)
 | 
						|
 | 
						|
int gi;
 | 
						|
 | 
						|
typedef unsigned long size_t;
 | 
						|
 | 
						|
// CHECK-DAG-RE: define void @my_malloc({{.*}}) #[[MALLOC_ATTR_NUMBER:[0-9]+]]
 | 
						|
// N.B. LLVM's allocsize arguments are base-0, whereas ours are base-1 (for
 | 
						|
// compat with GCC)
 | 
						|
// CHECK-DAG-RE: attributes #[[MALLOC_ATTR_NUMBER]] = {.*allocsize(0).*}
 | 
						|
void *my_malloc(size_t) __attribute__((alloc_size(1)));
 | 
						|
 | 
						|
// CHECK-DAG-RE: define void @my_calloc({{.*}}) #[[CALLOC_ATTR_NUMBER:[0-9]+]]
 | 
						|
// CHECK-DAG-RE: attributes #[[CALLOC_ATTR_NUMBER]] = {.*allocsize(0, 1).*}
 | 
						|
void *my_calloc(size_t, size_t) __attribute__((alloc_size(1, 2)));
 | 
						|
 | 
						|
// CHECK-LABEL: @test1
 | 
						|
void test1() {
 | 
						|
  void *const vp = my_malloc(100);
 | 
						|
  // CHECK: store i32 100
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(vp, 0);
 | 
						|
  // CHECK: store i32 100
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(vp, 1);
 | 
						|
  // CHECK: store i32 100
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(vp, 2);
 | 
						|
  // CHECK: store i32 100
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(vp, 3);
 | 
						|
 | 
						|
  void *const arr = my_calloc(100, 5);
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr, 0);
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr, 1);
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr, 2);
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr, 3);
 | 
						|
 | 
						|
  // CHECK: store i32 100
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(my_malloc(100), 0);
 | 
						|
  // CHECK: store i32 100
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(my_malloc(100), 1);
 | 
						|
  // CHECK: store i32 100
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(my_malloc(100), 2);
 | 
						|
  // CHECK: store i32 100
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(my_malloc(100), 3);
 | 
						|
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(my_calloc(100, 5), 0);
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(my_calloc(100, 5), 1);
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(my_calloc(100, 5), 2);
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(my_calloc(100, 5), 3);
 | 
						|
 | 
						|
  void *const zeroPtr = my_malloc(0);
 | 
						|
  // CHECK: store i32 0
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(zeroPtr, 0);
 | 
						|
  // CHECK: store i32 0
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(my_malloc(0), 0);
 | 
						|
 | 
						|
  void *const zeroArr1 = my_calloc(0, 1);
 | 
						|
  void *const zeroArr2 = my_calloc(1, 0);
 | 
						|
  // CHECK: store i32 0
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(zeroArr1, 0);
 | 
						|
  // CHECK: store i32 0
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(zeroArr2, 0);
 | 
						|
  // CHECK: store i32 0
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(my_calloc(1, 0), 0);
 | 
						|
  // CHECK: store i32 0
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(my_calloc(0, 1), 0);
 | 
						|
}
 | 
						|
 | 
						|
// CHECK-LABEL: @test2
 | 
						|
void test2() {
 | 
						|
  void *const vp = my_malloc(gi);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(vp, 0);
 | 
						|
 | 
						|
  void *const arr1 = my_calloc(gi, 1);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr1, 0);
 | 
						|
 | 
						|
  void *const arr2 = my_calloc(1, gi);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr2, 0);
 | 
						|
}
 | 
						|
 | 
						|
// CHECK-LABEL: @test3
 | 
						|
void test3() {
 | 
						|
  char *const buf = (char *)my_calloc(100, 5);
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(buf, 0);
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(buf, 1);
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(buf, 2);
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(buf, 3);
 | 
						|
}
 | 
						|
 | 
						|
struct Data {
 | 
						|
  int a;
 | 
						|
  int t[10];
 | 
						|
  char pad[3];
 | 
						|
  char end[1];
 | 
						|
};
 | 
						|
 | 
						|
// CHECK-LABEL: @test5
 | 
						|
void test5() {
 | 
						|
  struct Data *const data = my_malloc(sizeof(*data));
 | 
						|
  // CHECK: store i32 48
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(data, 0);
 | 
						|
  // CHECK: store i32 48
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(data, 1);
 | 
						|
  // CHECK: store i32 48
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(data, 2);
 | 
						|
  // CHECK: store i32 48
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(data, 3);
 | 
						|
 | 
						|
  // CHECK: store i32 40
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(&data->t[1], 0);
 | 
						|
  // CHECK: store i32 36
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(&data->t[1], 1);
 | 
						|
  // CHECK: store i32 40
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(&data->t[1], 2);
 | 
						|
  // CHECK: store i32 36
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(&data->t[1], 3);
 | 
						|
 | 
						|
  struct Data *const arr = my_calloc(sizeof(*data), 2);
 | 
						|
  // CHECK: store i32 96
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr, 0);
 | 
						|
  // CHECK: store i32 96
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr, 1);
 | 
						|
  // CHECK: store i32 96
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr, 2);
 | 
						|
  // CHECK: store i32 96
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr, 3);
 | 
						|
 | 
						|
  // CHECK: store i32 88
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(&arr->t[1], 0);
 | 
						|
  // CHECK: store i32 36
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(&arr->t[1], 1);
 | 
						|
  // CHECK: store i32 88
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(&arr->t[1], 2);
 | 
						|
  // CHECK: store i32 36
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(&arr->t[1], 3);
 | 
						|
}
 | 
						|
 | 
						|
// CHECK-LABEL: @test6
 | 
						|
void test6() {
 | 
						|
  // Things that would normally trigger conservative estimates don't need to do
 | 
						|
  // so when we know the source of the allocation.
 | 
						|
  struct Data *const data = my_malloc(sizeof(*data) + 10);
 | 
						|
  // CHECK: store i32 11
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(data->end, 0);
 | 
						|
  // CHECK: store i32 11
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(data->end, 1);
 | 
						|
  // CHECK: store i32 11
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(data->end, 2);
 | 
						|
  // CHECK: store i32 11
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(data->end, 3);
 | 
						|
 | 
						|
  struct Data *const arr = my_calloc(sizeof(*arr) + 5, 3);
 | 
						|
  // AFAICT, GCC treats malloc and calloc identically. So, we should do the
 | 
						|
  // same.
 | 
						|
  //
 | 
						|
  // Additionally, GCC ignores the initial array index when determining whether
 | 
						|
  // we're writing off the end of an alloc_size base. e.g.
 | 
						|
  //   arr[0].end
 | 
						|
  //   arr[1].end
 | 
						|
  //   arr[2].end
 | 
						|
  // ...Are all considered "writing off the end", because there's no way to tell
 | 
						|
  // with high accuracy if the user meant "allocate a single N-byte `Data`",
 | 
						|
  // or "allocate M smaller `Data`s with extra padding".
 | 
						|
 | 
						|
  // CHECK: store i32 112
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr->end, 0);
 | 
						|
  // CHECK: store i32 112
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr->end, 1);
 | 
						|
  // CHECK: store i32 112
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr->end, 2);
 | 
						|
  // CHECK: store i32 112
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr->end, 3);
 | 
						|
 | 
						|
  // CHECK: store i32 112
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr[0].end, 0);
 | 
						|
  // CHECK: store i32 112
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr[0].end, 1);
 | 
						|
  // CHECK: store i32 112
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr[0].end, 2);
 | 
						|
  // CHECK: store i32 112
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr[0].end, 3);
 | 
						|
 | 
						|
  // CHECK: store i32 64
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr[1].end, 0);
 | 
						|
  // CHECK: store i32 64
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr[1].end, 1);
 | 
						|
  // CHECK: store i32 64
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr[1].end, 2);
 | 
						|
  // CHECK: store i32 64
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr[1].end, 3);
 | 
						|
 | 
						|
  // CHECK: store i32 16
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr[2].end, 0);
 | 
						|
  // CHECK: store i32 16
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr[2].end, 1);
 | 
						|
  // CHECK: store i32 16
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr[2].end, 2);
 | 
						|
  // CHECK: store i32 16
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr[2].end, 3);
 | 
						|
}
 | 
						|
 | 
						|
// CHECK-LABEL: @test7
 | 
						|
void test7() {
 | 
						|
  struct Data *const data = my_malloc(sizeof(*data) + 5);
 | 
						|
  // CHECK: store i32 9
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(data->pad, 0);
 | 
						|
  // CHECK: store i32 3
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(data->pad, 1);
 | 
						|
  // CHECK: store i32 9
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(data->pad, 2);
 | 
						|
  // CHECK: store i32 3
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(data->pad, 3);
 | 
						|
}
 | 
						|
 | 
						|
// CHECK-LABEL: @test8
 | 
						|
void test8() {
 | 
						|
  // Non-const pointers aren't currently supported.
 | 
						|
  void *buf = my_calloc(100, 5);
 | 
						|
  // CHECK: @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true, i1
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(buf, 0);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(buf, 1);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(buf, 2);
 | 
						|
  // CHECK: store i32 0
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(buf, 3);
 | 
						|
}
 | 
						|
 | 
						|
// CHECK-LABEL: @test9
 | 
						|
void test9() {
 | 
						|
  // Check to be sure that we unwrap things correctly.
 | 
						|
  short *const buf0 = (my_malloc(100));
 | 
						|
  short *const buf1 = (short*)(my_malloc(100));
 | 
						|
  short *const buf2 = ((short*)(my_malloc(100)));
 | 
						|
 | 
						|
  // CHECK: store i32 100
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(buf0, 0);
 | 
						|
  // CHECK: store i32 100
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(buf1, 0);
 | 
						|
  // CHECK: store i32 100
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(buf2, 0);
 | 
						|
}
 | 
						|
 | 
						|
// CHECK-LABEL: @test10
 | 
						|
void test10() {
 | 
						|
  // Yay overflow
 | 
						|
  short *const arr = my_calloc((size_t)-1 / 2 + 1, 2);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr, 0);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr, 1);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr, 2);
 | 
						|
  // CHECK: store i32 0
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr, 3);
 | 
						|
 | 
						|
  // As an implementation detail, CharUnits can't handle numbers greater than or
 | 
						|
  // equal to 2**63. Realistically, this shouldn't be a problem, but we should
 | 
						|
  // be sure we don't emit crazy results for this case.
 | 
						|
  short *const buf = my_malloc((size_t)-1);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(buf, 0);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(buf, 1);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(buf, 2);
 | 
						|
  // CHECK: store i32 0
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(buf, 3);
 | 
						|
 | 
						|
  short *const arr_big = my_calloc((size_t)-1 / 2 - 1, 2);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr_big, 0);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr_big, 1);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr_big, 2);
 | 
						|
  // CHECK: store i32 0
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr_big, 3);
 | 
						|
}
 | 
						|
 | 
						|
void *my_tiny_malloc(char) __attribute__((alloc_size(1)));
 | 
						|
void *my_tiny_calloc(char, char) __attribute__((alloc_size(1, 2)));
 | 
						|
 | 
						|
// CHECK-LABEL: @test11
 | 
						|
void test11() {
 | 
						|
  void *const vp = my_tiny_malloc(100);
 | 
						|
  // CHECK: store i32 100
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(vp, 0);
 | 
						|
  // CHECK: store i32 100
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(vp, 1);
 | 
						|
  // CHECK: store i32 100
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(vp, 2);
 | 
						|
  // CHECK: store i32 100
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(vp, 3);
 | 
						|
 | 
						|
  // N.B. This causes char overflow, but not size_t overflow, so it should be
 | 
						|
  // supported.
 | 
						|
  void *const arr = my_tiny_calloc(100, 5);
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr, 0);
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr, 1);
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr, 2);
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr, 3);
 | 
						|
}
 | 
						|
 | 
						|
void *my_signed_malloc(long) __attribute__((alloc_size(1)));
 | 
						|
void *my_signed_calloc(long, long) __attribute__((alloc_size(1, 2)));
 | 
						|
 | 
						|
// CHECK-LABEL: @test12
 | 
						|
void test12() {
 | 
						|
  // CHECK: store i32 100
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(my_signed_malloc(100), 0);
 | 
						|
  // CHECK: store i32 500
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(my_signed_calloc(100, 5), 0);
 | 
						|
 | 
						|
  void *const vp = my_signed_malloc(-2);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(vp, 0);
 | 
						|
  // N.B. These get lowered to -1 because the function calls may have
 | 
						|
  // side-effects, and we can't determine the objectsize.
 | 
						|
  // CHECK: store i32 -1
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(my_signed_malloc(-2), 0);
 | 
						|
 | 
						|
  void *const arr1 = my_signed_calloc(-2, 1);
 | 
						|
  void *const arr2 = my_signed_calloc(1, -2);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr1, 0);
 | 
						|
  // CHECK: @llvm.objectsize
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(arr2, 0);
 | 
						|
  // CHECK: store i32 -1
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(my_signed_calloc(1, -2), 0);
 | 
						|
  // CHECK: store i32 -1
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(my_signed_calloc(-2, 1), 0);
 | 
						|
}
 | 
						|
 | 
						|
void *alloc_uchar(unsigned char) __attribute__((alloc_size(1)));
 | 
						|
 | 
						|
// CHECK-LABEL: @test13
 | 
						|
void test13() {
 | 
						|
  // If 128 were incorrectly seen as negative, the result would become -1.
 | 
						|
  // CHECK: store i32 128,
 | 
						|
  gi = OBJECT_SIZE_BUILTIN(alloc_uchar(128), 0);
 | 
						|
}
 |