Skip to content

Conversation

vvuksanovic
Copy link
Contributor

@vvuksanovic vvuksanovic commented Aug 28, 2025

Allocations of size zero are usually done intentionally and then reallocated before use.

Fixes #155633

Allocations of size zero are usually done intentionally and then
reallocated before use.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:static analyzer labels Aug 28, 2025
@llvmbot
Copy link
Member

llvmbot commented Aug 28, 2025

@llvm/pr-subscribers-clang-static-analyzer-1

@llvm/pr-subscribers-clang

Author: Vladimir Vuksanovic (vvuksanovic)

Changes

Allocations of size zero are usually done intentionally and then reallocated before use.


Full diff: https://github.com/llvm/llvm-project/pull/155793.diff

8 Files Affected:

  • (modified) clang/lib/Sema/SemaExpr.cpp (+3-1)
  • (modified) clang/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp (+2-2)
  • (modified) clang/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp (+1-1)
  • (modified) clang/test/Analysis/MismatchedDeallocator-checker-test.mm (+2-2)
  • (modified) clang/test/Analysis/NewDelete-checker-test.cpp (-6)
  • (modified) clang/test/Analysis/NewDelete-intersections.mm (-3)
  • (modified) clang/test/Analysis/unix-fns.c (+2-2)
  • (modified) clang/test/Sema/warn-alloc-size.c (+4-7)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index d383544e54329..c65ca09ee12bb 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7841,7 +7841,9 @@ static void CheckSufficientAllocSize(Sema &S, QualType DestType,
     return;
   std::optional<llvm::APInt> AllocSize =
       CE->evaluateBytesReturnedByAllocSizeCall(S.Context);
-  if (!AllocSize)
+  // Allocations of size zero are permitted as a special case. They are usually
+  // done intentionally.
+  if (!AllocSize || AllocSize->isZero())
     return;
   auto Size = CharUnits::fromQuantity(AllocSize->getZExtValue());
 
diff --git a/clang/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp b/clang/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
index fc324c311f82d..b9eb85d6b69fa 100644
--- a/clang/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
+++ b/clang/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_analyze_cc1 -Wno-alloc-size -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete -std=c++11 -verify %s
-// RUN: %clang_analyze_cc1 -Wno-alloc-size -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -verify %s
 
 #include "Inputs/system-header-simulator-for-malloc.h"
 
diff --git a/clang/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp b/clang/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
index 98873409a4fa2..b0cef2591486d 100644
--- a/clang/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
+++ b/clang/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -Wno-alloc-size -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator -std=c++11 -verify %s
 // expected-no-diagnostics
 
 typedef __typeof(sizeof(int)) size_t;
diff --git a/clang/test/Analysis/MismatchedDeallocator-checker-test.mm b/clang/test/Analysis/MismatchedDeallocator-checker-test.mm
index 21cbe86c9726f..ef8b24ba8de32 100644
--- a/clang/test/Analysis/MismatchedDeallocator-checker-test.mm
+++ b/clang/test/Analysis/MismatchedDeallocator-checker-test.mm
@@ -1,5 +1,5 @@
-// RUN: %clang_analyze_cc1 -Wno-alloc-size -analyzer-checker=core,unix.MismatchedDeallocator -fblocks -verify %s
-// RUN: %clang_analyze_cc1 -Wno-alloc-size -analyzer-checker=core,unix.MismatchedDeallocator -fblocks -DTEST_INLINABLE_ALLOCATORS -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.MismatchedDeallocator -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.MismatchedDeallocator -fblocks -DTEST_INLINABLE_ALLOCATORS -verify %s
 
 #include "Inputs/system-header-simulator-objc.h"
 #include "Inputs/system-header-simulator-cxx.h"
diff --git a/clang/test/Analysis/NewDelete-checker-test.cpp b/clang/test/Analysis/NewDelete-checker-test.cpp
index 5ab6e16edf0df..c417b9c2ac97e 100644
--- a/clang/test/Analysis/NewDelete-checker-test.cpp
+++ b/clang/test/Analysis/NewDelete-checker-test.cpp
@@ -1,37 +1,31 @@
 // RUN: %clang_analyze_cc1 -std=c++11 -fblocks %s \
-// RUN:   -Wno-alloc-size \
 // RUN:   -verify=expected,newdelete \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=cplusplus.NewDelete
 //
 // RUN: %clang_analyze_cc1 -DLEAKS -std=c++11 -fblocks %s \
-// RUN:   -Wno-alloc-size \
 // RUN:   -verify=expected,newdelete,leak \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=cplusplus.NewDelete \
 // RUN:   -analyzer-checker=cplusplus.NewDeleteLeaks
 //
 // RUN: %clang_analyze_cc1 -std=c++11 -fblocks -verify %s \
-// RUN:   -Wno-alloc-size \
 // RUN:   -verify=expected,leak \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=cplusplus.NewDeleteLeaks
 //
 // RUN: %clang_analyze_cc1 -std=c++17 -fblocks %s \
-// RUN:   -Wno-alloc-size \
 // RUN:   -verify=expected,newdelete \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=cplusplus.NewDelete
 //
 // RUN: %clang_analyze_cc1 -DLEAKS -std=c++17 -fblocks %s \
-// RUN:   -Wno-alloc-size \
 // RUN:   -verify=expected,newdelete,leak \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=cplusplus.NewDelete \
 // RUN:   -analyzer-checker=cplusplus.NewDeleteLeaks
 //
 // RUN: %clang_analyze_cc1 -std=c++17 -fblocks -verify %s \
-// RUN:   -Wno-alloc-size \
 // RUN:   -verify=expected,leak,inspection \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=cplusplus.NewDeleteLeaks \
diff --git a/clang/test/Analysis/NewDelete-intersections.mm b/clang/test/Analysis/NewDelete-intersections.mm
index dec9c2922cfea..eddfb3294073e 100644
--- a/clang/test/Analysis/NewDelete-intersections.mm
+++ b/clang/test/Analysis/NewDelete-intersections.mm
@@ -1,5 +1,4 @@
 // RUN: %clang_analyze_cc1 -std=c++11 -fblocks %s \
-// RUN:  -Wno-alloc-size \
 // RUN:  -verify=newdelete \
 // RUN:  -analyzer-checker=core \
 // RUN:  -analyzer-checker=cplusplus.NewDelete
@@ -7,13 +6,11 @@
 // leak-no-diagnostics
 
 // RUN: %clang_analyze_cc1 -std=c++11 -DLEAKS -fblocks %s \
-// RUN:   -Wno-alloc-size \
 // RUN:   -verify=leak \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=cplusplus.NewDeleteLeaks
 
 // RUN: %clang_analyze_cc1 -std=c++11 -DLEAKS -fblocks %s \
-// RUN:   -Wno-alloc-size \
 // RUN:   -verify=mismatch \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=unix.MismatchedDeallocator
diff --git a/clang/test/Analysis/unix-fns.c b/clang/test/Analysis/unix-fns.c
index 2a971be2e6023..77894285bcb69 100644
--- a/clang/test/Analysis/unix-fns.c
+++ b/clang/test/Analysis/unix-fns.c
@@ -1,6 +1,6 @@
-// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -Wno-alloc-size -analyzer-checker=core,unix.API,osx.API,optin.portability %s -analyzer-output=plist -analyzer-config faux-bodies=true  -fblocks -verify -o %t.plist
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,unix.API,osx.API,optin.portability %s -analyzer-output=plist -analyzer-config faux-bodies=true  -fblocks -verify -o %t.plist
 // RUN: %normalize_plist <%t.plist | diff -ub %S/Inputs/expected-plists/unix-fns.c.plist -
-// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux -Wno-alloc-size -analyzer-checker=core,unix.API,osx.API,optin.portability %s -analyzer-output=plist -analyzer-config faux-bodies=true  -fblocks -verify -o %t.plist
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux -analyzer-checker=core,unix.API,osx.API,optin.portability %s -analyzer-output=plist -analyzer-config faux-bodies=true  -fblocks -verify -o %t.plist
 // RUN: %normalize_plist <%t.plist | diff -ub %S/Inputs/expected-plists/unix-fns.c.plist -
 // RUN: mkdir -p %t.dir
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.API,osx.API,optin.portability -analyzer-output=html -analyzer-config faux-bodies=true -fblocks -o %t.dir %s
diff --git a/clang/test/Sema/warn-alloc-size.c b/clang/test/Sema/warn-alloc-size.c
index 445b0ba677337..3d403610c46f9 100644
--- a/clang/test/Sema/warn-alloc-size.c
+++ b/clang/test/Sema/warn-alloc-size.c
@@ -1,10 +1,6 @@
 // RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -Walloc-size %s
 struct Foo { int x[10]; };
 
-struct ZeroSize {
-  int flexible_array[];
-};
-
 typedef __typeof__(sizeof(int)) size_t;
 void *my_malloc(size_t) __attribute__((alloc_size(1)));
 void *my_calloc(size_t, size_t) __attribute__((alloc_size(2, 1)));
@@ -42,8 +38,9 @@ void alloc_foo(void) {
                                                           // expected-warning@-1 {{allocation of insufficient size '1' for type 'int' with size '4'}}
   (void)(int *)my_malloc(1);                              // expected-warning {{allocation of insufficient size '1' for type 'int' with size '4'}}
 
-  struct ZeroSize *ptr18 = my_malloc(0); // okay because sizeof(struct ZeroSize) = 0
+  void *funcptr_1 = (void (*)(int))my_malloc(1);
 
-  void *funcptr_1 = (void (*)(int))my_malloc(0); // expected-warning {{allocation of insufficient size '0' for type 'void (int)' with size '1'}}
-  void *funcptr_2 = (void (*)(int))my_malloc(1);
+  // Zero size allocations are assumed to be intentional.
+  int *zero_alloc1 = my_malloc(0);
+  int *zero_alloc2 = (int *)my_malloc(0);
 }

@vvuksanovic
Copy link
Contributor Author

There have been a couple of issues raised about the -Walloc-size diagnostic being emitted for allocations of size zero:

I think it makes sense to add an exception in that case, as it is likely done intentionally and just creates unnecessary diagnostics.

@vvuksanovic
Copy link
Contributor Author

@Fznamznon
Copy link
Contributor

Hi, thanks for the fix. I that is going to fix #155633 , you can also add Fixes #155633 to the PR desc and merging this PR will close the issue automatically.

@earnol
Copy link
Contributor

earnol commented Aug 28, 2025

Your change will prevent diagnostics for all functions: malloc, calloc, realloc.
I think only realloc is unjustified. So, probably, it makes sense to limit this change to realloc only. But the existing version is improvement already.

@vvuksanovic
Copy link
Contributor Author

Your change will prevent diagnostics for all functions: malloc, calloc, realloc. I think only realloc is unjustified. So, probably, it makes to limit this change to realloc only. But the existing version is improvement already.

Yes, that was intentional. I agree about realloc, but in practice I haven't yet seen an incorrect use of malloc(0) reported by this warning. I think it is rare that someone writes that by accident so mostly people who use it intentionally will see this warning.

Also, we don't check for malloc/calloc/realloc functions explicitly, but only check the alloc_size attribute. We can check for realloc explicitly, but then something like my_realloc_wrapper would still get this warning.

I am open to suggestions on the best way to handle this. The same gcc option works like before this patch (and I believe they have the same behavior for realloc), though it is gated behind -Wextra. They do have the -Walloc-zero option which diagnoses all zero-size allocations because that behavior is implementation defined.

@earnol
Copy link
Contributor

earnol commented Aug 28, 2025

I think this functionality is quite useful and created #155636 to expand it. If nobody will be picking it up, i'll probably implement it myself to make it even more useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:static analyzer clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

New option -Walloc-size causes injustified warning.
5 participants