Skip to content

Commit 677b4f0

Browse files
[llvm] Fix behavior of llvm.objectsize in presence of negative offset
When an object is located before it's allocation point, e.g. char a[10]; char* b = a[-3]; If we ask for the maximum amount of memory addressable from `b` through __builtin_object_size(b, 0) It is better to return -1, even if we actually know everything about the allocation point, than to return 0, which we currently do and that leads to sanitizer raising invalid/incorrect diagnostic.
1 parent 10feb40 commit 677b4f0

File tree

3 files changed

+66
-6
lines changed

3 files changed

+66
-6
lines changed

llvm/lib/Analysis/MemoryBuiltins.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,8 +564,13 @@ Value *llvm::getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI) {
564564
static APInt getSizeWithOverflow(const SizeOffsetAPInt &Data) {
565565
APInt Size = Data.Size;
566566
APInt Offset = Data.Offset;
567-
if (Offset.isNegative() || Size.ult(Offset))
568-
return APInt(Size.getBitWidth(), 0);
567+
568+
assert(!Offset.isNegative() &&
569+
"size for a pointer before the allocated object is ambiguous");
570+
571+
if (Size.ult(Offset))
572+
return APInt::getZero(Size.getBitWidth());
573+
569574
return Size - Offset;
570575
}
571576

@@ -749,6 +754,13 @@ OffsetSpan ObjectSizeOffsetVisitor::computeImpl(Value *V) {
749754
if (Overflow)
750755
ORT.After = APInt();
751756
}
757+
758+
// We end up pointing on a location that's outside of the original object.
759+
// This is UB, and we'd rather return an empty location then.
760+
if (ORT.knownBefore() && ORT.Before.isNegative()) {
761+
ORT.Before = APInt::getZero(ORT.Before.getBitWidth());
762+
ORT.After = APInt::getZero(ORT.Before.getBitWidth());
763+
}
752764
return ORT;
753765
}
754766

llvm/test/Transforms/LowerConstantIntrinsics/builtin-object-size-phi.ll

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,40 @@ define dso_local i64 @pick_max_large(i1 %c) local_unnamed_addr {
131131

132132
}
133133

