[Jython-checkins] jython: Fix stack overflow due to how proxies for Java classes resolve super method in

jim.baker jython-checkins at python.org
Thu Apr 16 00:34:23 CEST 2015


https://hg.python.org/jython/rev/95d09ba14aa7
changeset:   7672:95d09ba14aa7
user:        Jim Baker <jim.baker at rackspace.com>
date:        Wed Apr 15 18:34:17 2015 -0400
summary:
  Fix stack overflow due to how proxies for Java classes resolve super method in Java

For a Python class extending a Java class and/or interfaces, the MRO
contains a proxy (PyJavaType) so that Java can call back into
Python. However, because the proxy is in the MRO, it participates in
super lookup, and this was breaking because during super calls, the
referred Python code would refer to this proxy, which would refer back
to Python, generating a stack overflow.  So break out of this infinite
loop by ignoring this entry for super purposes.  The use of the
super__ prefix parallels the workaround seen in PyReflectedFunction.

Fixes http://bugs.jython.org/issue1540

files:
  Lib/test/test_java_subclasses.py |  31 ++++++++++++++++++-
  src/org/python/core/PyType.java  |  20 +++++++++++-
  2 files changed, 47 insertions(+), 4 deletions(-)


diff --git a/Lib/test/test_java_subclasses.py b/Lib/test/test_java_subclasses.py
--- a/Lib/test/test_java_subclasses.py
+++ b/Lib/test/test_java_subclasses.py
@@ -7,7 +7,7 @@
 
 from java.lang import (Boolean, Class, ClassLoader, Comparable,Integer, Object, Runnable, String,
         Thread, ThreadGroup)
-from java.util import AbstractList, Date, Hashtable, HashSet, Vector
+from java.util import AbstractList, ArrayList, Date, Hashtable, HashSet, Vector
 from java.util.concurrent import Callable, Executors
 
 from java.awt import Color, Component, Dimension, Rectangle
@@ -433,6 +433,32 @@
             C().call()
 
 
+class SuperIsSuperTest(unittest.TestCase):
+    # Testing how the vision described in Raymond Hettinger's blog
+    # https://rhettinger.wordpress.com/2011/05/26/super-considered-super/
+    # - super in Python is really next-method - can be merged with
+    # Java's super, which is a conventional super that dispatches up
+    # the class inheritance hierarchy
+    
+    def test_super_dispatches_through_proxy(self):
+        # Verify fix for http://bugs.jython.org/issue1540
+        
+        class MyList(ArrayList):
+
+            def get(self, index):
+                return super(MyList, self).get(index)
+
+            def toString(self):
+                return "MyList<<<" + super(MyList, self).toString() + ">>>"
+        
+        my_list = MyList([0, 1, 2, 3, 4, 5])
+        self.assertEqual(my_list.get(5), 5)
+        self.assertEqual(
+            str(my_list),
+            "MyList<<<[0, 1, 2, 3, 4, 5]>>>")
+        self.assertEqual(my_list.size(), 6)
+
+
 def test_main():
     test_support.run_unittest(
         InterfaceTest,
@@ -442,7 +468,8 @@
         AbstractOnSyspathTest,
         ContextClassloaderTest,
         MetaClassTest,
-        AbstractMethodTest)
+        AbstractMethodTest,
+        SuperIsSuperTest)
 
 
 if __name__ == '__main__':
diff --git a/src/org/python/core/PyType.java b/src/org/python/core/PyType.java
--- a/src/org/python/core/PyType.java
+++ b/src/org/python/core/PyType.java
@@ -1285,6 +1285,7 @@
     }
 
     public PyObject super_lookup(PyType ref, String name) {
+        String lookupName;  // the method name to lookup
         PyObject[] mro = this.mro;
         if (mro == null) {
             return null;
@@ -1296,11 +1297,26 @@
         }
         i++;
         for (; i < mro.length; i++) {
+            if (mro[i] instanceof PyJavaType) {
+                // The MRO contains this proxy for classes extending a Java class and/or
+                // interfaces, but the proxy points back to this starting Python class.
+                // So break out of this infinite loop by ignoring this entry for super purposes.
+                // The use of super__ parallels the workaround seen in PyReflectedFunction
+                // Fixes http://bugs.jython.org/issue1540
+                if(!name.startsWith("super__")) {
+                     lookupName = "super__" + name;
+                } else {
+                    lookupName = name;
+                }
+            } else {
+                lookupName = name;
+            }
             PyObject dict = mro[i].fastGetDict();
             if (dict != null) {
-                PyObject obj = dict.__finditem__(name);
-                if (obj != null)
+                PyObject obj = dict.__finditem__(lookupName);
+                if (obj != null) {
                     return obj;
+                }
             }
         }
         return null;

-- 
Repository URL: https://hg.python.org/jython


More information about the Jython-checkins mailing list