-
Notifications
You must be signed in to change notification settings - Fork 15k
Closed
Labels
Description
See how these compile to LLVM IR:
unsigned long long f(int *p) {
return __builtin_object_size(p, 2);
}
unsigned long long g(int *p) {
return __builtin_object_size(p, 1);
}
IR:
define i64 @f(ptr %p) {
entry:
%p.addr = alloca ptr, align 8
store ptr %p, ptr %p.addr, align 8
%0 = load ptr, ptr %p.addr, align 8
%1 = call i64 @llvm.objectsize.i64.p0(ptr %0, i1 true, i1 true, i1 false)
ret i64 %1
}
define i64 @g(ptr %p) {
entry:
%p.addr = alloca ptr, align 8
store ptr %p, ptr %p.addr, align 8
%0 = load ptr, ptr %p.addr, align 8
%1 = call i64 @llvm.objectsize.i64.p0(ptr %0, i1 false, i1 true, i1 false)
ret i64 %1
}
gcc's website (https://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html) specifies an interesting semantics:
If there are multiple objects ptr can point to and all of them are known at compile time, the returned number is the maximum of remaining byte counts in those objects if type & 2 is 0 and minimum if nonzero.
The deal is that we don't distinguish between those at the IR level. Optimizations like LowerConstantIntrinsics
are always giving the max.
Maybe it's sufficient to change our semantics to say that it returns a number greater or equal to the number of remaining bytes? I think that's sufficient for the purposes of checking if memcpy is within bounds.