commit 192a9c19765de83504eab58c1c769dad84602d8d
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Mon Sep 26 18:47:41 2011 -0400
cpychecker: remove reference to RefcountValue from absinterp
The absinterp core implemented comparisons between abstract values by
explicitly listing all of the cases, including those involving the
RefcountValue class.
Replace this with method calls: an AbstractValue.is_lt method, which calls
out to class-specific implementations of impl_is_lt and impl_is_ge, thus
allowing us to remove a reference to RefcountValue from the core simulator
libcpychecker/absinterp.py | 79 ++++++++++++++++++++++++++++++++++++++-----
libcpychecker/refcounts.py | 13 +++++++
2 files changed, 82 insertions(+), 10 deletions(-)
---
diff --git a/libcpychecker/absinterp.py b/libcpychecker/absinterp.py
index af32f4b..cc15003 100644
--- a/libcpychecker/absinterp.py
+++ b/libcpychecker/absinterp.py
@@ -38,6 +38,10 @@ from libcpychecker.types import *
# the prefix "r_" means a Region
# the prefix "f_" means a Facet
+############################################################################
+# Various kinds of r-value:
+############################################################################
+
class AbstractValue:
def __init__(self, gcctype, loc):
if gcctype:
@@ -81,6 +85,36 @@ class AbstractValue:
"""
raise NotImplementedError("is_equal for %s" % self)
+ def is_lt(self, rhs):
+ """
+ "lt" = "less-than"
+ Return a boolean, or None (meaning we don't know)
+ """
+ # First try "less-than":
+ lt_result = self.impl_is_lt(rhs)
+ if lt_result is not None:
+ return lt_result
+ # We don't know; try the other way around:
+ ge_result = rhs.impl_is_ge(self)
+ if ge_result is not None:
+ return not ge_result
+ # We don't know:
+ return None
+
+ def impl_is_lt(self, rhs):
+ """
+ "lt" = "less-than"
+ Return a boolean, or None (meaning we don't know)
+ """
+ raise NotImplementedError("impl_is_lt for %s" % self)
+
+ def impl_is_ge(self, rhs):
+ """
+ "ge" = "greater-than-or-equal"
+ Return a boolean, or None (meaning we don't know)
+ """
+ raise NotImplementedError("impl_is_ge for %s" % self)
+
class UnknownValue(AbstractValue):
"""
A value that we know nothing about
@@ -103,6 +137,12 @@ class UnknownValue(AbstractValue):
def is_equal(self, rhs):
return None
+ def impl_is_lt(self, rhs):
+ return None
+
+ def impl_is_ge(self, rhs):
+ return None
+
class ConcreteValue(AbstractValue):
"""
A known, specific value (e.g. 0)
@@ -161,6 +201,18 @@ class ConcreteValue(AbstractValue):
return self.value == rhs.value
return None
+ def impl_is_lt(self, rhs):
+ if isinstance(rhs, ConcreteValue):
+ log('comparing concrete values: %s %s', self, rhs)
+ return self.value < rhs.value
+ return None
+
+ def impl_is_ge(self, rhs):
+ if isinstance(rhs, ConcreteValue):
+ log('comparing concrete values: %s %s', self, rhs)
+ return self.value >= rhs.value
+ return None
+
class PointerToRegion(AbstractValue):
"""A non-NULL pointer value, pointing at a specific Region"""
def __init__(self, gcctype, loc, region):
@@ -189,6 +241,12 @@ class PointerToRegion(AbstractValue):
# We don't know:
return None
+ def impl_is_lt(self, rhs):
+ return None
+
+ def impl_is_ge(self, rhs):
+ return None
+
class DeallocatedMemory(AbstractValue):
def __str__(self):
if self.loc:
@@ -207,6 +265,16 @@ class UninitializedData(AbstractValue):
# We don't know:
return None
+ def impl_is_lt(self, rhs):
+ return None
+
+ def impl_is_ge(self, rhs):
+ return None
+
+############################################################################
+# Various kinds of predicted error:
+############################################################################
+
class PredictedError(Exception):
pass
@@ -1252,16 +1320,7 @@ class State:
# "less-than"
check_isinstance(lhs, AbstractValue)
check_isinstance(rhs, AbstractValue)
- if isinstance(rhs, ConcreteValue):
- if isinstance(lhs, ConcreteValue):
- log('comparing concrete values: %s %s', lhs, rhs)
- return lhs.value < rhs.value
- if isinstance(lhs, RefcountValue):
- log('comparing refcount value %s with concrete value: %s', lhs, rhs)
- if lhs.get_min_value() >= rhs.value:
- return False
- # We don't know:
- return None
+ return lhs.is_lt(rhs)
def is_le(lhs, rhs):
# "less-than-or-equal"
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index 57307d8..da0c2bb 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -154,6 +154,19 @@ class RefcountValue(AbstractValue):
# (Equality is thus not possible for this case)
return False
+ def impl_is_lt(self, rhs):
+ if isinstance(rhs, ConcreteValue):
+ log('comparing refcount value %s with concrete value: %s', lhs, rhs)
+ if self.get_min_value() >= rhs.value:
+ return False
+
+ def impl_is_ge(self, rhs):
+ if isinstance(rhs, ConcreteValue):
+ log('comparing refcount value %s with concrete value: %s', lhs, rhs)
+ if self.get_min_value() >= rhs.value:
+ return True
+
+
class GenericTpDealloc(AbstractValue):
"""
A function pointer that points to a "typical" tp_dealloc callback