[clang] fed6db4 - [clang][bytecode] Diagnose dereferencing a null pointer (#149330)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Jul 19 12:39:09 PDT 2025
Author: Timm Baeder
Date: 2025-07-19T21:39:06+02:00
New Revision: fed6db45dfbe10cf1a3dab663e8ceb7e7974d713
URL: https://github.com/llvm/llvm-project/commit/fed6db45dfbe10cf1a3dab663e8ceb7e7974d713
DIFF: https://github.com/llvm/llvm-project/commit/fed6db45dfbe10cf1a3dab663e8ceb7e7974d713.diff
LOG: [clang][bytecode] Diagnose dereferencing a null pointer (#149330)
Added:
Modified:
clang/lib/AST/ByteCode/Compiler.cpp
clang/lib/AST/ByteCode/Interp.h
clang/lib/AST/ByteCode/Opcodes.td
clang/test/AST/ByteCode/complex.cpp
clang/test/AST/ByteCode/const-eval.c
clang/test/AST/ByteCode/cxx11.cpp
clang/test/AST/ByteCode/records.cpp
clang/test/CXX/drs/cwg14xx.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 65ad7caf8913b..952a43a0ecbcf 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -6375,6 +6375,9 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
if (!this->visit(SubExpr))
return false;
+ if (!this->emitCheckNull(E))
+ return false;
+
if (classifyPrim(SubExpr) == PT_Ptr)
return this->emitNarrowPtr(E);
return true;
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index aac519d7c74fd..7ba6e21bd5d82 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1885,6 +1885,16 @@ inline bool Dump(InterpState &S, CodePtr OpPC) {
return true;
}
+inline bool CheckNull(InterpState &S, CodePtr OpPC) {
+ const auto &Ptr = S.Stk.peek<Pointer>();
+ if (Ptr.isZero()) {
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_dereferencing_null);
+ return S.noteUndefinedBehavior();
+ }
+ return true;
+}
+
inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
const Pointer &Ptr) {
Pointer Base = Ptr;
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 804853d29512e..80703ad72d954 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -865,6 +865,7 @@ def CheckNewTypeMismatchArray : Opcode {
def IsConstantContext: Opcode;
def CheckAllocations : Opcode;
+def CheckNull : Opcode;
def BitCastTypeClass : TypeClass {
let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64,
diff --git a/clang/test/AST/ByteCode/complex.cpp b/clang/test/AST/ByteCode/complex.cpp
index 959d759005ef4..be10b3cfa53da 100644
--- a/clang/test/AST/ByteCode/complex.cpp
+++ b/clang/test/AST/ByteCode/complex.cpp
@@ -396,10 +396,9 @@ namespace ComplexConstexpr {
// both-note {{cannot refer to element 3 of array of 2 elements}}
constexpr _Complex float *p = 0;
constexpr float pr = __real *p; // both-error {{constant expr}} \
- // expected-note {{read of dereferenced null pointer}} \
- // ref-note {{dereferencing a null pointer}}
+ // both-note {{dereferencing a null pointer}}
constexpr float pi = __imag *p; // both-error {{constant expr}} \
- // ref-note {{dereferencing a null pointer}}
+ // both-note {{dereferencing a null pointer}}
constexpr const _Complex double *q = &test3 + 1;
constexpr double qr = __real *q; // ref-error {{constant expr}} \
// ref-note {{cannot access real component of pointer past the end}}
diff --git a/clang/test/AST/ByteCode/const-eval.c b/clang/test/AST/ByteCode/const-eval.c
index eab14c08ec809..3e228226ac8c1 100644
--- a/clang/test/AST/ByteCode/const-eval.c
+++ b/clang/test/AST/ByteCode/const-eval.c
@@ -180,6 +180,9 @@ typedef __INTPTR_TYPE__ intptr_t;
const intptr_t A = (intptr_t)(((int*) 0) + 1);
const intptr_t B = (intptr_t)(((char*)0) + 3);
_Static_assert(A > B, "");
+int * GH149500_p = &(*(int *)0x400);
+static const void *GH149500_q = &(*(const struct sysrq_key_op *)0);
+
#else
#error :(
#endif
diff --git a/clang/test/AST/ByteCode/cxx11.cpp b/clang/test/AST/ByteCode/cxx11.cpp
index 55554220b0a8a..378702f9b3620 100644
--- a/clang/test/AST/ByteCode/cxx11.cpp
+++ b/clang/test/AST/ByteCode/cxx11.cpp
@@ -39,9 +39,8 @@ struct S {
constexpr S s = { 5 };
constexpr const int *p = &s.m + 1;
-constexpr const int *np2 = &(*(int(*)[4])nullptr)[0];
-// ref-error at -1 {{constexpr variable 'np2' must be initialized by a constant expression}} \
-// ref-note at -1 {{dereferencing a null pointer is not allowed in a constant expression}}
+constexpr const int *np2 = &(*(int(*)[4])nullptr)[0]; // both-error {{constexpr variable 'np2' must be initialized by a constant expression}} \
+ // both-note {{dereferencing a null pointer is not allowed in a constant expression}}
constexpr int preDec(int x) { // both-error {{never produces a constant expression}}
return --x; // both-note {{subexpression}}
diff --git a/clang/test/AST/ByteCode/records.cpp b/clang/test/AST/ByteCode/records.cpp
index 774fed6189d64..5ca3e2d12e2df 100644
--- a/clang/test/AST/ByteCode/records.cpp
+++ b/clang/test/AST/ByteCode/records.cpp
@@ -1660,11 +1660,9 @@ namespace NullptrCast {
constexpr A *na = nullptr;
constexpr B *nb = nullptr;
constexpr A &ra = *nb; // both-error {{constant expression}} \
- // ref-note {{dereferencing a null pointer}} \
- // expected-note {{cannot access base class of null pointer}}
+ // both-note {{dereferencing a null pointer}}
constexpr B &rb = (B&)*na; // both-error {{constant expression}} \
- // ref-note {{dereferencing a null pointer}} \
- // expected-note {{cannot access derived class of null pointer}}
+ // both-note {{dereferencing a null pointer}}
constexpr bool test() {
auto a = (A*)(B*)nullptr;
diff --git a/clang/test/CXX/drs/cwg14xx.cpp b/clang/test/CXX/drs/cwg14xx.cpp
index 8d39018d8926c..047df171afffa 100644
--- a/clang/test/CXX/drs/cwg14xx.cpp
+++ b/clang/test/CXX/drs/cwg14xx.cpp
@@ -6,6 +6,14 @@
// RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11,since-cxx14,since-cxx20 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11,since-cxx14,since-cxx20 -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++98 %s -verify=expected -fexceptions -fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++11 %s -verify=expected,cxx11-17,since-cxx11, -fexceptions -fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++14 %s -verify=expected,cxx14-17,cxx11-17,since-cxx11,since-cxx14 -fexceptions -fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++17 %s -verify=expected,cxx14-17,cxx11-17,since-cxx11,since-cxx14 -fexceptions -fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++20 %s -verify=expected,since-cxx11,since-cxx14,since-cxx20 -fexceptions -fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11,since-cxx14,since-cxx20 -fexceptions -fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11,since-cxx14,since-cxx20 -fexceptions -fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter
+
namespace cwg1413 { // cwg1413: 12
template<int> struct Check {
typedef int type;
More information about the cfe-commits
mailing list