[clang] [Clang][CodeGen] Check `isUnderlyingBasePointerConstantNull` in `emitPointerArithmetic` (PR #137849)

Yingwei Zheng via cfe-commits cfe-commits at lists.llvm.org
Sun May 4 03:56:22 PDT 2025


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/137849

>From f1db3a540ec1383451955efab62b64ed8d180349 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 30 Apr 2025 01:26:41 +0800
Subject: [PATCH 1/4] [Clang][CodeGen] Check
 `isUnderlyingBasePointerConstantNull` in `emitPointerArithmetic`

---
 clang/lib/CodeGen/CGExprScalar.cpp                   |  3 ++-
 .../test/CodeGen/catch-nullptr-and-nonzero-offset.c  | 12 ++++++++++++
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 8dbbcdaef25d8..d214d2af52563 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -4238,7 +4238,8 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
   else
     elemTy = CGF.ConvertTypeForMem(elementType);
 
-  if (CGF.getLangOpts().PointerOverflowDefined)
+  if (CGF.getLangOpts().PointerOverflowDefined ||
+      CGF.isUnderlyingBasePointerConstantNull(pointerOperand))
     return CGF.Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
 
   return CGF.EmitCheckedInBoundsGEP(
diff --git a/clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c b/clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c
index 63b6db2c2adeb..c5ae3f8bcc368 100644
--- a/clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c
+++ b/clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c
@@ -431,6 +431,18 @@ char *void_ptr(void *base, unsigned long offset) {
   return base + offset;
 }
 
+int *constant_null_add(long offset) {
+  // CHECK: define{{.*}} ptr @constant_null_add(i64 noundef %[[OFFSET:.*]])
+  // CHECK-NEXT: [[ENTRY:.*]]:
+  // CHECK-NEXT:   %[[OFFSET_ADDR:.*]] = alloca i64, align 8
+  // CHECK-NEXT:   store i64 %[[OFFSET]], ptr %[[OFFSET_ADDR]], align 8
+  // CHECK-NEXT:   %[[OFFSET_RELOADED:.*]] = load i64, ptr %[[OFFSET_ADDR]], align 8
+  // CHECK-NEXT:   %[[ADD_PTR:.*]] = getelementptr i32, ptr null, i64 %[[OFFSET_RELOADED]]
+  // CHECK-NEXT:   ret ptr %[[ADD_PTR]]
+#line 1800
+  return (int *)0 + offset;
+}
+
 #ifdef __cplusplus
 }
 #endif

>From 2796472ca05332419cade01afbea08d8f9446d76 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 30 Apr 2025 14:48:54 +0800
Subject: [PATCH 2/4] [Clang][CodeGen] Re-enable ubsan check

---
 clang/lib/CodeGen/CGExprScalar.cpp            |  3 +-
 .../catch-nullptr-and-nonzero-offset.c        | 38 ++++++++++++++-----
 2 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index d214d2af52563..96e48d65e8ace 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -4239,7 +4239,8 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
     elemTy = CGF.ConvertTypeForMem(elementType);
 
   if (CGF.getLangOpts().PointerOverflowDefined ||
-      CGF.isUnderlyingBasePointerConstantNull(pointerOperand))
+      (!CGF.SanOpts.has(SanitizerKind::PointerOverflow) &&
+       CGF.isUnderlyingBasePointerConstantNull(pointerOperand)))
     return CGF.Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
 
   return CGF.EmitCheckedInBoundsGEP(
diff --git a/clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c b/clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c
index c5ae3f8bcc368..338f85f2d2fbd 100644
--- a/clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c
+++ b/clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -x c -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 -x c -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-NOSANITIZE
 // RUN: %clang_cc1 -x c -fsanitize=pointer-overflow -fno-sanitize-recover=pointer-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_pointer_overflow" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE
 // RUN: %clang_cc1 -x c -fsanitize=pointer-overflow -fsanitize-recover=pointer-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_pointer_overflow" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER
 // RUN: %clang_cc1 -x c -fsanitize=pointer-overflow -fsanitize-trap=pointer-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_pointer_overflow" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE
 
-// RUN: %clang_cc1 -x c++ -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 -x c++ -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-NOSANITIZE
 // RUN: %clang_cc1 -x c++ -fsanitize=pointer-overflow -fno-sanitize-recover=pointer-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_pointer_overflow" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE
 // RUN: %clang_cc1 -x c++ -fsanitize=pointer-overflow -fsanitize-recover=pointer-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_pointer_overflow" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER
 // RUN: %clang_cc1 -x c++ -fsanitize=pointer-overflow -fsanitize-trap=pointer-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_pointer_overflow" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE
@@ -32,6 +32,7 @@
 // CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1500:.*]] = {{.*}}, i32 1500, i32 15 } }
 // CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1600:.*]] = {{.*}}, i32 1600, i32 15 } }
 // CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1700:.*]] = {{.*}}, i32 1700, i32 15 } }
+// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1800:.*]] = {{.*}}, i32 1800, i32 19 } }
 
 #ifdef __cplusplus
 extern "C" {
@@ -431,14 +432,33 @@ char *void_ptr(void *base, unsigned long offset) {
   return base + offset;
 }
 
-int *constant_null_add(long offset) {
+int *constant_null_add(unsigned long offset) {
   // CHECK: define{{.*}} ptr @constant_null_add(i64 noundef %[[OFFSET:.*]])
-  // CHECK-NEXT: [[ENTRY:.*]]:
-  // CHECK-NEXT:   %[[OFFSET_ADDR:.*]] = alloca i64, align 8
-  // CHECK-NEXT:   store i64 %[[OFFSET]], ptr %[[OFFSET_ADDR]], align 8
-  // CHECK-NEXT:   %[[OFFSET_RELOADED:.*]] = load i64, ptr %[[OFFSET_ADDR]], align 8
-  // CHECK-NEXT:   %[[ADD_PTR:.*]] = getelementptr i32, ptr null, i64 %[[OFFSET_RELOADED]]
-  // CHECK-NEXT:   ret ptr %[[ADD_PTR]]
+  // CHECK-NEXT:                      [[ENTRY:.*]]:
+  // CHECK-NEXT:                        %[[OFFSET_ADDR:.*]] = alloca i64, align 8
+  // CHECK-NEXT:                        store i64 %[[OFFSET]], ptr %[[OFFSET_ADDR]], align 8
+  // CHECK-NEXT:                        %[[OFFSET_RELOADED:.*]] = load i64, ptr %[[OFFSET_ADDR]], align 8
+  // CHECK-NOSANITIZE-NEXT:             %[[ADD_PTR:.*]] = getelementptr i32, ptr null, i64 %[[OFFSET_RELOADED]]
+  // CHECK-SANITIZE-NEXT:               %[[ADD_PTR:.*]] = getelementptr inbounds nuw i32, ptr null, i64 %[[OFFSET_RELOADED]]
+  // CHECK-SANITIZE-NEXT:               %[[COMPUTED_OFFSET_AGGREGATE:.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 4, i64 %[[OFFSET_RELOADED]]), !nosanitize
+  // CHECK-SANITIZE-NEXT:               %[[COMPUTED_OFFSET_OVERFLOWED:.*]] = extractvalue { i64, i1 } %[[COMPUTED_OFFSET_AGGREGATE]], 1, !nosanitize
+  // CHECK-SANITIZE-NEXT:               %[[OR_OV:.+]] = or i1 %[[COMPUTED_OFFSET_OVERFLOWED]], false, !nosanitize
+  // CHECK-SANITIZE-NEXT:               %[[COMPUTED_OFFSET:.*]] = extractvalue { i64, i1 } %[[COMPUTED_OFFSET_AGGREGATE]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT:               %[[COMPUTED_GEP:.*]] = add i64 0, %[[COMPUTED_OFFSET]], !nosanitize
+  // CHECK-SANITIZE-NEXT:               %[[COMPUTED_GEP_IS_NOT_NULL:.*]] = icmp ne i64 %[[COMPUTED_GEP]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT:               %[[BOTH_POINTERS_ARE_NULL_OR_BOTH_ARE_NONNULL:.*]] = icmp eq i1 false, %[[COMPUTED_GEP_IS_NOT_NULL]], !nosanitize
+  // CHECK-SANITIZE-NEXT:               %[[COMPUTED_OFFSET_DID_NOT_OVERFLOW:.*]] = xor i1 %[[OR_OV]], true, !nosanitize
+  // CHECK-SANITIZE-NEXT:               %[[COMPUTED_GEP_IS_UGE_BASE:.*]] = icmp uge i64 %[[COMPUTED_GEP]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT:               %[[GEP_DID_NOT_OVERFLOW:.*]] = and i1 %[[COMPUTED_GEP_IS_UGE_BASE]], %[[COMPUTED_OFFSET_DID_NOT_OVERFLOW]], !nosanitize
+  // CHECK-SANITIZE-NEXT:               %[[GEP_IS_OKAY:.*]] = and i1 %[[BOTH_POINTERS_ARE_NULL_OR_BOTH_ARE_NONNULL]], %[[GEP_DID_NOT_OVERFLOW]], !nosanitize
+  // CHECK-SANITIZE-NEXT:               br i1 %[[GEP_IS_OKAY]], label %[[CONT:.*]], label %[[HANDLER_POINTER_OVERFLOW:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE:                  [[HANDLER_POINTER_OVERFLOW]]:
+  // CHECK-SANITIZE-NORECOVER-NEXT:     call void @__ubsan_handle_pointer_overflow_abort(ptr @[[LINE_1800]], i64 0, i64 %[[COMPUTED_GEP]])
+  // CHECK-SANITIZE-RECOVER-NEXT:       call void @__ubsan_handle_pointer_overflow(ptr @[[LINE_1800]], i64 0, i64 %[[COMPUTED_GEP]])
+  // CHECK-SANITIZE-TRAP-NEXT:          call void @llvm.ubsantrap(i8 19){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT:   unreachable, !nosanitize
+  // CHECK-SANITIZE:                  [[CONT]]:
+  // CHECK-NEXT:                        ret ptr %[[ADD_PTR]]
 #line 1800
   return (int *)0 + offset;
 }

>From 61c7e1d981d85d6ace4b13ca286b91988675dc13 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 1 May 2025 18:54:58 +0800
Subject: [PATCH 3/4] [Clang][CodeGen] Add comments. NFC.

---
 clang/lib/CodeGen/CGExprScalar.cpp | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 96e48d65e8ace..a9a920b4686f2 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -4238,6 +4238,13 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
   else
     elemTy = CGF.ConvertTypeForMem(elementType);
 
+  // Some versions of glibc __PTR_ALIGN macro use idioms that add an index to a
+  // null pointer in order to cast the aligned integer value back to a pointer.
+  // This is undefined behavior, but we have to add a workaround for it.
+  //
+  // Unlike the above check `BinaryOperator::isNullPointerArithmeticExtension`,
+  // we still generate a GEP with a null-pointer base instead of inttoptr.
+  // This means that it's also UB to dereference a pointer created that way.
   if (CGF.getLangOpts().PointerOverflowDefined ||
       (!CGF.SanOpts.has(SanitizerKind::PointerOverflow) &&
        CGF.isUnderlyingBasePointerConstantNull(pointerOperand)))

>From 305e5636d99bfb6ce34adfd2a8e2c72a003a1b10 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 4 May 2025 18:55:44 +0800
Subject: [PATCH 4/4] [Clang][CodeGen] Reuse `isNullPointerArithmeticExtension`

---
 clang/include/clang/AST/ASTContext.h          |  2 ++
 clang/lib/AST/ASTContext.cpp                  |  7 +++++
 clang/lib/AST/Expr.cpp                        |  3 +--
 clang/lib/CodeGen/CGExpr.cpp                  | 14 +++-------
 clang/lib/CodeGen/CGExprScalar.cpp            | 26 ++++++++-----------
 clang/lib/CodeGen/CodeGenFunction.h           |  2 --
 .../catch-nullptr-and-nonzero-offset.c        | 13 +++++-----
 7 files changed, 32 insertions(+), 35 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 3c78833a3f069..e7ae0cdebe300 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -3238,6 +3238,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
   }
 
   bool isSentinelNullExpr(const Expr *E);
+  /// Check whether the underlying base pointer is a constant null.
+  bool isUnderlyingBasePointerConstantNull(const Expr *E);
 
   /// Get the implementation of the ObjCInterfaceDecl \p D, or nullptr if
   /// none exists.
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index c95e733f30494..3f081629b4e88 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3000,6 +3000,13 @@ bool ASTContext::isSentinelNullExpr(const Expr *E) {
   return false;
 }
 
+bool ASTContext::isUnderlyingBasePointerConstantNull(const Expr *E) {
+  const Expr *UnderlyingBaseExpr = E->IgnoreParens();
+  while (auto *BaseMemberExpr = dyn_cast<MemberExpr>(UnderlyingBaseExpr))
+    UnderlyingBaseExpr = BaseMemberExpr->getBase()->IgnoreParens();
+  return isSentinelNullExpr(UnderlyingBaseExpr);
+}
+
 /// Get the implementation of ObjCInterfaceDecl, or nullptr if none
 /// exists.
 ObjCImplementationDecl *ASTContext::getObjCImplementation(ObjCInterfaceDecl *D) {
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 59c0e47c7c195..243b7587aaebb 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -2248,8 +2248,7 @@ bool BinaryOperator::isNullPointerArithmeticExtension(ASTContext &Ctx,
   }
 
   // Check that the pointer is a nullptr.
-  if (!PExp->IgnoreParenCasts()
-          ->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
+  if (!Ctx.isUnderlyingBasePointerConstantNull(PExp))
     return false;
 
   // Check that the pointee type is char-sized.
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index bba7d1e805f3f..80f822cf5328a 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4816,13 +4816,6 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
                                   Base.getBaseInfo(), TBAAAccessInfo());
 }
 
-bool CodeGenFunction::isUnderlyingBasePointerConstantNull(const Expr *E) {
-  const Expr *UnderlyingBaseExpr = E->IgnoreParens();
-  while (auto *BaseMemberExpr = dyn_cast<MemberExpr>(UnderlyingBaseExpr))
-    UnderlyingBaseExpr = BaseMemberExpr->getBase()->IgnoreParens();
-  return getContext().isSentinelNullExpr(UnderlyingBaseExpr);
-}
-
 LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
   if (DeclRefExpr *DRE = tryToConvertMemberExprToDeclRefExpr(*this, E)) {
     EmitIgnoredExpr(E->getBase());
@@ -4834,7 +4827,7 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
   // If so, we do not set inbounds flag for GEP to avoid breaking some
   // old-style offsetof idioms.
   bool IsInBounds = !getLangOpts().PointerOverflowDefined &&
-                    !isUnderlyingBasePointerConstantNull(BaseExpr);
+                    !getContext().isUnderlyingBasePointerConstantNull(BaseExpr);
   // If this is s.x, emit s as an lvalue.  If it is s->x, emit s as a scalar.
   LValue BaseLV;
   if (E->isArrow()) {
@@ -6373,8 +6366,9 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) {
 
   LValueBaseInfo BaseInfo;
   TBAAAccessInfo TBAAInfo;
-  bool IsInBounds = !getLangOpts().PointerOverflowDefined &&
-                    !isUnderlyingBasePointerConstantNull(E->getLHS());
+  bool IsInBounds =
+      !getLangOpts().PointerOverflowDefined &&
+      !getContext().isUnderlyingBasePointerConstantNull(E->getLHS());
   Address MemberAddr = EmitCXXMemberDataPointerAddress(
       E, BaseAddr, OffsetV, MPT, IsInBounds, &BaseInfo, &TBAAInfo);
 
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index a9a920b4686f2..a15057b1ace16 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -4169,11 +4169,16 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
   //   The index is not pointer-sized.
   //   The pointer type is not byte-sized.
   //
-  if (BinaryOperator::isNullPointerArithmeticExtension(CGF.getContext(),
-                                                       op.Opcode,
-                                                       expr->getLHS(),
-                                                       expr->getRHS()))
-    return CGF.Builder.CreateIntToPtr(index, pointer->getType());
+  // Note that we do not suppress the pointer overflow check in this case.
+  if (!CGF.SanOpts.has(SanitizerKind::PointerOverflow) &&
+      BinaryOperator::isNullPointerArithmeticExtension(
+          CGF.getContext(), op.Opcode, expr->getLHS(), expr->getRHS())) {
+    // isUnderlyingBasePointerConstantNull returns true does not indicate that
+    // the base pointer is null.
+    Value *Base = CGF.Builder.CreatePtrToInt(pointer, index->getType());
+    Value *PtrAdd = CGF.Builder.CreateAdd(Base, index, "ptr.add");
+    return CGF.Builder.CreateIntToPtr(PtrAdd, pointer->getType());
+  }
 
   if (width != DL.getIndexTypeSizeInBits(PtrTy)) {
     // Zero-extend or sign-extend the pointer value according to
@@ -4238,16 +4243,7 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
   else
     elemTy = CGF.ConvertTypeForMem(elementType);
 
-  // Some versions of glibc __PTR_ALIGN macro use idioms that add an index to a
-  // null pointer in order to cast the aligned integer value back to a pointer.
-  // This is undefined behavior, but we have to add a workaround for it.
-  //
-  // Unlike the above check `BinaryOperator::isNullPointerArithmeticExtension`,
-  // we still generate a GEP with a null-pointer base instead of inttoptr.
-  // This means that it's also UB to dereference a pointer created that way.
-  if (CGF.getLangOpts().PointerOverflowDefined ||
-      (!CGF.SanOpts.has(SanitizerKind::PointerOverflow) &&
-       CGF.isUnderlyingBasePointerConstantNull(pointerOperand)))
+  if (CGF.getLangOpts().PointerOverflowDefined)
     return CGF.Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
 
   return CGF.EmitCheckedInBoundsGEP(
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 4c5e8a8a44926..756d94702db4a 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4559,8 +4559,6 @@ class CodeGenFunction : public CodeGenTypeCache {
                                                const CXXRecordDecl *RD);
 
   bool isPointerKnownNonNull(const Expr *E);
-  /// Check whether the underlying base pointer is a constant null.
-  bool isUnderlyingBasePointerConstantNull(const Expr *E);
 
   /// Create the discriminator from the storage address and the entity hash.
   llvm::Value *EmitPointerAuthBlendDiscriminator(llvm::Value *StorageAddress,
diff --git a/clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c b/clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c
index 338f85f2d2fbd..6eee33300ef63 100644
--- a/clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c
+++ b/clang/test/CodeGen/catch-nullptr-and-nonzero-offset.c
@@ -32,7 +32,7 @@
 // CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1500:.*]] = {{.*}}, i32 1500, i32 15 } }
 // CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1600:.*]] = {{.*}}, i32 1600, i32 15 } }
 // CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1700:.*]] = {{.*}}, i32 1700, i32 15 } }
-// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1800:.*]] = {{.*}}, i32 1800, i32 19 } }
+// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_1800:.*]] = {{.*}}, i32 1800, i32 20 } }
 
 #ifdef __cplusplus
 extern "C" {
@@ -432,15 +432,16 @@ char *void_ptr(void *base, unsigned long offset) {
   return base + offset;
 }
 
-int *constant_null_add(unsigned long offset) {
+char *constant_null_add(unsigned long offset) {
   // CHECK: define{{.*}} ptr @constant_null_add(i64 noundef %[[OFFSET:.*]])
   // CHECK-NEXT:                      [[ENTRY:.*]]:
   // CHECK-NEXT:                        %[[OFFSET_ADDR:.*]] = alloca i64, align 8
   // CHECK-NEXT:                        store i64 %[[OFFSET]], ptr %[[OFFSET_ADDR]], align 8
   // CHECK-NEXT:                        %[[OFFSET_RELOADED:.*]] = load i64, ptr %[[OFFSET_ADDR]], align 8
-  // CHECK-NOSANITIZE-NEXT:             %[[ADD_PTR:.*]] = getelementptr i32, ptr null, i64 %[[OFFSET_RELOADED]]
-  // CHECK-SANITIZE-NEXT:               %[[ADD_PTR:.*]] = getelementptr inbounds nuw i32, ptr null, i64 %[[OFFSET_RELOADED]]
-  // CHECK-SANITIZE-NEXT:               %[[COMPUTED_OFFSET_AGGREGATE:.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 4, i64 %[[OFFSET_RELOADED]]), !nosanitize
+  // CHECK-NOSANITIZE-NEXT:             %[[PTR_ADD:.*]] = add i64 0, %[[OFFSET_RELOADED]]
+  // CHECK-NOSANITIZE-NEXT:             %[[ADD_PTR:.*]] = inttoptr i64 %[[PTR_ADD]] to ptr
+  // CHECK-SANITIZE-NEXT:               %[[ADD_PTR:.*]] = getelementptr inbounds nuw i8, ptr null, i64 %[[OFFSET_RELOADED]]
+  // CHECK-SANITIZE-NEXT:               %[[COMPUTED_OFFSET_AGGREGATE:.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 1, i64 %[[OFFSET_RELOADED]]), !nosanitize
   // CHECK-SANITIZE-NEXT:               %[[COMPUTED_OFFSET_OVERFLOWED:.*]] = extractvalue { i64, i1 } %[[COMPUTED_OFFSET_AGGREGATE]], 1, !nosanitize
   // CHECK-SANITIZE-NEXT:               %[[OR_OV:.+]] = or i1 %[[COMPUTED_OFFSET_OVERFLOWED]], false, !nosanitize
   // CHECK-SANITIZE-NEXT:               %[[COMPUTED_OFFSET:.*]] = extractvalue { i64, i1 } %[[COMPUTED_OFFSET_AGGREGATE]], 0, !nosanitize
@@ -460,7 +461,7 @@ int *constant_null_add(unsigned long offset) {
   // CHECK-SANITIZE:                  [[CONT]]:
   // CHECK-NEXT:                        ret ptr %[[ADD_PTR]]
 #line 1800
-  return (int *)0 + offset;
+  return (char *)0 + offset;
 }
 
 #ifdef __cplusplus



More information about the cfe-commits mailing list