134+
define dso_local i64 @pick_max_one_oob(i1 %c0, i1 %c1) {
135+
; CHECK-LABEL: @pick_max_one_oob(
136+
; CHECK-NEXT: [[P:%.*]] = alloca [2 x i8], align 1
137+
; CHECK-NEXT: br i1 [[C0:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
138+
; CHECK: if.then:
139+
; CHECK-NEXT: [[P_THEN:%.*]] = getelementptr inbounds [2 x i8], ptr [[P]], i64 0, i64 1
140+
; CHECK-NEXT: br label [[IF_END:%.*]]
141+
; CHECK: if.else:
142+
; CHECK-NEXT: [[P_ELSE:%.*]] = getelementptr inbounds [2 x i8], ptr [[P]], i64 0, i64 -1
143+
; CHECK-NEXT: br label [[IF_END]]
144+
; CHECK: if.end:
145+
; CHECK-NEXT: [[P_END:%.*]] = phi ptr [ [[P_ELSE]], [[IF_ELSE]] ], [ [[P_THEN]], [[IF_THEN]] ]
146+
; CHECK-NEXT: [[OBJSIZE:%.*]] = select i1 [[C1:%.*]], i64 1, i64 0
147+
; CHECK-NEXT: ret i64 [[OBJSIZE]]
148+
;
149+
%p = alloca [2 x i8], align 1
150+
br i1 %c0, label %if.then, label %if.else
151+
152+
if.then:
153+
%p.then = getelementptr inbounds [2 x i8], ptr %p, i64 0, i64 1
154+
br label %if.end
155+
156+
if.else:
157+
%p.else = getelementptr inbounds [2 x i8], ptr %p, i64 0, i64 -1
158+
br label %if.end
159+
160+
if.end:
161+
%p.end = phi ptr [%p.else, %if.else], [%p.then, %if.then]
162+
%objsize.max = call i64 @llvm.objectsize.i64.p0(ptr %p.end, i1 false, i1 true, i1 false)
163+
%objsize.min = call i64 @llvm.objectsize.i64.p0(ptr %p.end, i1 true, i1 true, i1 false)
164+
%objsize = select i1 %c1, i64 %objsize.max, i64 %objsize.min
165+
ret i64 %objsize
166+
}
167+
134168

135169
define i64 @pick_negative_offset(i32 %n) {
136170
; CHECK-LABEL: @pick_negative_offset(

llvm/test/Transforms/LowerConstantIntrinsics/objectsize_basic.ll

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,23 @@ define i64 @out_of_bound_gep() {
195195
ret i64 %objsize
196196
}
197197

198-
define i64 @wrapping_gep() {
198+
define i64 @wrapping_gep(i1 %c) {
199199
; CHECK-LABEL: @wrapping_gep(
200200
; CHECK-NEXT: [[OBJ:%.*]] = alloca i8, i64 4, align 1
201+
; CHECK-NEXT: [[SLIDE:%.*]] = getelementptr i8, ptr [[OBJ]], i64 -9223372036854775807
202+
; CHECK-NEXT: [[SLIDE_BIS:%.*]] = getelementptr i8, ptr [[SLIDE]], i64 -9223372036854775808
203+
; CHECK-NEXT: ret i64 3
204+
;
205+
%obj = alloca i8, i64 4
206+
%slide = getelementptr i8, ptr %obj, i64 9223372036854775809
207+
%slide.bis = getelementptr i8, ptr %slide, i64 9223372036854775808
208+
%objsize = call i64 @llvm.objectsize.i64(ptr %slide.bis, i1 false, i1 false, i1 false)
209+
ret i64 %objsize
210+
}
211+
212+
define i64 @wrapping_gep_neg(i1 %c) {
213+
; CHECK-LABEL: @wrapping_gep_neg(
214+
; CHECK-NEXT: [[OBJ:%.*]] = alloca i8, i64 4, align 1
201215
; CHECK-NEXT: [[SLIDE:%.*]] = getelementptr i8, ptr [[OBJ]], i64 9223372036854775807
202216
; CHECK-NEXT: [[SLIDE_BIS:%.*]] = getelementptr i8, ptr [[SLIDE]], i64 9223372036854775807
203217
; CHECK-NEXT: ret i64 0
@@ -209,8 +223,8 @@ define i64 @wrapping_gep() {
209223
ret i64 %objsize
210224
}
211225

212-
define i64 @wrapping_gep_neg() {
213-
; CHECK-LABEL: @wrapping_gep_neg(
226+
define i64 @wrapping_gep_large_alloc(i1 %c) {
227+
; CHECK-LABEL: @wrapping_gep_large_alloc(
214228
; CHECK-NEXT: [[OBJ:%.*]] = alloca i8, i64 9223372036854775807, align 1
215229
; CHECK-NEXT: [[SLIDE:%.*]] = getelementptr i8, ptr [[OBJ]], i64 9223372036854775807
216230
; CHECK-NEXT: [[SLIDE_BIS:%.*]] = getelementptr i8, ptr [[SLIDE]], i64 3
@@ -251,7 +265,7 @@ define i64 @large_malloc() {
251265
ret i64 %objsize
252266
}
253267

254-
define i64 @out_of_bound_negative_gep() {
268+
define i64 @out_of_bound_negative_gep(i1 %c) {
255269
; CHECK-LABEL: @out_of_bound_negative_gep(
256270
; CHECK-NEXT: [[OBJ:%.*]] = alloca i8, i32 4, align 1
257271
; CHECK-NEXT: [[SLIDE:%.*]] = getelementptr i8, ptr [[OBJ]], i8 -8

0 commit comments

Comments
 (0)