summaryrefslogtreecommitdiff
blob: 81785eb05b072ff5c1a56d01c71aab5326523c2e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# HG changeset patch
# User Jim Baker <jim.baker@rackspace.com>
# Date 1454384221 25200
# Node ID d06e29d100c04576735e86c75a26c5f33669bb72
# Parent  b6735606c13df95f770527e629954407f82808c5
Do not deserialize PyFunction objects. Fixes #2454

Instead use standard Python pickling; or subclass PyFunction.

diff --git a/Lib/test/test_java_integration.py b/Lib/test/test_java_integration.py
--- a/Lib/test/test_java_integration.py
+++ b/Lib/test/test_java_integration.py
@@ -14,8 +14,9 @@ import re
 from collections import deque
 from test import test_support
 
-from java.lang import (ClassCastException, ExceptionInInitializerError, String, Runnable, System,
-        Runtime, Math, Byte)
+from java.lang import (
+    ClassCastException, ExceptionInInitializerError, UnsupportedOperationException,
+    String, Runnable, System, Runtime, Math, Byte)
 from java.math import BigDecimal, BigInteger
 from java.net import URI
 from java.io import (ByteArrayInputStream, ByteArrayOutputStream, File, FileInputStream,
@@ -656,13 +657,30 @@ class SerializationTest(unittest.TestCas
         self.assertEqual(date_list, roundtrip_serialization(date_list))
 
     def test_java_serialization_pycode(self):
-
         def universal_answer():
             return 42
 
         serialized_code = roundtrip_serialization(universal_answer.func_code)
         self.assertEqual(eval(serialized_code), universal_answer())
 
+    def test_java_serialization_pyfunction(self):
+        # Not directly supported due to lack of general utility
+        # (globals will usually be in the function object in
+        # func_globals), and problems with unserialization
+        # vulnerabilities. Users can always subclass from PyFunction
+        # for specific cases, as seen in PyCascading
+        import new
+        def f():
+            return 6 * 7 + max(0, 1, 2)
+        # However, using the new module, it's possible to create a
+        # function with no globals, which means the globals will come
+        # from the current context
+        g = new.function(f.func_code, {}, "g")
+        # But still forbid Java deserialization of this function
+        # object. Use pickling or other support instead.
+        with self.assertRaises(UnsupportedOperationException):
+            roundtrip_serialization(g)
+
     def test_builtin_names(self):
         import __builtin__
         names = [x for x in dir(__builtin__)]
@@ -872,7 +890,7 @@ class SingleMethodInterfaceTest(unittest
         future.get()
         self.assertEqual(x, [42])
 
-    @unittest.skip("FIXME: not working")
+    @unittest.skip("FIXME: not working; see http://bugs.jython.org/issue2115")
     def test_callable_object(self):
         callable_obj = CallableObject()
         future = self.executor.submit(callable_obj)
diff --git a/Lib/test/test_new.py b/Lib/test/test_new.py
--- a/Lib/test/test_new.py
+++ b/Lib/test/test_new.py
@@ -24,18 +24,10 @@ class NewTest(unittest.TestCase):
         c = new.instance(C, {'yolks': 3})
 
         o = new.instance(C)
-
-        # __dict__ is a non dict mapping in Jython
-        if test_support.is_jython:
-            self.assertEqual(len(o.__dict__), 0, "new __dict__ should be empty")
-        else:
-            self.assertEqual(o.__dict__, {}, "new __dict__ should be empty")
+        self.assertEqual(o.__dict__, {}, "new __dict__ should be empty")
         del o
         o = new.instance(C, None)
-        if test_support.is_jython:
-            self.assertEqual(len(o.__dict__), 0, "new __dict__ should be empty")
-        else:
-            self.assertEqual(o.__dict__, {}, "new __dict__ should be empty")
+        self.assertEqual(o.__dict__, {}, "new __dict__ should be empty")
         del o
 
         def break_yolks(self):
@@ -109,7 +101,14 @@ class NewTest(unittest.TestCase):
         test_closure(g, (1, 1), ValueError) # closure is wrong size
         test_closure(f, g.func_closure, ValueError) # no closure needed
 
-    if hasattr(new, 'code') and not test_support.is_jython:
+    # [Obsolete] Note: Jython will never have new.code()
+    #
+    # Who said that?!!! guess what, we do! :)
+    # 
+    # Unfortunately we still need a way to compile to Python bytecode,
+    # so support is still incomplete, as seen in the fact that we need
+    # to get values from CPython 2.7.
+    if hasattr(new, 'code'):
         def test_code(self):
             # bogus test of new.code()
             def f(a): pass
@@ -117,16 +116,16 @@ class NewTest(unittest.TestCase):
             c = f.func_code
             argcount = c.co_argcount
             nlocals = c.co_nlocals
-            stacksize = c.co_stacksize
+            stacksize = 1  # TODO c.co_stacksize
             flags = c.co_flags
-            codestring = c.co_code
-            constants = c.co_consts
-            names = c.co_names
+            codestring = 'd\x00\x00S'  # TODO c.co_code
+            constants = (None,)  # TODO c.co_consts
+            names = ()  # TODO c.co_names
             varnames = c.co_varnames
             filename = c.co_filename
             name = c.co_name
             firstlineno = c.co_firstlineno
-            lnotab = c.co_lnotab
+            lnotab = '' # TODO c.co_lnotab, but also see http://bugs.jython.org/issue1638
             freevars = c.co_freevars
             cellvars = c.co_cellvars
 
diff --git a/src/org/python/core/PyBytecode.java b/src/org/python/core/PyBytecode.java
--- a/src/org/python/core/PyBytecode.java
+++ b/src/org/python/core/PyBytecode.java
@@ -66,6 +66,12 @@ public class PyBytecode extends PyBaseCo
 
         debug = defaultDebug;
 
+        if (argcount < 0) {
+            throw Py.ValueError("code: argcount must not be negative");
+        } else if (nlocals < 0) {
+            throw Py.ValueError("code: nlocals must not be negative");
+        }
+
         co_argcount = nargs = argcount;
         co_varnames = varnames;
         co_nlocals = nlocals; // maybe assert = varnames.length;
diff --git a/src/org/python/core/PyFunction.java b/src/org/python/core/PyFunction.java
--- a/src/org/python/core/PyFunction.java
+++ b/src/org/python/core/PyFunction.java
@@ -545,6 +545,9 @@ public class PyFunction extends PyObject
     @Override
     public boolean isSequenceType() { return false; }
 
+    private Object readResolve() {
+        throw new UnsupportedOperationException();
+    }
 
     /* Traverseproc implementation */
     @Override