fix: Add Dict and List to Any_to_bool precondition#675
Merged
MikaelMayer merged 33 commits intomainfrom Mar 27, 2026
Merged
Conversation
e3d708d to
8b71992
Compare
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Any_to_bool only accepted bool, none, string, and int in its precondition and body (returning false for everything else). This caused a soundness issue: after `if results:`, the solver knew results must satisfy Any_to_bool's precondition (bool/none/ string/int) and its body must return true. Since Dict and List were not in the precondition, the solver could prove that results is never Dict or List. Then PIn's precondition (requires Dict or List) was provably unsatisfiable — reported as: ❌ always false and is reachable from declaration entry In Python, non-empty dicts and lists are truthy. Add isfrom_Dict and isfrom_ListAny to Any_to_bool's precondition and body (empty → false, non-empty → true). Test: test_pin_any.py — `if results: assert 'key' in results` Before: PIn precondition is ❌ always false and is reachable After: PIn precondition is ❓ unknown
8b71992 to
496d5e1
Compare
MikaelMayer
commented
Mar 26, 2026
MikaelMayer
commented
Mar 26, 2026
test_variable_reassign and test_while_loop had assertions that were previously provably false (❌) because Any_to_bool excluded Dict/List. With the fix, these become unknown (❓) — the solver can no longer rule out Dict/List values after a truthiness check.
…l affected assertions
MikaelMayer
commented
Mar 26, 2026
MikaelMayer
commented
Mar 26, 2026
StrataTest/Languages/Python/Specs/dispatch_test/test_pin_any.py
Outdated
Show resolved
Hide resolved
Remove Lean #eval test (requires fake fixture). Use run_py_analyze.sh framework instead: test_pin_any.py in tests/ with expected output in expected_laurel/. Empty expected file — CI will show the correct output.
… output Add '# strata-args:' comment directive to Python test files for passing extra flags to strata (e.g. --check-mode bugFinding). The shell script parses this and appends the args to the strata invocation. test_pin_any.py uses bugFinding mode to verify that PIn precondition is not provably false after a truthiness check on an opaque Any.
thanhnguyen-aws
previously approved these changes
Mar 26, 2026
pyAnalyze is deprecated in favor of pyAnalyzeLaurel. The shell script now defaults to laurel mode. CI no longer runs the non-Laurel pipeline.
joscoh
approved these changes
Mar 27, 2026
Contributor
joscoh
left a comment
There was a problem hiding this comment.
I think the CI change should be a separate PR, but I am fine to merge if others are.
aqjune-aws
approved these changes
Mar 27, 2026
Contributor
aqjune-aws
left a comment
There was a problem hiding this comment.
Approving based on the fact that Thanh approved in the past
olivier-aws
pushed a commit
that referenced
this pull request
Mar 30, 2026
## Problem `Any_to_bool` only accepted `bool`, `none`, `string`, and `int` in its precondition and body (returning `false` for everything else). This caused a soundness issue: After `if results:`, the solver knows `results` must satisfy `Any_to_bool`'s precondition and its body must return `true`. Since Dict and List were not handled, the solver could prove that `results` is never a Dict or List. Then `PIn`'s precondition (`requires isfrom_Dict || isfrom_ListAny`) was provably unsatisfiable: ``` ❌ always false and is reachable from declaration entry ``` This is a false positive — in Python, non-empty dicts and lists are truthy. ## Fix Add `isfrom_Dict` and `isfrom_ListAny` to `Any_to_bool`'s precondition and body: empty dict/list → `false`, non-empty → `true`. ## Additional changes - Add `# strata-args:` directive for per-file flags in test Python files - Deprecate `pyAnalyze` (non-Laurel) in CI — default to `pyAnalyzeLaurel` ## Test `test_pin_any.py`: `def test_in_on_any(results: Any): if results: assert 'key' in results` - **Before**: `assert_assert(124)_calls_PIn_0: ❌ always false and is reachable` - **After**: `assert_assert(124)_calls_PIn_0: ❓ unknown`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Any_to_boolonly acceptedbool,none,string, andintin its precondition and body (returningfalsefor everything else). This caused a soundness issue:After
if results:, the solver knowsresultsmust satisfyAny_to_bool's precondition and its body must returntrue. Since Dict and List were not handled, the solver could prove thatresultsis never a Dict or List. ThenPIn's precondition (requires isfrom_Dict || isfrom_ListAny) was provably unsatisfiable:This is a false positive — in Python, non-empty dicts and lists are truthy.
Fix
Add
isfrom_Dictandisfrom_ListAnytoAny_to_bool's precondition and body: empty dict/list →false, non-empty →true.Additional changes
# strata-args:directive for per-file flags in test Python filespyAnalyze(non-Laurel) in CI — default topyAnalyzeLaurelTest
test_pin_any.py:def test_in_on_any(results: Any): if results: assert 'key' in resultsassert_assert(124)_calls_PIn_0: ❌ always false and is reachableassert_assert(124)_calls_PIn_0: ❓ unknown