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.

Copy link
Contributor

@alexfh alexfh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for handling this. Looks good!

@vvuksanovic
Copy link
Contributor Author

If there are no alternative suggestions, can someone merge this? I don't have commit access.

@erichkeane erichkeane merged commit 5f38548 into llvm:main Sep 2, 2025
13 checks passed
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.
6 participants