174 Commits

Author SHA1 Message Date
Eric Li
a6a6066290
[clang][dataflow] Fix crash when analyzing a coroutine (#85957)
A coroutine function body (`CoroutineBodyStmt`) may have null children,
which causes `isa` to segfault.
2024-03-20 12:45:30 -04:00
martinboehme
b788e4655c
[clang][dataflow] Model assignment to derived class from base. (#85064)
This is a relatively rare case, but

- It's still nice to get this right,
- We can remove the special case for this in
`VisitCXXOperatorCallExpr()` (that
  simply bails out), and
- With this in place, I can avoid having to add a similar special case
in an
  upcoming patch.
2024-03-19 09:22:35 +01:00
martinboehme
27d504998e
[clang][dataflow] Fix getResultObjectLocation() on CXXDefaultArgExpr. (#85072)
This patch includes a test that causes an assertion failure without the
other
changes in this patch.
2024-03-18 13:36:20 +01:00
martinboehme
9b74c43d70
[clang][dataflow] Add context-sensitive test for returning a record by value. (#84317)
I'm making some changes to `Environment::getResultObjectLocation()`,
with the
ultimate goal of eliminating `RecordValue` entirely, and I'd like to
make sure
I don't break this behavior (and I've realized we don't have a test for
it yet).
2024-03-08 08:19:41 +01:00
martinboehme
2d539db246
[clang][dataflow] When analyzing ctors, don't initialize fields of *this with values. (#84164)
This is the constructor's job, and we want to be able to test that it
does this.
2024-03-08 08:19:02 +01:00
martinboehme
128780b06f
[clang][dataflow] Correctly treat empty initializer lists for unions. (#82986)
This fixes a crash introduced by
https://github.com/llvm/llvm-project/pull/82348
but also adds additional handling to make sure that we treat empty
initializer
lists for both unions and structs/classes correctly (see tests added in
this
patch).
2024-03-01 09:27:59 +01:00
Samira Bazuzi
2730a5c68c
[clang][dataflow] Skip array types when handling InitListExprs. (#83013)
Crashes resulted from single-element InitListExprs for arrays with
elements of a record type after #80970.
2024-02-26 10:53:33 -05:00
Samira Bazuzi
c4e94633e8
Revert "[clang][dataflow] Correctly handle InitListExpr of union type." (#82856)
Reverts llvm/llvm-project#82348, which caused crashes when analyzing
empty InitListExprs for unions, e.g.

```cc
union U {
  double double_value;
  int int_value;
};

void target() {
  U value;
  value = {};
}
```

Co-authored-by: Samira Bazuzi <bazuzi@users.noreply.github.com>
2024-02-26 14:23:46 +01:00
martinboehme
4725993f1a
[clang][dataflow] Correctly handle InitListExpr of union type. (#82348) 2024-02-21 10:10:25 +01:00
Yitzhak Mandelbaum
60cb09ba4f
[clang][dataflow] Fix crash on unions introduced in ba279934c6ab09d5394a89d8318651aefd8d565b (#81918)
The commit was itself a crash fix, but inadvertently changed the
behavior for unions, which results in crashes.
2024-02-15 16:19:10 -05:00
Paul Semel
ba279934c6
[dataflow] Fix crash when InitListExpr is not a prvalue (#80970) 2024-02-15 10:59:51 +01:00
Paul Semel
a8fb0dcc41
[dataflow] CXXOperatorCallExpr equal operator might not be a glvalue (#80991)
Although in a normal implementation the assumption is reasonable, it
seems that some esoteric implementation are not returning a T&. This
should be handled correctly and the values be propagated.

---------

Co-authored-by: martinboehme <mboehme@google.com>
2024-02-13 11:39:27 +01:00
Danny Mösch
00e80fbfb9
[NFC] Correct C++ standard names (#81421) 2024-02-11 19:43:34 +01:00
Paul Semel
5c2da289d2
[clang][dataflow] fix assert in Environment::getResultObjectLocation (#79608)
When calling `Environment::getResultObjectLocation` with a
CXXOperatorCallExpr that is a prvalue, we just hit an assert because no
record was ever created.

---------

Co-authored-by: martinboehme <mboehme@google.com>
2024-01-31 17:18:16 +01:00
martinboehme
ccf1e322bd
[clang][dataflow] Process terminator condition within transferCFGBlock(). (#78127)
In particular, it's important that we create the "fallback" atomic at
this point
(which we produce if the transfer function didn't produce a value for
the
expression) so that it is placed in the correct environment.

Previously, we processed the terminator condition in the
`TerminatorVisitor`,
which put the fallback atomic in a copy of the environment that is
produced as
input for the _successor_ block, rather than the environment for the
block
containing the expression for which we produce the fallback atomic.

As a result, we produce different fallback atomics every time we process
the
successor block, and hence we don't have a consistent representation of
the
terminator condition in the flow condition.

This patch includes a test (authored by ymand@) that fails without the
fix.
2024-01-23 10:19:06 +01:00
Yitzhak Mandelbaum
f3dd8f10c7
[clang][dataflow] Make cap on block visits configurable by caller. (#77481)
Previously, we hard-coded the cap on block visits inside the framework.
This
patch enables the caller to specify the cap in the APIs for running an
analysis.
2024-01-22 22:41:48 -05:00
martinboehme
a2caa4929e
[clang][dataflow] Treat comma operator correctly in getResultObjectLocation(). (#78427) 2024-01-22 09:23:06 +01:00
martinboehme
f1226eea52
[clang][dataflow] Consider CXXDefaultInitExpr to be an "original record ctor". (#78423)
The CFG doesn't contain a CFGElement for the
`CXXDefaultInitExpr::getInit()`, so
it makes sense to consider the `CXXDefaultInitExpr` to be the expression
that
originally constructs the object.
2024-01-18 08:59:26 +01:00
martinboehme
1aacdfe473
Revert "[clang][dataflow] Process terminator condition within transferCFGBlock()." (#77895)
Reverts llvm/llvm-project#77750
2024-01-12 09:54:50 +01:00
martinboehme
537bbb4688
[clang][dataflow] Process terminator condition within transferCFGBlock(). (#77750)
In particular, it's important that we create the "fallback" atomic at
this point
(which we produce if the transfer function didn't produce a value for
the
expression) so that it is placed in the correct environment.

Previously, we processed the terminator condition in the
`TerminatorVisitor`,
which put the fallback atomic in a copy of the environment that is
produced as
input for the _successor_ block, rather than the environment for the
block
containing the expression for which we produce the fallback atomic.

As a result, we produce different fallback atomics every time we process
the
successor block, and hence we don't have a consistent representation of
the
terminator condition in the flow condition.

This patch includes a test (authored by ymand@) that fails without the
fix.
2024-01-12 09:20:58 +01:00
martinboehme
ca1034341c
[clang][dataflow] Fix an issue with Environment::getResultObjectLocation(). (#75483)
So far, if there was a chain of record type prvalues,
`getResultObjectLocation()` would assign a different result object
location to
each one. This makes no sense, of course, as all of these prvalues end
up
initializing the same result object.

This patch fixes this by propagating storage locations up through the
entire
chain of prvalues.

The new implementation also has the desirable effect of making it
possible to
make `getResultObjectLocation()` const, which seems appropriate given
that,
logically, it is just an accessor.
2023-12-18 09:10:03 +01:00
martinboehme
5bd643e145
[clang][dataflow] Strengthen widening of boolean values. (#73484)
Before we widen to top, we now check if both values can be proved either
true or
false in their respective environments; if so, widening returns a true
or false
literal. The idea is that we avoid losing information if posssible.

This patch includes a test that fails without this change to widening.

This change does mean that we call the SAT solver in more places, but
this seems
acceptable given the additional precision we gain.

In tests on an internal codebase, the number of SAT solver timeouts we
observe
with Crubit's nullability checker does increase by about 25%. They can
be
brought back to the previous level by doubling the SAT solver work
limit.
2023-11-27 14:55:49 +01:00
Samira Bazuzi
3001d6ddaa
[clang][dataflow] Fix buggy assertion: Compare an unqualified type to an unqualified type. (#71573)
Includes crash-reproducing test case.

---------

Co-authored-by: martinboehme <mboehme@google.com>
2023-11-09 16:57:04 +01:00
martinboehme
6b573f4611
[clang][dataflow] Fix assert-fail when calling assignment operator with by-value parameter. (#71384)
The code assumed that the source parameter of an assignment operator is
always
passed by reference, but it is legal for it to be passed by value.

This patch includes a test that assert-fails without the fix.
2023-11-07 09:48:40 +01:00
martinboehme
526c9b7e37
[clang][nullability] Use proves() and assume() instead of deprecated synonyms. (#70297) 2023-10-30 13:18:57 +01:00
martinboehme
14b039c1dd
[clang][dataflow] Remove declToLocConsistent() assertion. (#69819)
As described [here](https://discourse.llvm.org/t/70086/6), there are
legitimate
non-bug scenarios where two `DeclToLoc` maps to be joined contain
different
storage locations for the same declaration. This patch also adds a test
containing an example of such a situation. (The test fails without the
other
changes in this patch.)

With the assertion removed, the existing logic in `intersectDenseMaps()`
will
remove the corresponding declaration from the joined DeclToLoc map.

We also remove `removeDecl()`'s precondition (that the declaration must
be
associated with a storage location) because this may no longer hold if
the
declaration was previously removed during a join, as described above.
2023-10-24 08:42:30 +02:00
Sam McCall
7338eb561c Reapply "[dataflow] use true/false literals in formulas, rather than variables"
This reverts commit 3353f7dd3d91c9b2b6a15ba9229bee53e0cb8196.

Fixed test bug (unspecified order of arg evaluation)
2023-10-19 11:34:08 +02:00
Yitzhak Mandelbaum
342dca7528
[clang][dataflow] Check for backedges directly (instead of loop statements). (#68923)
Widen on backedge nodes, instead of nodes with a loop statement as
terminator.
This fixes #67834 and a precision loss from assignment in a loop
condition. The
commit contains tests for both of these issues.
2023-10-16 14:07:16 -04:00
Stanislav Gatev
52d0696355
[clang][dataflow] Add support for lambda captures (#68558)
This adds support for copy, ref, and this lambda captures to the core
framework and also adds relevant tests in UncheckedOptionalAccessTest.
2023-10-11 22:18:46 +02:00
martinboehme
834cb919b3
[clang][dataflow] Remove declarations from DeclToLoc when their lifetime ends. (#67300)
After https://reviews.llvm.org/D153273, we're now able to use
`CFGLifetimeEnds`
together with the other CFG options we use.
2023-09-26 08:41:09 +02:00
Douglas Yung
3353f7dd3d Revert "[dataflow] use true/false literals in formulas, rather than variables"
This reverts commit 36bd5bd888f193b70abf43a09bb4fc04cd2a2ff1.

This change is causing a test failure on several build bots:
- https://lab.llvm.org/buildbot/#/builders/139/builds/50255
- https://lab.llvm.org/buildbot/#/builders/216/builds/27735
- https://lab.llvm.org/buildbot/#/builders/247/builds/9334
2023-09-22 11:43:27 -07:00
Sam McCall
36bd5bd888 [dataflow] use true/false literals in formulas, rather than variables
And simplify formulas containing true/false
It's unclear to me how useful this is, it does make formulas more
conveniently self-contained now (we can usefully print them without
carrying around the "true/false" labels)

(while here, simplify !!X to X, too)

Differential Revision: https://reviews.llvm.org/D153485
2023-09-22 17:12:20 +02:00
martinboehme
1d7b59ca8d
[clang][dataflow] Fix two null pointer dereferences in getMemberForAccessor(). (#66742)
The additions to the test trigger crashes without the fixes.
2023-09-19 09:03:20 +02:00
Kinuko Yasuda
03be486ecc
[clang][dataflow] Model the fields that are accessed via inline accessors (#66368)
So that the values that are accessed via such accessors can be analyzed
as a limited version of context-sensitive analysis. We can potentially
do this only when some option is set, but doing additional modeling like
this won't be expensive and intrusive, so we do it by default for now.
2023-09-18 10:46:36 +02:00
martinboehme
0069004856
[clang][dataflow] Add a test for context-sensitive analysis on a self-referential class. (#66359)
The test demonstrates that the `this` pointer seen in the constructor
has the
same value as the address of the variable the object is constructed
into.
2023-09-15 14:31:10 +02:00
Kinuko Yasuda
0612c9b09a
[clang][dataflow] Ignore assignment where base class's operator is used (#66364)
In C++ it seems it is legit to use base class's operator (e.g. `using
Base::operator=`) to perform copy if the base class is the common
ancestor of the source and destination object. In such a case we
shouldn't try to access fields beyond that of the base class, however
such a case seems to be very rare (typical code would implement a copy
constructor instead), and could add complexities, so in this patch we
simply bail if the method operator's parent class is different from the
type of the destination object that this framework recognizes.
2023-09-14 20:45:56 +02:00
martinboehme
e65e94fddc
[clang][dataflow] Rename test target function to target(). (#66195)
Otherwise, the test doesn't actually do anything.
2023-09-13 15:07:44 +02:00
martinboehme
7cf20f156f
[clang][dataflow] Eliminate RecordValue::getChild(). (#65586)
We want to eliminate the `RecordStorageLocation` from `RecordValue` and,
ultimately, eliminate `RecordValue` entirely (see the discussion linked
in the
`RecordValue` class comment). This is one step in that direction.

To eliminate `RecordValue::getChild()`, we also eliminate the last
remaining
caller, namely the `getFieldValue(const RecordValue *, ...)` overload.
Calls
to this overload have been rewritten to use the
`getFieldValue(const RecordStorageLocation *, ...)` overload. Note that
this
also makes the code slightly simpler in many cases.
2023-09-12 09:17:38 +02:00
Tianlan Zhou
057564fec5
Fix some typos in comments: evalute -> evaluate (NFC) (#65906) 2023-09-11 04:11:06 +08:00
Kinuko Yasuda
8e1d2f2f12
[clang][dataflow] Don't crash when BlockToState is called from unreachable path (#65732)
When we call `getEnvironment`, `BlockToState[BlockId]` for the block can
return null even if CFCtx.isBlockReachable(B) returns true if it is
called from a particular block that is marked unreachable to the block.
2023-09-08 10:24:08 -04:00
Yitzhak Mandelbaum
80f0dc3aa4 [clang][dataflow] Unsoundly treat "Unknown" as "Equivalent" in widening.
This change makes widening act the same as equivalence checking. When the
analysis does not provide an answer regarding the equivalence of two distinct
values, the framework treats them as equivalent. This is an unsound choice that
enables convergence.

Differential Revision: https://reviews.llvm.org/D159355
2023-09-07 19:06:35 +00:00
Kinuko Yasuda
f9026cfb76 [clang][dataflow] Fix Record initialization with InitListExpr and inheritances
Usually RecordValues for record objects (e.g. struct) are initialized with
`Environment::createValue()` which internally calls `getObjectFields()` to
collects all fields from the current and base classes, and then filter them
with `ModeledValues` via `DACtx::getModeledFields()` so that the fields that
are actually referenced are modeled.

The consistent set of fields should be initialized when a record is initialized
with an initializer list (InitListExpr), however the existing code's behavior
was different.

Before this patch:
* When a struct is initialized with InitListExpr, its fields are
  initialized based on what is returned by `getFieldsForInitListExpr()`, which
  only collects the direct fields in the current class, but not from the base
  classes. Moreover, if the base classes have their own InitListExpr, values
  that are initialized by their InitListExpr's weren't merged into the
  child objects.

After this patch:
* When a struct is initialized with InitListExpr, it collects and merges the
  fields in the base classes that were initialized by their InitListExpr's.
  The code also asserts that the consistent set of fields are initialized
  with the ModeledFields.

Reviewed By: mboehme

Differential Revision: https://reviews.llvm.org/D159284
2023-09-07 07:37:50 +00:00
martinboehme
c0703eaec1
[clang][dataflow] Emit an error if source code is not compiled as C++. (#65301)
The shape of certain elements of the AST can vary depending on the
langugage.
We currently only support C++.
2023-09-06 10:02:21 +02:00
martinboehme
f470c361d9
[clang][dataflow] Eliminate uses of RecordValue::getChild(). (#65329)
We want to work towards eliminating the `RecordStorageLocation` from
`RecordValue`. These particular uses of `RecordValue::getChild()` can
simply
be replaced with `RecordStorageLocation::getChild()`.
2023-09-06 09:43:05 +02:00
Martin Braenne
37458c66bf [clang][dataflow] Eliminate deprecated DataflowAnalysis constructor.
Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D159261
2023-09-04 07:00:11 +00:00
Kai Luo
09ccc5563e Fix [-Werror,-Wsign-compare] error. NFC. 2023-08-24 07:56:43 +00:00
Martin Braenne
4866a6e1d3 [clang][dataflow] Produce pointer values for callees of member operator calls.
Calls to member operators are a special case in that their callees have pointer
type. The callees of non-operator non-static member functions are not pointers.
See the comments in the code for details.

This issue came up in the Crubit nullability check; the fact that we weren't
modeling the `PointerValue` caused non-convergence.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D158592
2023-08-24 07:12:14 +00:00
Martin Braenne
a1a63d68a4 [clang][dataflow] Add two repros for non-convergence involving pointers in loops.
These are broken out from https://reviews.llvm.org/D156658, which it now seems obvious isn't the right way to solve the non-convergence.

Instead, my plan is to address the non-convergence through pointer value widening, but the exact way this should be implemented is TBD. In the meantime, I think there's value in getting these repros submitted to record the current undesirable behavior.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D158513
2023-08-23 07:03:16 +00:00
Martin Braenne
9ecdbe3855 [clang][dataflow] Rename AggregateStorageLocation to RecordStorageLocation and StructValue to RecordValue.
- Both of these constructs are used to represent structs, classes, and unions;
  Clang uses the collective term "record" for these.

- The term "aggregate" in `AggregateStorageLocation` implies that, at some
  point, the intention may have been to use it also for arrays, but it don't
  think it's possible to use it for arrays. Records and arrays are very
  different and therefore need to be modeled differently. Records have a fixed
  set of named fields, which can have different type; arrays have a variable
  number of elements, but they all have the same type.

- Futhermore, "aggregate" has a very specific meaning in C++
  (https://en.cppreference.com/w/cpp/language/aggregate_initialization).
  Aggregates of class type may not have any user-declared or inherited
  constructors, no private or protected non-static data members, no virtual
  member functions, and so on, but we use `AggregateStorageLocations` to model all objects of class type.

In addition, for consistency, we also rename the following:

- `getAggregateLoc()` (in `RecordValue`, formerly known as `StructValue`) to
  simply `getLoc()`.

- `refreshStructValue()` to `refreshRecordValue()`

We keep the old names around as deprecated synonyms to enable clients to be migrated to the new names.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D156788
2023-08-01 20:29:40 +00:00
Martin Braenne
e95134b9cb [clang][dataflow] Reverse course on getValue() deprecation.
In the [value categories RFC](https://discourse.llvm.org/t/70086), I proposed that the end state of the migration should be that `getValue()` should only be legal to call on prvalues.

As a stepping stone, to allow migrating off existing calls to `getValue()`, I proposed introducing `getValueStrict()`, which would already have the new semantics.

However, I've now reconsidered this. Any expression, whether prvalue or glvalue, has a value, so really there isn't any reason to forbid calling `getValue()` on glvalues. I'm therefore removing the deprecation from `getValue()` and transitioning existing `getValueStrict()` calls back to `getValue()`.

The other "strict" accessors are a different case. `setValueStrict()` should only be called on prvalues because glvalues need to have a storage location associated with them; it doesn't make sense to only set a value for them. And, of course, `getStorageLocationStrict()` and `setStorageLocationStrict()` should obviously only be called on glvalues because prvalues don't have storage locations.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D155921
2023-07-27 13:14:49 +00:00