https://github.com/aaditya8979 updated https://github.com/llvm/llvm-project/pull/227874
>From 72dae6577cd73092ed17ff6d73976a7550b21e86 Mon Sep 17 00:00:00 2001 From: openhands <[email protected]> Date: Thu, 1 Oct 2026 02:28:44 +0530 Subject: [PATCH] [clang][analyzer] Suppress core.NullDereference for offsetof macro pattern Fixes a false positive where the C90-style `offsetof` macro expansion `&(((T*)0)->m)` triggers `DereferenceChecker`. The `ExprEngine` correctly evaluates the `MemberExpr` as a `FieldRegion` on a null base, but we now suppress the diagnostic if the immediate parent operation is `UO_AddrOf`, as no physical memory load occurs. Fixes #221768 --- .../Checkers/DereferenceChecker.cpp | 22 ++++++++++++++++- clang/test/Analysis/offsetof-null-deref.c | 24 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 clang/test/Analysis/offsetof-null-deref.c diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index 979d12f1e967c..4860054dd58f9 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ExprObjC.h" +#include "clang/AST/ParentMap.h" #include "clang/Basic/TargetInfo.h" #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -149,6 +150,26 @@ static const Expr *getDereferenceExpr(const Stmt *S, bool IsBind=false){ bool DereferenceChecker::suppressReport(CheckerContext &C, const Expr *E) const { + // Intercept C90-style offsetof() macro expansion: &(((T*)0)->m) + // The analyzer evaluates the MemberExpr as a FieldRegion on a null base, + // triggering checkLocation. We suppress it if the parent operation is + // UO_AddrOf. + if (const auto *ME = dyn_cast<MemberExpr>(E->IgnoreParenCasts())) { + if (ME->isArrow()) { + const Expr *Base = ME->getBase()->IgnoreParenCasts(); + if (const auto *CE = dyn_cast<CastExpr>(Base)) { + if (CE->getCastKind() == CK_NullToPointer) { + const Stmt *Parent = + C.getStackFrame()->getParentMap().getParentIgnoreParenCasts(E); + if (const auto *UO = dyn_cast_or_null<UnaryOperator>(Parent)) { + if (UO->getOpcode() == UO_AddrOf) + return true; + } + } + } + } + } + // Do not report dereferences on memory that use address space #256, #257, // and #258. Those address spaces are used when dereferencing address spaces // relative to the GS, FS, and SS segments on x86/x86-64 targets. @@ -157,7 +178,6 @@ bool DereferenceChecker::suppressReport(CheckerContext &C, // are defined as an error unless explicitly defined. // See https://clang.llvm.org/docs/LanguageExtensions.html, the section // "X86/X86-64 Language Extensions" - QualType Ty = E->getType(); if (!Ty.hasAddressSpace()) return false; diff --git a/clang/test/Analysis/offsetof-null-deref.c b/clang/test/Analysis/offsetof-null-deref.c new file mode 100644 index 0000000000000..aeb98dd8637d6 --- /dev/null +++ b/clang/test/Analysis/offsetof-null-deref.c @@ -0,0 +1,24 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core.NullDereference %s +// expected-no-diagnostics + +typedef unsigned long size_t; + +struct Point { + int x; + int y; +}; + +#define MY_OFFSETOF(T, m) ((size_t)(&((T*)0)->m)) + +size_t get_y_offset(void) { + return MY_OFFSETOF(struct Point, y); +} + +struct Outer { + int pad; + struct Point pt; +}; + +size_t get_nested_offset(void) { + return MY_OFFSETOF(struct Outer, pt.x); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
