llvm-project/clang/test/CodeGen/object-size.cpp
George Burgess IV a51c4077c5 Make __builtin_object_size more conservative
r246877 made __builtin_object_size substantially more aggressive with
unknown bases if Type=1 or Type=3, which causes issues when we encounter
code like this:

struct Foo {
  int a;
  char str[1];
};

const char str[] = "Hello, World!";
struct Foo *f = (struct Foo *)malloc(sizeof(*f) + strlen(str));
strcpy(&f->str, str);

__builtin_object_size(&f->str, 1) would hand back 1, which is
technically correct given the type of Foo, but the type of Foo lies to
us about how many bytes are available in this case.

This patch adds support for this "writing off the end" idiom -- we now
answer conservatively when we're given the address of the very last
member in a struct.

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

llvm-svn: 250488
2015-10-16 01:49:01 +00:00

65 lines
2.1 KiB
C++

// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
// C++-specific tests for __builtin_object_size
int gi;
// CHECK-LABEL: define void @_Z5test1v()
void test1() {
// Guaranteeing that our cast removal logic doesn't break more interesting
// cases.
struct A { int a; };
struct B { int b; };
struct C: public A, public B {};
C c;
// CHECK: store i32 8
gi = __builtin_object_size(&c, 0);
// CHECK: store i32 8
gi = __builtin_object_size((A*)&c, 0);
// CHECK: store i32 4
gi = __builtin_object_size((B*)&c, 0);
// CHECK: store i32 8
gi = __builtin_object_size((char*)&c, 0);
// CHECK: store i32 8
gi = __builtin_object_size((char*)(A*)&c, 0);
// CHECK: store i32 4
gi = __builtin_object_size((char*)(B*)&c, 0);
}
// CHECK-LABEL: define void @_Z5test2v()
void test2() {
struct A { char buf[16]; };
struct B : A {};
struct C { int i; B bs[1]; } *c;
// CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
gi = __builtin_object_size(&c->bs[0], 0);
// CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
gi = __builtin_object_size(&c->bs[0], 1);
// CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
gi = __builtin_object_size(&c->bs[0], 2);
// CHECK: store i32 16
gi = __builtin_object_size(&c->bs[0], 3);
// CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
gi = __builtin_object_size((A*)&c->bs[0], 0);
// CHECK: store i32 16
gi = __builtin_object_size((A*)&c->bs[0], 1);
// CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
gi = __builtin_object_size((A*)&c->bs[0], 2);
// CHECK: store i32 16
gi = __builtin_object_size((A*)&c->bs[0], 3);
// CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
gi = __builtin_object_size(&c->bs[0].buf[0], 0);
// CHECK: store i32 16
gi = __builtin_object_size(&c->bs[0].buf[0], 1);
// CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
gi = __builtin_object_size(&c->bs[0].buf[0], 2);
// CHECK: store i32 16
gi = __builtin_object_size(&c->bs[0].buf[0], 3);
}