Skip to content

Commit 305e563

Browse files
committed
[Clang][CodeGen] Reuse isNullPointerArithmeticExtension
1 parent 61c7e1d commit 305e563

File tree

7 files changed

+32
-35
lines changed

7 files changed

+32
-35
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3238,6 +3238,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
32383238
}
32393239

32403240
bool isSentinelNullExpr(const Expr *E);
3241+
/// Check whether the underlying base pointer is a constant null.
3242+
bool isUnderlyingBasePointerConstantNull(const Expr *E);
32413243

32423244
/// Get the implementation of the ObjCInterfaceDecl \p D, or nullptr if
32433245
/// none exists.

clang/lib/AST/ASTContext.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3000,6 +3000,13 @@ bool ASTContext::isSentinelNullExpr(const Expr *E) {
30003000
return false;
30013001
}
30023002

3003+
bool ASTContext::isUnderlyingBasePointerConstantNull(const Expr *E) {
3004+
const Expr *UnderlyingBaseExpr = E->IgnoreParens();
3005+
while (auto *BaseMemberExpr = dyn_cast<MemberExpr>(UnderlyingBaseExpr))
3006+
UnderlyingBaseExpr = BaseMemberExpr->getBase()->IgnoreParens();
3007+
return isSentinelNullExpr(UnderlyingBaseExpr);
3008+
}
3009+
30033010
/// Get the implementation of ObjCInterfaceDecl, or nullptr if none
30043011
/// exists.
30053012
ObjCImplementationDecl *ASTContext::getObjCImplementation(ObjCInterfaceDecl *D) {

clang/lib/AST/Expr.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2248,8 +2248,7 @@ bool BinaryOperator::isNullPointerArithmeticExtension(ASTContext &Ctx,
22482248
}
22492249

22502250
// Check that the pointer is a nullptr.
2251-
if (!PExp->IgnoreParenCasts()
2252-
->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
2251+
if (!Ctx.isUnderlyingBasePointerConstantNull(PExp))
22532252
return false;
22542253

22552254
// Check that the pointee type is char-sized.

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4816,13 +4816,6 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
48164816
Base.getBaseInfo(), TBAAAccessInfo());
48174817
}
48184818

