https://github.com/NagyDonat updated 
https://github.com/llvm/llvm-project/pull/237447

From 0f0c9c0af0256813b2ef9ab78f15a68085f468f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <[email protected]>
Date: Sat, 31 Oct 2026 01:14:07 +0100
Subject: [PATCH 1/2] [analyzer] MallocChecker: don't crash on funny funopen
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The method mayFreeAnyEscapedMemoryOrIsModeledExplicitly implemented a
heuristic for handling "funopen", but only checked that the call has at
least 4 arguments before accessing the fifth (index 4) one.

This off-by-one error could cause a crash in the theoretical case when
a system header had a nonstandard 4-argument function named "funopen".
I'm pretty sure that nobody encountered this in the wild since 2012 when
it was added. The bug was noticed by a Claude review of a PR that
touched nearby code; but this change is written by hand.

Reported-by: Balázs Benics <[email protected]>
---
 clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp   |  2 +-
 .../Inputs/system-header-simulator-funny-funopen.h    | 11 +++++++++++
 clang/test/Analysis/malloc-funny-funopen.c            | 11 +++++++++++
 3 files changed, 23 insertions(+), 1 deletion(-)
 create mode 100644 
clang/test/Analysis/Inputs/system-header-simulator-funny-funopen.h
 create mode 100644 clang/test/Analysis/malloc-funny-funopen.c

diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index ccd8e4efabcce2..ee83afb8ab5457 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -3830,7 +3830,7 @@ bool 
MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
   // but it will not if closefn is not specified.
   // Currently, we do not inspect the 'closefn' function (PR12101).
   if (FName == "funopen")
-    if (Call->getNumArgs() >= 4 && Call->getArgSVal(4).isConstant(0))
+    if (Call->getNumArgs() >= 5 && Call->getArgSVal(4).isConstant(0))
       return false;
 
   // Do not warn on pointers passed to 'setbuf' when used with std streams,
diff --git a/clang/test/Analysis/Inputs/system-header-simulator-funny-funopen.h 
b/clang/test/Analysis/Inputs/system-header-simulator-funny-funopen.h
new file mode 100644
index 00000000000000..efbaa28b159928
--- /dev/null
+++ b/clang/test/Analysis/Inputs/system-header-simulator-funny-funopen.h
@@ -0,0 +1,11 @@
+#pragma clang system_header
+
+// A non-standard function named "funopen" with four parameters:
+void funopen(int *, int *, int *, int *);
+
+// Note that standard funopen() has five parameters:
+//FILE *funopen(const void *cookie,
+//              int (*readfn)(void *, char *, int),
+//              int (*writefn)(void *, const char *, int),
+//              off_t (*seekfn)(void *, off_t, int),
+//              int (*closefn)(void *));
diff --git a/clang/test/Analysis/malloc-funny-funopen.c 
b/clang/test/Analysis/malloc-funny-funopen.c
new file mode 100644
index 00000000000000..8e9dd0060712e8
--- /dev/null
+++ b/clang/test/Analysis/malloc-funny-funopen.c
@@ -0,0 +1,11 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=unix.Malloc -verify %s
+#include "Inputs/system-header-simulator-funny-funopen.h"
+
+// expected-no-diagnostics
+
+// Standard funopen() has 5 parameters; but if a system header contained a
+// nonstandard declaration with only 4 parameters, then calling that used to
+// trigger an assertion failure through MallocChecker.
+void use_funny_funopen(int *a, int *b, int *c, int *d) {
+  funopen(a, b, c, d); // no-crash
+}

From b7fdb11f35003c1f163e5b937e07b91c200d8d83 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <[email protected]>
Date: Mon, 2 Nov 2026 13:12:30 +0100
Subject: [PATCH 2/2] Use split-file instead of single-use system header
 simulator

---
 .../system-header-simulator-funny-funopen.h   | 11 -------
 clang/test/Analysis/malloc-funny-funopen.c    | 29 +++++++++++++++----
 2 files changed, 24 insertions(+), 16 deletions(-)
 delete mode 100644 
clang/test/Analysis/Inputs/system-header-simulator-funny-funopen.h

diff --git a/clang/test/Analysis/Inputs/system-header-simulator-funny-funopen.h 
b/clang/test/Analysis/Inputs/system-header-simulator-funny-funopen.h
deleted file mode 100644
index efbaa28b159928..00000000000000
--- a/clang/test/Analysis/Inputs/system-header-simulator-funny-funopen.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma clang system_header
-
-// A non-standard function named "funopen" with four parameters:
-void funopen(int *, int *, int *, int *);
-
-// Note that standard funopen() has five parameters:
-//FILE *funopen(const void *cookie,
-//              int (*readfn)(void *, char *, int),
-//              int (*writefn)(void *, const char *, int),
-//              off_t (*seekfn)(void *, off_t, int),
-//              int (*closefn)(void *));
diff --git a/clang/test/Analysis/malloc-funny-funopen.c 
b/clang/test/Analysis/malloc-funny-funopen.c
index 8e9dd0060712e8..3d92de9e67aad9 100644
--- a/clang/test/Analysis/malloc-funny-funopen.c
+++ b/clang/test/Analysis/malloc-funny-funopen.c
@@ -1,11 +1,30 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=unix.Malloc -verify %s
-#include "Inputs/system-header-simulator-funny-funopen.h"
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+
+// RUN: %clang_analyze_cc1 -analyzer-checker=unix.Malloc -verify %t/source.c
+
+//--- header.h
+
+#pragma clang system_header
+
+// A non-standard function named "funopen" with four parameters:
+void funopen(int *, int *, int *, int *);
+
+// Note that standard funopen() has five parameters:
+//FILE *funopen(const void *cookie,
+//              int (*readfn)(void *, char *, int),
+//              int (*writefn)(void *, const char *, int),
+//              off_t (*seekfn)(void *, off_t, int),
+//              int (*closefn)(void *));
+
+//--- source.c
+
+#include "header.h"
 
 // expected-no-diagnostics
 
-// Standard funopen() has 5 parameters; but if a system header contained a
-// nonstandard declaration with only 4 parameters, then calling that used to
-// trigger an assertion failure through MallocChecker.
+// This used to trigger an assertion failure through MallocChecker.
 void use_funny_funopen(int *a, int *b, int *c, int *d) {
   funopen(a, b, c, d); // no-crash
 }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to