You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Partial fix for 9049: False negative: uninitialized variable with nested ifs (#8680)
This fixes the case for this:
```cpp
unsigned int g();
void f(bool a) {
unsigned int dimensions = 0;
bool mightBeLarger;
if (a) {
dimensions = g();
if (dimensions >= 1)
mightBeLarger = false;
} else {
mightBeLarger = false;
}
if (dimensions == 1)
return;
if (!mightBeLarger) {}
}
```
Which doesnt use a compund condition `dimensions >= 1 && b)` and it also
requires complete variables and functions. The compund condition could
be handled in the future by forking within the condition, so `if(a && b)
{ ... }` can be treated as `if(a) { if(b) { ... }}`.
Here is a summary of the changes:
1. Fork-based condition handling — lib/forwardanalyzer.cpp (the largest
change)
- When a condition can't be resolved, the traversal now forks: the
then-branch is walked by a separate ForwardTraversal, in analyze-only
mode when the value can't actually flow into it (opaque/correlated
conditions like if (f(x))), so the branch's effect is tracked but
nothing is reported there.
- Branch breaks are deferred: if the else kills the value on the main
path, the then-fork can still carry it forward.
- Escapes the traversal didn't flag (e.g. unknown noreturn calls) are
detected via isEscapeScope, and exit/abort are now recognized as escape
functions (lib/astutils.cpp).
2. Program-state anchoring at block boundaries — lib/vf_analyzers.cpp +
lib/analyzer.h
- assume() now anchors the assumed state at the block's end (not the
condition) when control is leaving an already-traversed branch. This
keeps an assumption on a variable modified inside the block (e.g. a
nested if narrowing a value computed there) from being discarded as
"modified" once control leaves the block.
- New Assume::Pending flag marks the pre-traversal assume (branch walked
separately) so it doesn't record premature boundary state.
- ProgramMemoryState::assume gained an optional origin parameter so the
anchor point can be overridden.
3. vars-aware execute — lib/programmemory.cpp / .h
- execute/conditionIsTrue/conditionIsFalse now take the tracked values
(vars). A tracked value is the authoritative current value of its
expression (returned and written back into the program memory), and any
cached compound that depends on a tracked value is re-evaluated instead
of served stale (getTrackedValue / dependsOnTrackedValue).
- The per-assignment substitution was removed from
fillProgramMemoryFromAssignments and now lives entirely in execute so it
can be used for all executions.
---------
Co-authored-by: Your Name <you@example.com>
Copy file name to clipboardExpand all lines: test/testautovariables.cpp
+3-1Lines changed: 3 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -4941,7 +4941,9 @@ class TestAutoVariables : public TestFixture {
4941
4941
" return *iPtr;\n"
4942
4942
" return 0;\n"
4943
4943
"}");
4944
-
ASSERT_EQUALS("[test.cpp:5:16] -> [test.cpp:4:13] -> [test.cpp:8:17]: (error) Using pointer to local variable 'x' that is out of scope. [invalidLifetime]\n", errout_str());
4944
+
ASSERT_EQUALS(
4945
+
"[test.cpp:5:16] -> [test.cpp:7:10] -> [test.cpp:4:13] -> [test.cpp:8:17]: (error) Using pointer to local variable 'x' that is out of scope. [invalidLifetime]\n",
0 commit comments