https://github.com/dmzimmerman updated https://github.com/llvm/llvm-project/pull/219568
>From 1ddc39c9b90563ebd3ce221357d5b421dcfe3257 Mon Sep 17 00:00:00 2001 From: "Daniel M. Zimmerman" <[email protected]> Date: Fri, 28 Aug 2026 12:49:17 -0700 Subject: [PATCH 1/3] [clang][analyzer] Fix false positive in mmap fd constraint on Darwin On Darwin, mmap acccepts a Mach VM tag encoded in the fd argument when MAP_ANON is set, using VM_MAKE_TAG(tag). For some tags, VM_MAKE_TAG produces a large negative signed integer, which causes a false positive with the current Range(-1, IntMax) constraint for fd. Fixed by omitting the fd constraint on Darwin targets, where the set of valid fd values can't be expressed as a simple range. Assisted-by: Claude:claude-4.6-sonnet Signed-off-by: Daniel M. Zimmerman <[email protected]> rdar://185124909 --- .../Checkers/StdLibraryFunctionsChecker.cpp | 33 ++++++++++++++----- clang/test/Analysis/mmap-vm-make-tag.c | 30 +++++++++++++++++ 2 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 clang/test/Analysis/mmap-vm-make-tag.c diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index 3f027025fd25e..556a92911e96c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -41,6 +41,7 @@ //===----------------------------------------------------------------------===// #include "ErrnoModeling.h" +#include "clang/Basic/TargetInfo.h" #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" @@ -2950,15 +2951,29 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( // void *mmap(void *addr, size_t length, int prot, int flags, int fd, // off_t offset); // FIXME: Improve for errno modeling. - addToFunctionSummaryMap( - "mmap", - Signature( - ArgTypes{VoidPtrTy, SizeTyCanonTy, IntTy, IntTy, IntTy, Off_tTy}, - RetType{VoidPtrTy}), - Summary(NoEvalCall) - .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax))) - .ArgConstraint( - ArgumentCondition(4, WithinRange, Range(-1, IntMax)))); + if (ACtx.getTargetInfo().getTriple().isOSDarwin()) { + // On Darwin, MAP_ANON + VM_MAKE_TAG(tag) uses argument 4 (len) for + // the tag, which looks like a large negative signed integer. The + // valid range for fd is not expressible as a simple union of ranges + // so omit the constraint. + addToFunctionSummaryMap("mmap", + Signature(ArgTypes{VoidPtrTy, SizeTyCanonTy, + IntTy, IntTy, IntTy, Off_tTy}, + RetType{VoidPtrTy}), + Summary(NoEvalCall) + .ArgConstraint(ArgumentCondition( + 1, WithinRange, Range(1, SizeMax)))); + } else { + addToFunctionSummaryMap("mmap", + Signature(ArgTypes{VoidPtrTy, SizeTyCanonTy, + IntTy, IntTy, IntTy, Off_tTy}, + RetType{VoidPtrTy}), + Summary(NoEvalCall) + .ArgConstraint(ArgumentCondition( + 1, WithinRange, Range(1, SizeMax))) + .ArgConstraint(ArgumentCondition( + 4, WithinRange, Range(-1, IntMax)))); + } std::optional<QualType> Off64_tTy = lookupTy("off64_t"); // void *mmap64(void *addr, size_t length, int prot, int flags, int fd, diff --git a/clang/test/Analysis/mmap-vm-make-tag.c b/clang/test/Analysis/mmap-vm-make-tag.c new file mode 100644 index 0000000000000..cef5cf0e0b9c9 --- /dev/null +++ b/clang/test/Analysis/mmap-vm-make-tag.c @@ -0,0 +1,30 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=unix.StdCLibraryFunctions \ +// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=true \ +// RUN: -triple arm64-apple-darwin -verify=darwin %s +// RUN: %clang_analyze_cc1 -analyzer-checker=unix.StdCLibraryFunctions \ +// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=true \ +// RUN: -triple x86_64-unknown-linux-gnu -verify=linux %s + +typedef unsigned long size_t; +typedef long off_t; +void *mmap(void *, size_t, int, int, int, off_t); + +#define MAP_PRIVATE 0x0002 +#define MAP_ANON 0x1000 + +// VM_MAKE_TAG on Darwin encodes a Mach VM memory tag in the top 8 bits. +// For tags >= 128 the result is a large negative signed integer. +#define VM_MAKE_TAG(tag) ((int)((unsigned)(tag) << 24)) +#define VM_MEMORY_APPLICATION_SPECIFIC_1 240 + +void test_mmap_vm_make_tag_no_false_positive(void) { + void *p = mmap(0, 4096, 0, MAP_ANON | MAP_PRIVATE, + VM_MAKE_TAG(VM_MEMORY_APPLICATION_SPECIFIC_1), 0); + // linux-warning@-2 {{should be >= -1}} +} + +void test_size_constraint_still_enforced(void) { + void *p = mmap(0, 0, 0, MAP_ANON | MAP_PRIVATE, -1, 0); + // darwin-warning@-1 {{should be > 0}} + // linux-warning@-2 {{should be > 0}} +} >From 32cb5576265416c0605165b3eaa79b4be1123d5f Mon Sep 17 00:00:00 2001 From: "Daniel M. Zimmerman" <[email protected]> Date: Fri, 28 Aug 2026 16:12:26 -0700 Subject: [PATCH 2/3] fix: address review comments --- .../Checkers/StdLibraryFunctionsChecker.cpp | 39 +++++++++---------- clang/test/Analysis/mmap-vm-make-tag.c | 30 -------------- .../test/Analysis/stdlibraryfunction-darwin.c | 31 +++++++++++++++ 3 files changed, 50 insertions(+), 50 deletions(-) delete mode 100644 clang/test/Analysis/mmap-vm-make-tag.c create mode 100644 clang/test/Analysis/stdlibraryfunction-darwin.c diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index 556a92911e96c..34df77c82a102 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -2950,29 +2950,28 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( // void *mmap(void *addr, size_t length, int prot, int flags, int fd, // off_t offset); - // FIXME: Improve for errno modeling. + // FIXME: Improve for errno modeling + auto MmapSignature = Signature( + ArgTypes{VoidPtrTy, SizeTyCanonTy, IntTy, IntTy, IntTy, Off_tTy}, + RetType{VoidPtrTy}); + auto MmapSummaryWithLengthConstraint = + Summary(NoEvalCall) + .ArgConstraint( + ArgumentCondition(1, WithinRange, Range(1, SizeMax))); + if (ACtx.getTargetInfo().getTriple().isOSDarwin()) { // On Darwin, MAP_ANON + VM_MAKE_TAG(tag) uses argument 4 (len) for - // the tag, which looks like a large negative signed integer. The - // valid range for fd is not expressible as a simple union of ranges - // so omit the constraint. - addToFunctionSummaryMap("mmap", - Signature(ArgTypes{VoidPtrTy, SizeTyCanonTy, - IntTy, IntTy, IntTy, Off_tTy}, - RetType{VoidPtrTy}), - Summary(NoEvalCall) - .ArgConstraint(ArgumentCondition( - 1, WithinRange, Range(1, SizeMax)))); + // the tag, which looks like a large negative signed integer. + // The valid range for fd is not expressible as a simple union of + // ranges so we only constrain the length parameter. + addToFunctionSummaryMap("mmap", MmapSignature, + MmapSummaryWithLengthConstraint); } else { - addToFunctionSummaryMap("mmap", - Signature(ArgTypes{VoidPtrTy, SizeTyCanonTy, - IntTy, IntTy, IntTy, Off_tTy}, - RetType{VoidPtrTy}), - Summary(NoEvalCall) - .ArgConstraint(ArgumentCondition( - 1, WithinRange, Range(1, SizeMax))) - .ArgConstraint(ArgumentCondition( - 4, WithinRange, Range(-1, IntMax)))); + // On other platforms, we also constrain the fd parameter (-1 <= fd). + addToFunctionSummaryMap( + "mmap", MmapSignature, + MmapSummaryWithLengthConstraint.ArgConstraint( + ArgumentCondition(4, WithinRange, Range(-1, IntMax)))); } std::optional<QualType> Off64_tTy = lookupTy("off64_t"); diff --git a/clang/test/Analysis/mmap-vm-make-tag.c b/clang/test/Analysis/mmap-vm-make-tag.c deleted file mode 100644 index cef5cf0e0b9c9..0000000000000 --- a/clang/test/Analysis/mmap-vm-make-tag.c +++ /dev/null @@ -1,30 +0,0 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=unix.StdCLibraryFunctions \ -// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=true \ -// RUN: -triple arm64-apple-darwin -verify=darwin %s -// RUN: %clang_analyze_cc1 -analyzer-checker=unix.StdCLibraryFunctions \ -// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=true \ -// RUN: -triple x86_64-unknown-linux-gnu -verify=linux %s - -typedef unsigned long size_t; -typedef long off_t; -void *mmap(void *, size_t, int, int, int, off_t); - -#define MAP_PRIVATE 0x0002 -#define MAP_ANON 0x1000 - -// VM_MAKE_TAG on Darwin encodes a Mach VM memory tag in the top 8 bits. -// For tags >= 128 the result is a large negative signed integer. -#define VM_MAKE_TAG(tag) ((int)((unsigned)(tag) << 24)) -#define VM_MEMORY_APPLICATION_SPECIFIC_1 240 - -void test_mmap_vm_make_tag_no_false_positive(void) { - void *p = mmap(0, 4096, 0, MAP_ANON | MAP_PRIVATE, - VM_MAKE_TAG(VM_MEMORY_APPLICATION_SPECIFIC_1), 0); - // linux-warning@-2 {{should be >= -1}} -} - -void test_size_constraint_still_enforced(void) { - void *p = mmap(0, 0, 0, MAP_ANON | MAP_PRIVATE, -1, 0); - // darwin-warning@-1 {{should be > 0}} - // linux-warning@-2 {{should be > 0}} -} diff --git a/clang/test/Analysis/stdlibraryfunction-darwin.c b/clang/test/Analysis/stdlibraryfunction-darwin.c new file mode 100644 index 0000000000000..55d8c15d72978 --- /dev/null +++ b/clang/test/Analysis/stdlibraryfunction-darwin.c @@ -0,0 +1,31 @@ +// DEFINE: %{analyze} = %clang_analyze_cc1 \ +// DEFINE: -analyzer-checker=core,unix.StdCLibraryFunctions \ +// DEFINE: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=true + +// RUN: %{analyze} -triple arm64-apple-darwin -verify=darwin %s +// RUN: %{analyze} -triple x86_64-unknown-linux-gnu -verify=linux %s + +typedef unsigned long size_t; +typedef long off_t; +void *mmap(void *, size_t, int, int, int, off_t); + +#define MAP_PRIVATE 0x0002 +#define MAP_ANON 0x1000 + +// VM_MAKE_TAG on Darwin encodes a Mach VM memory tag in the top 8 bits. +// For tags >= 128 the result is a large negative signed integer. +#define VM_MAKE_TAG(tag) ((int)((unsigned)(tag) << 24)) +#define VM_MEMORY_APPLICATION_SPECIFIC_1 240 + +void test_mmap_vm_make_tag(void) { + void *p = mmap(0, 4096, 0, MAP_ANON | MAP_PRIVATE, + VM_MAKE_TAG(VM_MEMORY_APPLICATION_SPECIFIC_1), 0); + // darwin-no-warning: no bound restriction on fd parameter on Darwin + // linux-warning@-3 {{The 5th argument to 'mmap' is -268435456 but should be >= -1}} +} + +void test_mmap_size_constraint(void) { + void *p = mmap(0, 0, 0, MAP_ANON | MAP_PRIVATE, -1, 0); + // darwin-warning@-1 {{The 2nd argument to 'mmap' is 0 but should be > 0}} + // linux-warning@-2 {{The 2nd argument to 'mmap' is 0 but should be > 0}} +} >From 133687a112f28b61a586caa2495bb98487c6bbe7 Mon Sep 17 00:00:00 2001 From: "Daniel M. Zimmerman" <[email protected]> Date: Mon, 31 Aug 2026 08:56:09 -0700 Subject: [PATCH 3/3] Update clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Balázs Benics <[email protected]> --- .../lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index 34df77c82a102..f6a6e535f7638 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -2950,7 +2950,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( // void *mmap(void *addr, size_t length, int prot, int flags, int fd, // off_t offset); - // FIXME: Improve for errno modeling + // FIXME: Improve for errno modeling. auto MmapSignature = Signature( ArgTypes{VoidPtrTy, SizeTyCanonTy, IntTy, IntTy, IntTy, Off_tTy}, RetType{VoidPtrTy}); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
