Fix IntervalValue equality/bitshift stubs, expose CopyKind, preserve AbstractState subclass identity - #71
Open
yuleisui wants to merge 9 commits into
Open
Fix IntervalValue equality/bitshift stubs, expose CopyKind, preserve AbstractState subclass identity#71yuleisui wants to merge 9 commits into
yuleisui wants to merge 9 commits into
Conversation
…AbstractState subclass identity Fixes several mismatches between the Python bindings/stubs and the actual C++ implementation/behavior: - IntervalValue.__eq__/__ne__ were wired to equals() (bool), while the stub documented (and C++'s operator==/!= actually implement) an abstract-domain IntervalValue result ([1,1]/[0,0]/[0,1]). Rewire the bindings to call operator==/operator!=, and add __bool__ (true only for a definite [1,1]) so common `if a == b:` patterns keep behaving correctly. Also fix equals()'s stub, which was mistakenly typed as returning IntervalValue instead of bool. - Add a CopyKind IntEnum (pysvf/enums.py) mirroring CopyStmt::CopyKind, following the same convention already used for Predicate/OpCode, so zext/trunc/etc. copy kinds don't need to be guessed as magic numbers. - AbstractState.clone()/widening()/narrowing() always constructed a plain AbstractState in C++, silently discarding any Python subclass (e.g. a `class AEState(AbstractState): ...` pattern). Reconstruct an instance of the caller's actual runtime type instead. - isCmpBranchFeasible/isSwitchBranchFeasible are pysvf-only static helpers (the real AbstractInterpretation methods are private in SVF); document this in their stubs, mark them @staticmethod, and fix their argument lists to match the real 4-arg (svfir, stmt, succ, abstract_state) binding. - Fix IntervalValue.__lshift__/__rshift__ stubs: the binding accepts another IntervalValue as the RHS (py::self << py::self), not int. Validated by rebuilding the extension and running it against the Assignment-3 course material (Software-Security-Analysis[-Sol]): the full 120-case regression corpus passes identically before/after these changes (120/120, 69/69 assertions verified, 0 regressions), and the new equality/CopyKind/branch-feasibility behavior was independently exercised against real compiled IR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR aligns pysvf’s Python bindings and type stubs with SVF’s intended abstract-domain semantics and the actual pybind-exposed APIs, especially around IntervalValue equality/bitshifts, AbstractState subclass preservation, and feasibility helper signatures. It also exposes CopyStmt copy kinds to Python callers via a new enum.
Changes:
- Rewire
IntervalValueequality to return an abstract-domainIntervalValueresult and add__bool__to make commonif a == b:patterns work sensibly. - Add
CopyKind(IntEnum)mirroringSVF::CopyStmt::CopyKindand export it frompysvf.__init__. - Preserve Python subclass identity for
AbstractState.clone()/widening()/narrowing()and correct stub signatures for feasibility helpers and shift operators.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| pysvf/pysvf.pyi | Updates stubs for IntervalValue shifts/equality helpers and corrects AbstractState static helper signatures + documentation. |
| pysvf/enums.py | Adds CopyKind enum for CopyStmt copy-kind inspection. |
| pysvf/init.py | Re-exports CopyKind from the package top-level. |
| pybind/AE.cpp | Adjusts IntervalValue equality/truthiness semantics and preserves AbstractState Python subclass identity in clone/widen/narrow. |
Suppressed comments (1)
pybind/AE.cpp:135
__bool__currently gates onis_numeral()but then callsgetIntNumeral(). Ifis_numeral()can also be true for real numerals (suggested by the presence ofis_real()/getRealNumeral()), this can throw or assert for non-integer numerals.
Using is_int() avoids calling getIntNumeral() on non-integer values while preserving the intended [1,1] truthiness semantics.
.def("__bool__", [](const IntervalValue &self) {
return self.is_numeral() && self.getIntNumeral() == 1;
})
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+122
to
+126
| .def("__eq__", [](const IntervalValue &self, const IntervalValue &other) { | ||
| return self.equals(other); | ||
| return self.operator==(other); | ||
| }) | ||
| .def("__ne__", [](const IntervalValue &self, const IntervalValue &other) { | ||
| return !self.equals(other); | ||
| return self.operator!=(other); |
| def isCmpBranchFeasible(self, cmp: 'CmpStmt', succ: int, abstract_state: AbstractState) -> bool: ... | ||
| def isSwitchBranchFeasible(self, switch_var: SVFVar, succ: int, abstract_state: AbstractState) -> bool: ... | ||
| @staticmethod | ||
| def isCmpBranchFeasible(pag: 'SVFIR', cmpStmt: 'CmpStmt', succ: int, as_: 'AbstractState') -> bool: ... |
FIX: remove incorrect Copilot fixes for AE API mismatches
Patch missing Copilot fixes
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.
Summary
Fixes several mismatches between the Python bindings/stubs and the actual C++ implementation/behavior in
pysvf:IntervalValue.__eq__/__ne__returnedbool, notIntervalValue. The binding calledequals()(bool), while the stub already documented (and C++'soperator==/operator!=actually implement) an abstract-domain result ([1,1]/[0,0]/[0,1]). Rewired the bindings to calloperator==/operator!=, and added__bool__(true only for a definite[1,1]) so commonif a == b:patterns keep behaving correctly. Also fixedequals()'s stub, which was mistakenly typed as returningIntervalValueinstead ofbool.CopyKindenum was missing from the bindings, so callers had to guess raw integer values to detect zext/trunc/etc. copy kinds. Added aCopyKind(IntEnum)topysvf/enums.pymirroringCopyStmt::CopyKind, following the same convention already used forPredicate/OpCode.AbstractState.clone()/widening()/narrowing()always constructed a plainAbstractStatein C++, silently discarding any Python subclass (e.g. aclass AEState(AbstractState): ...pattern, as used in the SVF course material). Reconstruct an instance of the caller's actual runtime type instead.isCmpBranchFeasible/isSwitchBranchFeasibledon't exist in the C++ library (the realAbstractInterpretationmethods are private) and the stub had an incorrect argument count (missing the leadingSVFIR/pagargument) and wasn't marked@staticmethod, despite the binding being adef_static. Documented these as pysvf-only helpers in the stub and fixed the signatures to match the real 4-arg binding.IntervalValue.__lshift__/__rshift__stubs were typed as takingintfor the RHS, but the binding accepts anotherIntervalValue(py::self << py::self).Validation
svf-lib/LLVM 21 toolchain) and ran the SVF course's Assignment-3 material (Software-Security-Analysis/Software-Security-Analysis-Sol) against it..llregression corpus passes identically before/after these changes (120/120, 69/69 assertions verified, 0 regressions vs. a pre-fix build using the same SVF/LLVM version).__bool__,CopyKind, and subclass-preservation behavior against real compiled IR and confirmed correctness.stubtestpasses with the existingstubtest_allowlist.txt.No behavioral changes were made to
isCmpBranchFeasible/isSwitchBranchFeasible's underlying logic — only their stub signatures were corrected.