[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-15 Thread via cfe-commits

https://github.com/DonatNagyE created 
https://github.com/llvm/llvm-project/pull/72402

...to model the results of alloca() and _alloca() calls. Previously it acted as 
if these functions were returning memory from the heap, which led to 
alpha.security.ArrayBoundV2 producing incorrect messages.

>From 703c06e2d6781c45e55d7021929a06cdb0275a14 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= 
Date: Wed, 15 Nov 2023 16:03:22 +0100
Subject: [PATCH] [analyzer] Use AllocaRegion in MallocChecker

...to model the results of alloca() and _alloca() calls. Previously it
acted as if these functions were returning memory from the heap, which
led to alpha.security.ArrayBoundV2 producing incorrect messages.
---
 .../Core/PathSensitive/SValBuilder.h  |  9 ++
 .../Checkers/BuiltinFunctionChecker.cpp   | 29 +--
 .../StaticAnalyzer/Checkers/MallocChecker.cpp | 10 ---
 clang/lib/StaticAnalyzer/Core/SValBuilder.cpp |  8 +
 clang/test/Analysis/malloc.c  | 14 +++--
 clang/test/Analysis/memory-model.cpp  |  2 +-
 .../test/Analysis/out-of-bounds-diagnostics.c |  8 ++---
 7 files changed, 52 insertions(+), 28 deletions(-)

diff --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 692c4384586569e..a64cf7ae4efcb82 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -215,6 +215,15 @@ class SValBuilder {
 const LocationContext *LCtx,
 QualType type, unsigned Count);
 
+  /// Create an SVal representing the result of an alloca()-like call, that is,
+  /// an AllocaRegion on the stack.
+  ///
+  /// After calling this function, it's a good idea to set the extent of the
+  /// returned AllocaRegion.
+  loc::MemRegionVal getAllocaRegionVal(const Expr *E,
+   const LocationContext *LCtx,
+   unsigned Count);
+
   DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(
   SymbolRef parentSymbol, const TypedValueRegion *region);
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index 4a56156de4b27fe..143326c435cf815 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -81,22 +81,21 @@ bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
 
   case Builtin::BI__builtin_alloca_with_align:
   case Builtin::BI__builtin_alloca: {
-// FIXME: Refactor into StoreManager itself?
-MemRegionManager& RM = C.getStoreManager().getRegionManager();
-const AllocaRegion* R =
-  RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext());
-
-// Set the extent of the region in bytes. This enables us to use the
-// SVal of the argument directly. If we save the extent in bits, we
-// cannot represent values like symbol*8.
-auto Size = Call.getArgSVal(0);
-if (Size.isUndef())
-  return true; // Return true to model purity.
-
-state = setDynamicExtent(state, R, Size.castAs(),
- C.getSValBuilder());
+SValBuilder &SVB = C.getSValBuilder();
+const loc::MemRegionVal R =
+SVB.getAllocaRegionVal(CE, C.getLocationContext(), C.blockCount());
 
-C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
+// Set the extent of the region in bytes. This enables us to use the SVal
+// of the argument directly. If we saved the extent in bits, it'd be more
+// difficult to reason about values like symbol*8.
+auto Size = Call.getArgSVal(0);
+if (auto DefSize = Size.getAs()) {
+  state = setDynamicExtent(state, R.getRegion(), *DefSize, SVB);
+  // FIXME: perhaps the following transition should be moved out of the
+  // 'if' to bind an AllocaRegion (with unknown/unspecified size) even in
+  // the unlikely case when the size argument is undefined.
+  C.addTransition(state->BindExpr(CE, LCtx, R));
+}
 return true;
   }
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index d3a4020280616b0..417305e26c41b09 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1731,10 +1731,12 @@ ProgramStateRef 
MallocChecker::MallocMemAux(CheckerContext &C,
   // TODO: We could rewrite post visit to eval call; 'malloc' does not have
   // side effects other than what we model here.
   unsigned Count = C.blockCount();
-  SValBuilder &svalBuilder = C.getSValBuilder();
+  SValBuilder &SVB = C.getSValBuilder();
   const LocationContext *LCtx = C.getPredecessor()->getLocationContext

[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-15 Thread via cfe-commits

llvmbot wrote:



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

@llvm/pr-subscribers-clang

Author: None (DonatNagyE)


Changes

...to model the results of alloca() and _alloca() calls. Previously it acted as 
if these functions were returning memory from the heap, which led to 
alpha.security.ArrayBoundV2 producing incorrect messages.

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


7 Files Affected:

- (modified) 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h (+9) 
- (modified) clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp 
(+14-15) 
- (modified) clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (+6-4) 
- (modified) clang/lib/StaticAnalyzer/Core/SValBuilder.cpp (+8) 
- (modified) clang/test/Analysis/malloc.c (+12-2) 
- (modified) clang/test/Analysis/memory-model.cpp (+1-1) 
- (modified) clang/test/Analysis/out-of-bounds-diagnostics.c (+2-6) 


``diff
diff --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 692c4384586569e..a64cf7ae4efcb82 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -215,6 +215,15 @@ class SValBuilder {
 const LocationContext *LCtx,
 QualType type, unsigned Count);
 
+  /// Create an SVal representing the result of an alloca()-like call, that is,
+  /// an AllocaRegion on the stack.
+  ///
+  /// After calling this function, it's a good idea to set the extent of the
+  /// returned AllocaRegion.
+  loc::MemRegionVal getAllocaRegionVal(const Expr *E,
+   const LocationContext *LCtx,
+   unsigned Count);
+
   DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(
   SymbolRef parentSymbol, const TypedValueRegion *region);
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index 4a56156de4b27fe..143326c435cf815 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -81,22 +81,21 @@ bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
 
   case Builtin::BI__builtin_alloca_with_align:
   case Builtin::BI__builtin_alloca: {
-// FIXME: Refactor into StoreManager itself?
-MemRegionManager& RM = C.getStoreManager().getRegionManager();
-const AllocaRegion* R =
-  RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext());
-
-// Set the extent of the region in bytes. This enables us to use the
-// SVal of the argument directly. If we save the extent in bits, we
-// cannot represent values like symbol*8.
-auto Size = Call.getArgSVal(0);
-if (Size.isUndef())
-  return true; // Return true to model purity.
-
-state = setDynamicExtent(state, R, Size.castAs(),
- C.getSValBuilder());
+SValBuilder &SVB = C.getSValBuilder();
+const loc::MemRegionVal R =
+SVB.getAllocaRegionVal(CE, C.getLocationContext(), C.blockCount());
 
-C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
+// Set the extent of the region in bytes. This enables us to use the SVal
+// of the argument directly. If we saved the extent in bits, it'd be more
+// difficult to reason about values like symbol*8.
+auto Size = Call.getArgSVal(0);
+if (auto DefSize = Size.getAs()) {
+  state = setDynamicExtent(state, R.getRegion(), *DefSize, SVB);
+  // FIXME: perhaps the following transition should be moved out of the
+  // 'if' to bind an AllocaRegion (with unknown/unspecified size) even in
+  // the unlikely case when the size argument is undefined.
+  C.addTransition(state->BindExpr(CE, LCtx, R));
+}
 return true;
   }
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index d3a4020280616b0..417305e26c41b09 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1731,10 +1731,12 @@ ProgramStateRef 
MallocChecker::MallocMemAux(CheckerContext &C,
   // TODO: We could rewrite post visit to eval call; 'malloc' does not have
   // side effects other than what we model here.
   unsigned Count = C.blockCount();
-  SValBuilder &svalBuilder = C.getSValBuilder();
+  SValBuilder &SVB = C.getSValBuilder();
   const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
-  DefinedSVal RetVal = svalBuilder.getConjuredHeapSymbolVal(CE, LCtx, Count)
-  .castAs();
+  DefinedSVal RetVal =
+  ((Family == AF_Alloca) ? SVB.getAllocaRegionVal(CE, LCtx, Count)
+ : SVB.getConjuredHeapSymbolVal(CE, L

[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-15 Thread Artem Dergachev via cfe-commits

haoNoQ wrote:

Hmm, it really worries me that `MallocChecker` is setting a return value 
outside of `evalCall()`. This can easily lead to conflicts if multiple checkers 
try to do this: `evalCall()` is protected from conflicts (the engine asserts 
that at most one checker evaluates each call) but `checkPostCall()` isn't.

To the best of my knowledge, the only legal way to use `State->BindExpr(...)` 
in a checker is to set the return value in `evalCall()`. Ideally we should have 
an assertion about this ("Environment is unchanged after checker callback 
invocation, unless the callback is a successful `evalCall()`").

https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-15 Thread Artem Dergachev via cfe-commits


@@ -266,13 +266,18 @@ void CheckUseZeroAllocated1(void) {
 }
 
 char CheckUseZeroAllocated2(void) {
+  // FIXME: The return value of `alloca()` is modeled with `AllocaRegion`
+  // instead of `SymbolicRegion`, so the current implementation of
+  // `MallocChecker::checkUseZeroAllocated()` cannot handle it; and we get an
+  // unrelated, but suitable warning from core.uninitialized.UndefReturn.
   char *p = alloca(0);
-  return *p; // expected-warning {{Use of memory allocated with size zero}}
+  return *p; // expected-warning {{Undefined or garbage value returned to 
caller}}

haoNoQ wrote:

So we'd have no warning in case of
```c++
char CheckUseZeroAllocatedAndInitialized(void) {
   char *p = alloca(0);
  *p = 4;
   return *p;
}
```
? Might be worth testing.

(It's probably not hard to fix it as well? It's not like `AllocaRegion` is 
special when it comes to being able to carry dynamic extent?)

https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-16 Thread via cfe-commits


@@ -266,13 +266,18 @@ void CheckUseZeroAllocated1(void) {
 }
 
 char CheckUseZeroAllocated2(void) {
+  // FIXME: The return value of `alloca()` is modeled with `AllocaRegion`
+  // instead of `SymbolicRegion`, so the current implementation of
+  // `MallocChecker::checkUseZeroAllocated()` cannot handle it; and we get an
+  // unrelated, but suitable warning from core.uninitialized.UndefReturn.
   char *p = alloca(0);
-  return *p; // expected-warning {{Use of memory allocated with size zero}}
+  return *p; // expected-warning {{Undefined or garbage value returned to 
caller}}

DonatNagyE wrote:

Ok, I'll test that.

Unfortunately this "allocated with size zero" report is based on the private 
"Symbol -> state enum" map that's maintained by MallocChecker (so it's 
independent of the dynamic extent). I'd guess that switching to dynamic extent 
wouldn't be too difficult and it could simplify the code, but I think that 
belongs to a separate commit.

https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-16 Thread via cfe-commits

DonatNagyE wrote:

> Hmm, it really worries me that `MallocChecker` is setting a return value 
> outside of `evalCall()`. This can easily lead to conflicts if multiple 
> checkers try to do this: `evalCall()` is protected from conflicts (the engine 
> asserts that at most one checker evaluates each call) but `checkPostCall()` 
> isn't.
> 
> To the best of my knowledge, the only legal way to use `State->BindExpr(...)` 
> in a checker is to set the return value in `evalCall()`. Ideally we should 
> have an assertion about this ("Environment is unchanged after checker 
> callback invocation, unless the callback is a successful `evalCall()`").

I agree and there's already a FIXME which suggests moving this modeling step 
into an EvalCall callback. If you feel that this is an important improvement, I 
could create a separate commit that does it.

https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-16 Thread via cfe-commits


@@ -266,13 +266,18 @@ void CheckUseZeroAllocated1(void) {
 }
 
 char CheckUseZeroAllocated2(void) {
+  // FIXME: The return value of `alloca()` is modeled with `AllocaRegion`
+  // instead of `SymbolicRegion`, so the current implementation of
+  // `MallocChecker::checkUseZeroAllocated()` cannot handle it; and we get an
+  // unrelated, but suitable warning from core.uninitialized.UndefReturn.
   char *p = alloca(0);
-  return *p; // expected-warning {{Use of memory allocated with size zero}}
+  return *p; // expected-warning {{Undefined or garbage value returned to 
caller}}

DonatNagyE wrote:

Also note that the report "Use of memory allocated with size zero" is redundant 
with ArrayBoundV2, which detects and reports that the offset (0) is not smaller 
than the extent (also 0). Based on this I'm not sure that it's useful to 
maintain this "size zero" special case.

https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-16 Thread via cfe-commits

https://github.com/DonatNagyE edited 
https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-16 Thread via cfe-commits

https://github.com/DonatNagyE edited 
https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-20 Thread Endre Fülöp via cfe-commits


@@ -81,22 +81,21 @@ bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
 
   case Builtin::BI__builtin_alloca_with_align:
   case Builtin::BI__builtin_alloca: {
-// FIXME: Refactor into StoreManager itself?
-MemRegionManager& RM = C.getStoreManager().getRegionManager();
-const AllocaRegion* R =
-  RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext());
-
-// Set the extent of the region in bytes. This enables us to use the
-// SVal of the argument directly. If we save the extent in bits, we
-// cannot represent values like symbol*8.
-auto Size = Call.getArgSVal(0);
-if (Size.isUndef())
-  return true; // Return true to model purity.
-
-state = setDynamicExtent(state, R, Size.castAs(),
- C.getSValBuilder());
+SValBuilder &SVB = C.getSValBuilder();
+const loc::MemRegionVal R =
+SVB.getAllocaRegionVal(CE, C.getLocationContext(), C.blockCount());
 
-C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
+// Set the extent of the region in bytes. This enables us to use the SVal
+// of the argument directly. If we saved the extent in bits, it'd be more
+// difficult to reason about values like symbol*8.
+auto Size = Call.getArgSVal(0);
+if (auto DefSize = Size.getAs()) {
+  state = setDynamicExtent(state, R.getRegion(), *DefSize, SVB);
+  // FIXME: perhaps the following transition should be moved out of the

gamesh411 wrote:

I would go with first asserting that the Size is DefinedOrUnknown anyway, and 
if we have a crash with a reproducer, then we can add the if and the test case 
for it.

https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-20 Thread Endre Fülöp via cfe-commits

https://github.com/gamesh411 approved this pull request.

LGTM, added two remarks inline, but those can be separate patches as well.

https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-20 Thread Endre Fülöp via cfe-commits

https://github.com/gamesh411 edited 
https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-20 Thread Endre Fülöp via cfe-commits


@@ -266,13 +266,18 @@ void CheckUseZeroAllocated1(void) {
 }
 
 char CheckUseZeroAllocated2(void) {
+  // FIXME: The return value of `alloca()` is modeled with `AllocaRegion`
+  // instead of `SymbolicRegion`, so the current implementation of
+  // `MallocChecker::checkUseZeroAllocated()` cannot handle it; and we get an
+  // unrelated, but suitable warning from core.uninitialized.UndefReturn.
   char *p = alloca(0);
-  return *p; // expected-warning {{Use of memory allocated with size zero}}
+  return *p; // expected-warning {{Undefined or garbage value returned to 
caller}}

gamesh411 wrote:

Even if it is not the real question, what we are to do with the 0-size `alloca` 
calls, but just to highlight some practical concerns, I found these sources:
https://discourse.llvm.org/t/malloc-free-and-alloca-with-zero-size/9284/3
https://stackoverflow.com/questions/8036654/what-does-alloca0-do-and-return-on-various-platforms

So `alloca(0)` sometimes has a special meaning. If we can give more specific 
error messages in these cases, I would prefer to handle those error messages in 
the more specific checker.
Even if ArrayBoundV2 has more user-friendly and mature error reporting (and 
would cover this case strictly speaking), making this more specific checker 
emit better diagnostics as well is something worth considering IMO.

https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-20 Thread via cfe-commits


@@ -266,13 +266,18 @@ void CheckUseZeroAllocated1(void) {
 }
 
 char CheckUseZeroAllocated2(void) {
+  // FIXME: The return value of `alloca()` is modeled with `AllocaRegion`
+  // instead of `SymbolicRegion`, so the current implementation of
+  // `MallocChecker::checkUseZeroAllocated()` cannot handle it; and we get an
+  // unrelated, but suitable warning from core.uninitialized.UndefReturn.
   char *p = alloca(0);
-  return *p; // expected-warning {{Use of memory allocated with size zero}}
+  return *p; // expected-warning {{Undefined or garbage value returned to 
caller}}

DonatNagyE wrote:

It seems that `alloca()` in general and `alloca(0)` in particular can mean many 
things, and I don't think that it's worth to create a specific error message 
because I cannot say anything concrete in it. This is a nonstandard function, 
and while we can model its "basic" behavior, I think that we shouldn't try to 
deal with its corner cases.

https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-20 Thread via cfe-commits
=?utf-8?q?Donát?= Nagy 
Message-ID:
In-Reply-To: 


https://github.com/DonatNagyE updated 
https://github.com/llvm/llvm-project/pull/72402

>From 703c06e2d6781c45e55d7021929a06cdb0275a14 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= 
Date: Wed, 15 Nov 2023 16:03:22 +0100
Subject: [PATCH 1/2] [analyzer] Use AllocaRegion in MallocChecker

...to model the results of alloca() and _alloca() calls. Previously it
acted as if these functions were returning memory from the heap, which
led to alpha.security.ArrayBoundV2 producing incorrect messages.
---
 .../Core/PathSensitive/SValBuilder.h  |  9 ++
 .../Checkers/BuiltinFunctionChecker.cpp   | 29 +--
 .../StaticAnalyzer/Checkers/MallocChecker.cpp | 10 ---
 clang/lib/StaticAnalyzer/Core/SValBuilder.cpp |  8 +
 clang/test/Analysis/malloc.c  | 14 +++--
 clang/test/Analysis/memory-model.cpp  |  2 +-
 .../test/Analysis/out-of-bounds-diagnostics.c |  8 ++---
 7 files changed, 52 insertions(+), 28 deletions(-)

diff --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 692c4384586569e..a64cf7ae4efcb82 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -215,6 +215,15 @@ class SValBuilder {
 const LocationContext *LCtx,
 QualType type, unsigned Count);
 
+  /// Create an SVal representing the result of an alloca()-like call, that is,
+  /// an AllocaRegion on the stack.
+  ///
+  /// After calling this function, it's a good idea to set the extent of the
+  /// returned AllocaRegion.
+  loc::MemRegionVal getAllocaRegionVal(const Expr *E,
+   const LocationContext *LCtx,
+   unsigned Count);
+
   DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(
   SymbolRef parentSymbol, const TypedValueRegion *region);
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index 4a56156de4b27fe..143326c435cf815 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -81,22 +81,21 @@ bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
 
   case Builtin::BI__builtin_alloca_with_align:
   case Builtin::BI__builtin_alloca: {
-// FIXME: Refactor into StoreManager itself?
-MemRegionManager& RM = C.getStoreManager().getRegionManager();
-const AllocaRegion* R =
-  RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext());
-
-// Set the extent of the region in bytes. This enables us to use the
-// SVal of the argument directly. If we save the extent in bits, we
-// cannot represent values like symbol*8.
-auto Size = Call.getArgSVal(0);
-if (Size.isUndef())
-  return true; // Return true to model purity.
-
-state = setDynamicExtent(state, R, Size.castAs(),
- C.getSValBuilder());
+SValBuilder &SVB = C.getSValBuilder();
+const loc::MemRegionVal R =
+SVB.getAllocaRegionVal(CE, C.getLocationContext(), C.blockCount());
 
-C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
+// Set the extent of the region in bytes. This enables us to use the SVal
+// of the argument directly. If we saved the extent in bits, it'd be more
+// difficult to reason about values like symbol*8.
+auto Size = Call.getArgSVal(0);
+if (auto DefSize = Size.getAs()) {
+  state = setDynamicExtent(state, R.getRegion(), *DefSize, SVB);
+  // FIXME: perhaps the following transition should be moved out of the
+  // 'if' to bind an AllocaRegion (with unknown/unspecified size) even in
+  // the unlikely case when the size argument is undefined.
+  C.addTransition(state->BindExpr(CE, LCtx, R));
+}
 return true;
   }
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index d3a4020280616b0..417305e26c41b09 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1731,10 +1731,12 @@ ProgramStateRef 
MallocChecker::MallocMemAux(CheckerContext &C,
   // TODO: We could rewrite post visit to eval call; 'malloc' does not have
   // side effects other than what we model here.
   unsigned Count = C.blockCount();
-  SValBuilder &svalBuilder = C.getSValBuilder();
+  SValBuilder &SVB = C.getSValBuilder();
   const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
-  DefinedSVal RetVal = svalBuilder.getConjuredHeapSymbolVal(CE, LCtx, Count)
-  .castAs();
+  DefinedSVal RetVal =
+  ((Family == AF_Alloca) ?

[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-20 Thread via cfe-commits
=?utf-8?q?Donát?= Nagy 
Message-ID:
In-Reply-To: 



@@ -81,22 +81,21 @@ bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
 
   case Builtin::BI__builtin_alloca_with_align:
   case Builtin::BI__builtin_alloca: {
-// FIXME: Refactor into StoreManager itself?
-MemRegionManager& RM = C.getStoreManager().getRegionManager();
-const AllocaRegion* R =
-  RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext());
-
-// Set the extent of the region in bytes. This enables us to use the
-// SVal of the argument directly. If we save the extent in bits, we
-// cannot represent values like symbol*8.
-auto Size = Call.getArgSVal(0);
-if (Size.isUndef())
-  return true; // Return true to model purity.
-
-state = setDynamicExtent(state, R, Size.castAs(),
- C.getSValBuilder());
+SValBuilder &SVB = C.getSValBuilder();
+const loc::MemRegionVal R =
+SVB.getAllocaRegionVal(CE, C.getLocationContext(), C.blockCount());
 
-C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
+// Set the extent of the region in bytes. This enables us to use the SVal
+// of the argument directly. If we saved the extent in bits, it'd be more
+// difficult to reason about values like symbol*8.
+auto Size = Call.getArgSVal(0);
+if (auto DefSize = Size.getAs()) {
+  state = setDynamicExtent(state, R.getRegion(), *DefSize, SVB);
+  // FIXME: perhaps the following transition should be moved out of the

DonatNagyE wrote:

I checked the situation with an assert and a straightforward testcase, and it 
turns out that currently the `getAs()` always succeeds, because 
`core.CallAndMessage` stops the execution with a bug report when an undefined 
argument is passed to a function. (However, if I disabled this functionality of 
`core.CallAndMessage`, the test -- obviously -- triggered the assertion.)

Based on this, I decided to keep the current defensive check, because I didn't 
want to add a hidden and marginal dependency relationship between these two 
checkers. I know that we may assume that `core` checkers are always on, but 
that doesn't mean that I should hide landmines like `assert(core.CallAndMessage 
is active and works as I assume)` in unrelated checkers.

I updated the comment to explain this situation, and I also moved the 
`addTransition()` call out of the `if` because that's the more logical place 
for that method call and this `supporting fire` from `core.CallAndMessage` 
guarantees that this change won't have unintended side effects (because the 
`if` succeeds in normal operation).

https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-20 Thread via cfe-commits
=?utf-8?q?Donát?= Nagy 
Message-ID:
In-Reply-To: 


https://github.com/DonatNagyE edited 
https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-22 Thread via cfe-commits
=?utf-8?q?Don=C3=A1t?= Nagy 
Message-ID:
In-Reply-To: 


DonatNagyE wrote:

@haoNoQ What do you think about this commit? May I merge it?

https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-23 Thread Gábor Horváth via cfe-commits

Xazax-hun wrote:

I think the original `alloca(0)` warning message might be clearer/easier to 
understand. While it might have platform or compiler dependent meaning, those 
behaviors are non-portable, so I think it is undesirable in most cases and 
people probably want to be notified about it. Regarding binding the return 
value outside of `evalCall`, I think that could be addressed in a separate PR. 
This one does not make the current situation any worse. But the very least we 
should add a FIXME now (and potentially open a ticket), to reduce the chances 
of this getting forgotten.

https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-24 Thread via cfe-commits
=?utf-8?q?Donát?= Nagy 
Message-ID:
In-Reply-To: 


DonatNagyE wrote:

> I think the original `alloca(0)` warning message might be clearer/easier to 
> understand.

The difficulty is that we switch from the `SymbolicRegion` that represents the 
heap allocation to an `AllocaRegion` that doesn't have an associated symbol, 
while the code that produces the warnings about zero-allocated memory areas 
(essentially) maintains a set of _symbols_ that correspond to zero-allocated 
regions (I'd guess that this was implemented before the introduction of dynamic 
extent).

It would be possible to reintroduce the original `alloca(0)` message (while 
keeping the improvement that `alloca` returns an `AllocaRegion` and not a 
`SymbolicRegion` on the heap), but that would require significant refactoring 
(and/or ugly code duplication) and frankly I feel that `alloca` is rare and 
this would be a waste of time.

> While it might have platform or compiler dependent meaning, those behaviors 
> are non-portable, so I think it is undesirable in most cases and people 
> probably want to be notified about it.

I'd say that "non-portable" and "undesirable in most cases" is true for 
_practically all_ applications of `alloca`, not just the `alloca(0)` corner 
case. Experienced programmers who use `alloca` check that their code works with 
_their own particular_ `alloca` and wouldn't want to see generic messages that 
may or may not be relevant for them; while novices ( / projects that don't want 
to deal with `alloca` issues) would be better served by a generic "don't use 
`alloca`, it's platform-specific" warning.

> Regarding binding the return value outside of `evalCall`, I think that could 
> be addressed in a separate PR. This one does not make the current situation 
> any worse. But the very least we should add a FIXME now (and potentially open 
> a ticket), to reduce the chances of this getting forgotten.
> 
> Edit: we already have a TODO, but I think that one does not really do justice 
> to the urgency of the problem, it does not mention that doing bindings in 
> checkers outside of `evalCall` is not a good idea.

I'll spice up that TODO note; and after merging this commit I could start 
working on fixing it.

https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-24 Thread via cfe-commits
=?utf-8?q?Donát?= Nagy ,
=?utf-8?q?Donát?= Nagy 
Message-ID:
In-Reply-To: 


https://github.com/DonatNagyE updated 
https://github.com/llvm/llvm-project/pull/72402

>From 703c06e2d6781c45e55d7021929a06cdb0275a14 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= 
Date: Wed, 15 Nov 2023 16:03:22 +0100
Subject: [PATCH 1/3] [analyzer] Use AllocaRegion in MallocChecker

...to model the results of alloca() and _alloca() calls. Previously it
acted as if these functions were returning memory from the heap, which
led to alpha.security.ArrayBoundV2 producing incorrect messages.
---
 .../Core/PathSensitive/SValBuilder.h  |  9 ++
 .../Checkers/BuiltinFunctionChecker.cpp   | 29 +--
 .../StaticAnalyzer/Checkers/MallocChecker.cpp | 10 ---
 clang/lib/StaticAnalyzer/Core/SValBuilder.cpp |  8 +
 clang/test/Analysis/malloc.c  | 14 +++--
 clang/test/Analysis/memory-model.cpp  |  2 +-
 .../test/Analysis/out-of-bounds-diagnostics.c |  8 ++---
 7 files changed, 52 insertions(+), 28 deletions(-)

diff --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 692c4384586569e..a64cf7ae4efcb82 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -215,6 +215,15 @@ class SValBuilder {
 const LocationContext *LCtx,
 QualType type, unsigned Count);
 
+  /// Create an SVal representing the result of an alloca()-like call, that is,
+  /// an AllocaRegion on the stack.
+  ///
+  /// After calling this function, it's a good idea to set the extent of the
+  /// returned AllocaRegion.
+  loc::MemRegionVal getAllocaRegionVal(const Expr *E,
+   const LocationContext *LCtx,
+   unsigned Count);
+
   DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(
   SymbolRef parentSymbol, const TypedValueRegion *region);
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index 4a56156de4b27fe..143326c435cf815 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -81,22 +81,21 @@ bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
 
   case Builtin::BI__builtin_alloca_with_align:
   case Builtin::BI__builtin_alloca: {
-// FIXME: Refactor into StoreManager itself?
-MemRegionManager& RM = C.getStoreManager().getRegionManager();
-const AllocaRegion* R =
-  RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext());
-
-// Set the extent of the region in bytes. This enables us to use the
-// SVal of the argument directly. If we save the extent in bits, we
-// cannot represent values like symbol*8.
-auto Size = Call.getArgSVal(0);
-if (Size.isUndef())
-  return true; // Return true to model purity.
-
-state = setDynamicExtent(state, R, Size.castAs(),
- C.getSValBuilder());
+SValBuilder &SVB = C.getSValBuilder();
+const loc::MemRegionVal R =
+SVB.getAllocaRegionVal(CE, C.getLocationContext(), C.blockCount());
 
-C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
+// Set the extent of the region in bytes. This enables us to use the SVal
+// of the argument directly. If we saved the extent in bits, it'd be more
+// difficult to reason about values like symbol*8.
+auto Size = Call.getArgSVal(0);
+if (auto DefSize = Size.getAs()) {
+  state = setDynamicExtent(state, R.getRegion(), *DefSize, SVB);
+  // FIXME: perhaps the following transition should be moved out of the
+  // 'if' to bind an AllocaRegion (with unknown/unspecified size) even in
+  // the unlikely case when the size argument is undefined.
+  C.addTransition(state->BindExpr(CE, LCtx, R));
+}
 return true;
   }
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index d3a4020280616b0..417305e26c41b09 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1731,10 +1731,12 @@ ProgramStateRef 
MallocChecker::MallocMemAux(CheckerContext &C,
   // TODO: We could rewrite post visit to eval call; 'malloc' does not have
   // side effects other than what we model here.
   unsigned Count = C.blockCount();
-  SValBuilder &svalBuilder = C.getSValBuilder();
+  SValBuilder &SVB = C.getSValBuilder();
   const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
-  DefinedSVal RetVal = svalBuilder.getConjuredHeapSymbolVal(CE, LCtx, Count)
-  .castAs();
+  DefinedSVal RetVal =
+ 

[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-28 Thread Balazs Benics via cfe-commits
=?utf-8?q?Donát?= Nagy ,
=?utf-8?q?Donát?= Nagy 
Message-ID:
In-Reply-To: 


https://github.com/steakhal approved this pull request.

Overall, I'm in favor of this change.
On the other hand, I'd urge for not to regress on the diagnostics.
To me, `alloca` is like a VLA; which is prone to misuses, thus the edge-cases 
count there (esp. if tainted).

https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-28 Thread via cfe-commits
=?utf-8?q?Donát?= Nagy ,
=?utf-8?q?Donát?= Nagy 
Message-ID:
In-Reply-To: 


DonatNagyE wrote:

I'm merging this commit in its current shape because even if I'd reimplement a 
warning for the "use of `alloc(0)`", I'd do it in a separate commit.

I thought about potential approaches to implement this "use of zero-allocated" 
warning for the `AllocaRegion`s and it seems to be troublesome, so I lean 
towards not doing it.

https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Use AllocaRegion in MallocChecker (PR #72402)

2023-11-28 Thread via cfe-commits
=?utf-8?q?Donát?= Nagy ,
=?utf-8?q?Donát?= Nagy 
Message-ID:
In-Reply-To: 


https://github.com/DonatNagyE closed 
https://github.com/llvm/llvm-project/pull/72402
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits