[Jython-checkins] jython: Use internal methods to prevent subclasses of set causing a stack overflow.
jim.baker
jython-checkins at python.org
Sat Oct 31 12:44:22 EDT 2015
https://hg.python.org/jython/rev/a7d1380c4594
changeset: 7788:a7d1380c4594
user: Jim Baker <jim.baker at rackspace.com>
date: Sat Oct 31 10:44:15 2015 -0600
summary:
Use internal methods to prevent subclasses of set causing a stack overflow. Fixes #2357.
set.intersection_update and set.difference_update methods were defined
in terms of terms of __iand__ and __isub__, which would cause a stack
overflow if a subclass bound both method names to the same underying
method. Fix by ensuring that the implementation of
set.intersection_update and set.difference_update uses the
corresponding internal method for set.
files:
Lib/test/test_set_jy.py | 85 ++++++++++++++++++++++
src/org/python/core/PySet.java | 4 +-
2 files changed, 87 insertions(+), 2 deletions(-)
diff --git a/Lib/test/test_set_jy.py b/Lib/test/test_set_jy.py
--- a/Lib/test/test_set_jy.py
+++ b/Lib/test/test_set_jy.py
@@ -109,6 +109,90 @@
class TestJavaLinkedHashSet(TestJavaSet):
thetype = LinkedHashSet
+class SetSubclassCallsSuperMethods(set):
+
+ # Used to verify all call paths where there is more than one way
+ # to call the super method, such as (union, __or__), etc
+
+ def _valid_op_args(f):
+ def _screener(*args):
+ if len(args) != 2:
+ raise TypeError()
+ for arg in args:
+ if not (isinstance(arg, set) or isinstance(arg, frozenset)):
+ raise TypeError()
+ return f(*args)
+ return _screener
+
+ def _call_for_side_effects(f):
+ def _mutating_convention(*args):
+ f(*args)
+ return None
+ return _mutating_convention
+
+ def issubset(self, other):
+ return super(SetSubclassCallsSuperMethods, self).issubset(other)
+
+ __le__ = issubset
+
+ def issuperset(self, other):
+ return super(SetSubclassCallsSuperMethods, self).issuperset(other)
+
+ __ge__ = issuperset
+
+ def union(self, *others):
+ return super(SetSubclassCallsSuperMethods, self).union(*others)
+
+ __or__ = _valid_op_args(union)
+
+ def intersection(self, *others):
+ return super(SetSubclassCallsSuperMethods, self).intersection(*others)
+
+ __and__ = _valid_op_args(intersection)
+
+ def difference(self, *others):
+ return super(SetSubclassCallsSuperMethods, self).difference(*others)
+
+ __sub__ = _valid_op_args(difference)
+
+ def symmetric_difference(self, *others):
+ return super(SetSubclassCallsSuperMethods, self).symmetric_difference(*others)
+
+ __xor__ = _valid_op_args(symmetric_difference)
+
+ def _update(self, *others):
+ super(SetSubclassCallsSuperMethods, self).update(*others)
+ return self
+
+ update = _call_for_side_effects(_update)
+ __ior__ = _update
+
+ def _difference_update(self, *others):
+ super(SetSubclassCallsSuperMethods, self).difference_update(*others)
+ return self
+
+ difference_update = _call_for_side_effects(_difference_update)
+ __isub__ = _difference_update
+
+ def _intersection_update(self, *others):
+ super(SetSubclassCallsSuperMethods, self).intersection_update(*others)
+ return self
+
+ intersection_update = _call_for_side_effects(_intersection_update)
+ __iand__ = _intersection_update
+
+ def _symmetric_difference_update(self, other):
+ super(SetSubclassCallsSuperMethods, self).symmetric_difference_update(other)
+ return self
+
+ symmetric_difference_update = _call_for_side_effects(_symmetric_difference_update)
+ __ixor__ = _symmetric_difference_update
+
+
+class TestSetSubclassCallsSuperMethods(test_set.TestSet):
+ # verifies fix for http://bugs.jython.org/issue2357
+ thetype = SetSubclassCallsSuperMethods
+
def test_main():
tests = [
@@ -116,6 +200,7 @@
SetInJavaTestCase,
TestJavaHashSet,
TestJavaLinkedHashSet,
+ TestSetSubclassCallsSuperMethods
]
test_support.run_unittest(*tests)
diff --git a/src/org/python/core/PySet.java b/src/org/python/core/PySet.java
--- a/src/org/python/core/PySet.java
+++ b/src/org/python/core/PySet.java
@@ -306,7 +306,7 @@
for (PyObject other: args) {
if (other instanceof BaseSet) {
- __iand__(other);
+ set___iand__(other);
} else {
BaseSet set = (BaseSet)baseset_intersection(other);
_set = set._set;
@@ -343,7 +343,7 @@
for (PyObject other: args) {
if (other instanceof BaseSet) {
- __isub__(other);
+ set___isub__(other);
}
for (PyObject o : other.asIterable()) {
if (__contains__(o)) {
--
Repository URL: https://hg.python.org/jython
More information about the Jython-checkins
mailing list