https://github.com/bozicrHT created https://github.com/llvm/llvm-project/pull/217608
`SValBuilder::getConstantVal()` does not currently handle direct function addresses, as a result, a const function pointer initialized with a function is loaded into `UnknownVal`, preventing the analyzer from resolving and inlining calls through that pointer. Fixes #216983 From 9ef09e0c2a6f72c2ed0ff683c28e610d5fc8ed79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radovan=20Bo=C5=BEi=C4=87?= <[email protected]> Date: Thu, 20 Aug 2026 14:50:13 +0200 Subject: [PATCH] [clang][analyzer] Model function addresses in constant initializers Teach `SValBuilder::getConstantVal()` to represent direct function addresses using the existing `FunctionCodeRegion` SVal. This allows the analyzer to resolve calls through constant function pointers and preserve caller constraints. --- clang/lib/StaticAnalyzer/Core/SValBuilder.cpp | 6 ++ .../test/Analysis/constant-function-pointer.c | 80 +++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 clang/test/Analysis/constant-function-pointer.c diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp index 57c97b2852445..54b4d9cd4dfed 100644 --- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -326,6 +326,12 @@ loc::MemRegionVal SValBuilder::getCXXThis(const CXXRecordDecl *D, std::optional<SVal> SValBuilder::getConstantVal(const Expr *E) { E = E->IgnoreParens(); + if (E->getType()->isFunctionPointerType()) { + if (const auto *FD = + dyn_cast_or_null<FunctionDecl>(E->getReferencedDeclOfCallee())) + return getFunctionPointer(FD); + } + switch (E->getStmtClass()) { // Handle expressions that we treat differently from the AST's constant // evaluator. diff --git a/clang/test/Analysis/constant-function-pointer.c b/clang/test/Analysis/constant-function-pointer.c new file mode 100644 index 0000000000000..dcd12eb1122e9 --- /dev/null +++ b/clang/test/Analysis/constant-function-pointer.c @@ -0,0 +1,80 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection \ +// RUN: -analyze-function=test_function_pointer_forms -verify=forms %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection \ +// RUN: -analyze-function=test_mutable_pointer -verify=mutable %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection \ +// RUN: -analyze-function=test_no_false_positive -verify=fp %s + +void clang_analyzer_checkInlined(int); +void clang_analyzer_eval(int); + +typedef void (*callback)(unsigned); + +static void decay_target(unsigned value) { + clang_analyzer_checkInlined(value == 1); // forms-warning{{TRUE}} +} + +static callback const decayCallback = decay_target; + +static void address_target(unsigned value) { + clang_analyzer_checkInlined(value == 2); // forms-warning{{TRUE}} +} + +static callback const addressCallback = &address_target; + +static void cast_target(unsigned value) { + clang_analyzer_checkInlined(value == 3); // forms-warning{{TRUE}} +} + +static callback const castCallback = (callback)cast_target; + +void test_function_pointer_forms(void) { + clang_analyzer_eval(decayCallback == decay_target); // forms-warning{{TRUE}} + decay_target(1); + + clang_analyzer_eval(addressCallback == address_target); // forms-warning{{TRUE}} + address_target(2); + + clang_analyzer_eval(castCallback == cast_target); // forms-warning{{TRUE}} + castCallback(3); +} + +static callback mutableCallback = decay_target; + +void test_mutable_pointer(void) { + clang_analyzer_eval(mutableCallback == decay_target); // mutable-warning{{UNKNOWN}} +} + +struct St { + int f; +}; + +static struct St sts[4]; + +static void helper(unsigned id) { + struct St *s = 0; + + if (id < 1) + return; + if (id < 5) + s = &sts[id-1]; + else if (id == 5) + return; + + s->f = 60; +} + +static void notify(unsigned id) { + clang_analyzer_checkInlined(id >= 1 && id <= 4); // fp-warning{{TRUE}} + helper(id); +} + +static callback const callbackFn = notify; + +void test_no_false_positive(unsigned id) { + if (id < 1 || id > 4) + return; + + clang_analyzer_eval(callbackFn == notify); // fp-warning{{TRUE}} + callbackFn(id); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
