[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