4819-
bool CodeGenFunction::isUnderlyingBasePointerConstantNull(const Expr *E) {
4820-
const Expr *UnderlyingBaseExpr = E->IgnoreParens();
4821-
while (auto *BaseMemberExpr = dyn_cast<MemberExpr>(UnderlyingBaseExpr))
4822-
UnderlyingBaseExpr = BaseMemberExpr->getBase()->IgnoreParens();
4823-
return getContext().isSentinelNullExpr(UnderlyingBaseExpr);
4824-
}
4825-
48264819
LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
48274820
if (DeclRefExpr *DRE = tryToConvertMemberExprToDeclRefExpr(*this, E)) {
48284821
EmitIgnoredExpr(E->getBase());
@@ -4834,7 +4827,7 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
48344827
// If so, we do not set inbounds flag for GEP to avoid breaking some
48354828
// old-style offsetof idioms.
48364829
bool IsInBounds = !getLangOpts().PointerOverflowDefined &&
4837-
!isUnderlyingBasePointerConstantNull(BaseExpr);
4830+
!getContext().isUnderlyingBasePointerConstantNull(BaseExpr);
48384831
// If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
48394832
LValue BaseLV;
48404833
if (E->isArrow()) {
@@ -6373,8 +6366,9 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) {
63736366

63746367
LValueBaseInfo BaseInfo;
63756368
TBAAAccessInfo TBAAInfo;
6376-
bool IsInBounds = !getLangOpts().PointerOverflowDefined &&
6377-
!isUnderlyingBasePointerConstantNull(E->getLHS());
6369+
bool IsInBounds =
6370+
!getLangOpts().PointerOverflowDefined &&
6371+
!getContext().isUnderlyingBasePointerConstantNull(E->getLHS());
63786372
Address MemberAddr = EmitCXXMemberDataPointerAddress(
63796373
E, BaseAddr, OffsetV, MPT, IsInBounds, &BaseInfo, &TBAAInfo);
63806374

clang/lib/CodeGen/CGExprScalar.cpp

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4169,11 +4169,16 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
41694169
// The index is not pointer-sized.
41704170
// The pointer type is not byte-sized.
41714171
//
4172-
if (BinaryOperator::isNullPointerArithmeticExtension(CGF.getContext(),
4173-
op.Opcode,
4174-
expr->getLHS(),
4175-
expr->getRHS()))
4176-
return CGF.Builder.CreateIntToPtr(index, pointer->getType());
4172+
// Note that we do not suppress the pointer overflow check in this case.
4173+
if (!CGF.SanOpts.has(SanitizerKind::PointerOverflow) &&
4174+
BinaryOperator::isNullPointerArithmeticExtension(
4175+
CGF.getContext(), op.Opcode, expr->getLHS(), expr->getRHS())) {
4176+
// isUnderlyingBasePointerConstantNull returns true does not indicate that
4177+
// the base pointer is null.
4178+
Value *Base = CGF.Builder.CreatePtrToInt(pointer, index->getType());
4179+
Value *PtrAdd = CGF.Builder.CreateAdd(Base, index, "ptr.add");
4180+
return CGF.Builder.CreateIntToPtr(PtrAdd, pointer->getType());
4181+
}
41774182

41784183
if (width != DL.getIndexTypeSizeInBits(PtrTy)) {
41794184
// Zero-extend or sign-extend the pointer value according to
@@ -4238,16 +4243,7 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
42384243
else
42394244
elemTy = CGF.ConvertTypeForMem(elementType);
42404245

4241-
// Some versions of glibc __PTR_ALIGN macro use idioms that add an index to a
4242-
// null pointer in order to cast the aligned integer value back to a pointer.
4243-
// This is undefined behavior, but we have to add a workaround for it.
4244-
//
4245-
// Unlike the above check `BinaryOperator::isNullPointerArithmeticExtension`,
4246-
// we still generate a GEP with a null-pointer base instead of inttoptr.
4247-
// This means that it's also UB to dereference a pointer created that way.
4248-
if (CGF.getLangOpts().PointerOverflowDefined ||
4249-
(!CGF.SanOpts.has(SanitizerKind::PointerOverflow) &&
4250-
CGF.isUnderlyingBasePointerConstantNull(pointerOperand)))
4246+
if (CGF.getLangOpts().PointerOverflowDefined)
42514247
return CGF.Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
42524248

42534249
return CGF.EmitCheckedInBoundsGEP(

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4559,8 +4559,6 @@ class CodeGenFunction : public CodeGenTypeCache {
45594559
const CXXRecordDecl *RD);
45604560

45614561
bool isPointerKnownNonNull(const Expr *E);
4562-
/// Check whether the underlying base pointer is a constant null.
4563-
bool isUnderlyingBasePointerConstantNull(const Expr *E);
45644562

45654563
/// Create the discriminator from the storage address and the entity hash.
45664564
llvm::Value *EmitPointerAuthBlendDiscriminator(llvm::Value *StorageAddress,

clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1500:.*]] = {{.*}}, i32 1500, i32 15 } }
3333
// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1600:.*]] = {{.*}}, i32 1600, i32 15 } }
3434
// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1700:.*]] = {{.*}}, i32 1700, i32 15 } }
35-
// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1800:.*]] = {{.*}}, i32 1800, i32 19 } }
35+
// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1800:.*]] = {{.*}}, i32 1800, i32 20 } }
3636

3737
#ifdef __cplusplus
3838
extern "C" {
@@ -432,15 +432,16 @@ char *void_ptr(void *base, unsigned long offset) {
432432
return base + offset;
433433
}
434434

435-
int *constant_null_add(unsigned long offset) {
435+
char *constant_null_add(unsigned long offset) {
436436
// CHECK: define{{.*}} ptr @constant_null_add(i64 noundef %[[OFFSET:.*]])
437437
// CHECK-NEXT: [[ENTRY:.*]]:
438438
// CHECK-NEXT: %[[OFFSET_ADDR:.*]] = alloca i64, align 8
439439
// CHECK-NEXT: store i64 %[[OFFSET]], ptr %[[OFFSET_ADDR]], align 8
440440
// CHECK-NEXT: %[[OFFSET_RELOADED:.*]] = load i64, ptr %[[OFFSET_ADDR]], align 8
441-
// CHECK-NOSANITIZE-NEXT: %[[ADD_PTR:.*]] = getelementptr i32, ptr null, i64 %[[OFFSET_RELOADED]]
442-
// CHECK-SANITIZE-NEXT: %[[ADD_PTR:.*]] = getelementptr inbounds nuw i32, ptr null, i64 %[[OFFSET_RELOADED]]
443-
// CHECK-SANITIZE-NEXT: %[[COMPUTED_OFFSET_AGGREGATE:.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 4, i64 %[[OFFSET_RELOADED]]), !nosanitize
441+
// CHECK-NOSANITIZE-NEXT: %[[PTR_ADD:.*]] = add i64 0, %[[OFFSET_RELOADED]]
442+
// CHECK-NOSANITIZE-NEXT: %[[ADD_PTR:.*]] = inttoptr i64 %[[PTR_ADD]] to ptr
443+
// CHECK-SANITIZE-NEXT: %[[ADD_PTR:.*]] = getelementptr inbounds nuw i8, ptr null, i64 %[[OFFSET_RELOADED]]
444+
// CHECK-SANITIZE-NEXT: %[[COMPUTED_OFFSET_AGGREGATE:.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 1, i64 %[[OFFSET_RELOADED]]), !nosanitize
444445
// CHECK-SANITIZE-NEXT: %[[COMPUTED_OFFSET_OVERFLOWED:.*]] = extractvalue { i64, i1 } %[[COMPUTED_OFFSET_AGGREGATE]], 1, !nosanitize
445446
// CHECK-SANITIZE-NEXT: %[[OR_OV:.+]] = or i1 %[[COMPUTED_OFFSET_OVERFLOWED]], false, !nosanitize
446447
// CHECK-SANITIZE-NEXT: %[[COMPUTED_OFFSET:.*]] = extractvalue { i64, i1 } %[[COMPUTED_OFFSET_AGGREGATE]], 0, !nosanitize
@@ -460,7 +461,7 @@ int *constant_null_add(unsigned long offset) {
460461
// CHECK-SANITIZE: [[CONT]]:
461462
// CHECK-NEXT: ret ptr %[[ADD_PTR]]
462463
#line 1800
463-
return (int *)0 + offset;
464+
return (char *)0 + offset;
464465
}
465466

466467
#ifdef __cplusplus

0 commit comments

Comments
 (0)