Author: Timm Baeder Date: 2024-11-21T15:53:11+01:00 New Revision: 685e41e7774386b78c9527ebf70d3552aef383d7
URL: https://github.com/llvm/llvm-project/commit/685e41e7774386b78c9527ebf70d3552aef383d7 DIFF: https://github.com/llvm/llvm-project/commit/685e41e7774386b78c9527ebf70d3552aef383d7.diff LOG: [clang][ExprConst] Reject field access with nullptr base (#113885) Reject them if the base is null, not only if the entire pointer is null. Fixes #113821 Added: Modified: clang/docs/ReleaseNotes.rst clang/lib/AST/ExprConstant.cpp clang/test/CXX/expr/expr.const/p2-0x.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 084be14952cfa3..8c81de341937ca 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -148,6 +148,17 @@ C++ Specific Potentially Breaking Changes // Now diagnoses with an error. void f(int& i [[clang::lifetimebound]]); +- Clang now rejects all field accesses on null pointers in constant expressions. The following code + used to work but will now be rejected: + + .. code-block:: c++ + + struct S { int a; int b; }; + constexpr const int *p = &((S*)nullptr)->b; + + Previously, this code was erroneously accepted. + + ABI Changes in This Version --------------------------- diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 261de141637020..c6a210459240a8 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -3261,8 +3261,8 @@ static bool HandleLValueDirectBase(EvalInfo &Info, const Expr *E, LValue &Obj, RL = &Info.Ctx.getASTRecordLayout(Derived); } - Obj.getLValueOffset() += RL->getBaseClassOffset(Base); Obj.addDecl(Info, E, Base, /*Virtual*/ false); + Obj.getLValueOffset() += RL->getBaseClassOffset(Base); return true; } @@ -3286,8 +3286,8 @@ static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj, // Find the virtual base class. if (DerivedDecl->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl); - Obj.getLValueOffset() += Layout.getVBaseClassOffset(BaseDecl); Obj.addDecl(Info, E, BaseDecl, /*Virtual*/ true); + Obj.getLValueOffset() += Layout.getVBaseClassOffset(BaseDecl); return true; } @@ -3330,8 +3330,8 @@ static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal, } unsigned I = FD->getFieldIndex(); - LVal.adjustOffset(Info.Ctx.toCharUnitsFromBits(RL->getFieldOffset(I))); LVal.addDecl(Info, E, FD); + LVal.adjustOffset(Info.Ctx.toCharUnitsFromBits(RL->getFieldOffset(I))); return true; } diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp index 767eee1c74f054..67160ba571f33c 100644 --- a/clang/test/CXX/expr/expr.const/p2-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp @@ -188,7 +188,7 @@ namespace UndefinedBehavior { namespace Ptr { struct A {}; - struct B : A { int n; }; + struct B : A { int n; int m; }; B a[3][3]; constexpr B *p = a[0] + 4; // expected-error {{constant expression}} expected-note {{element 4 of array of 3 elements}} B b = {}; @@ -204,6 +204,7 @@ namespace UndefinedBehavior { static_assert((A*)nb == 0, ""); static_assert((B*)na == 0, ""); constexpr const int &nf = nb->n; // expected-error {{constant expression}} expected-note {{cannot access field of null pointer}} + constexpr const int &mf = nb->m; // expected-error {{constant expression}} expected-note {{cannot access field of null pointer}} constexpr const int *np1 = (int*)nullptr + 0; // ok constexpr const int *np2 = &(*(int(*)[4])nullptr)[0]; // ok constexpr const int *np3 = &(*(int(*)[4])nullptr)[2]; // expected-error {{constant expression}} expected-note {{cannot perform pointer arithmetic on null pointer}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits