Skip to content

Commit 958bb7a

Browse files
committed
Updated CPython bytecode (.pyc-files) support to bytecode-version 2.7 (compliant with magic number 62211). Fixes #2533 and prepares for #527524. pycimport.py now checks for the right magic number; previously it just attempted to run incompatible bytecode, potentially yielding undefined behavior.
1 parent c358d4e commit 958bb7a

5 files changed

Lines changed: 482 additions & 379 deletions

File tree

Lib/pycimport.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
__debugging__ = False
77

8+
# Todo: This should be stored in a central place.
9+
supported_magic = 62211 # CPython 2.7
10+
811
def __readPycHeader(file):
912
def read():
1013
return ord(file.read(1))
@@ -26,6 +29,7 @@ class __Importer(object):
2629
def __init__(self, path):
2730
if __debugging__: print "Importer invoked"
2831
self.__path = path
32+
2933
def find_module(self, fullname, path=None):
3034
if __debugging__:
3135
print "Importer.find_module(fullname=%s, path=%s)" % (
@@ -42,19 +46,26 @@ def find_module(self, fullname, path=None):
4246
except:
4347
return None # abort! not a valid pyc-file
4448
f.close()
49+
# Todo: This check should also be in Unmarshaller
50+
if magic != supported_magic:
51+
return None # bytecode version mismatch
4552
if os.path.exists(pyfile):
4653
pytime = os.stat(pyfile).st_mtime
4754
if pytime > mtime:
4855
return None # abort! py-file was newer
4956
return self
5057
else:
5158
return None # abort! pyc-file does not exist
59+
5260
def load_module(self, fullname):
5361
path = fullname.split('.')
5462
path[-1] += '.pyc'
5563
filename = os.path.join(self.__path, *path)
5664
f = open(filename, 'rb')
5765
magic, mtime = __readPycHeader(f)
66+
if magic != supported_magic:
67+
if __debugging__: print "Unsupported bytecode version:", fullname
68+
return None
5869
#code = Unmarshaller(f, magic=magic).load()
5970
code = Unmarshaller(f).load()
6071
if __debugging__: print "Successfully loaded:", fullname
@@ -63,6 +74,7 @@ def load_module(self, fullname):
6374
class __MetaImporter(object):
6475
def __init__(self):
6576
self.__importers = {}
77+
6678
def find_module(self, fullname, path):
6779
if __debugging__: print "MetaImporter.find_module(%s, %s)" % (
6880
repr(fullname), repr(path))

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ For more details, please see https://hg.python.org/jython
44

55
Jython 2.7.1rc1
66
Bugs fixed
7+
- [ 2533 ] Opcode.java is outdated -> breaks PyBytecode.interpret
78
- [ 2502 ] Missing OpenFlags enum entry makes Jython clash with JRuby dependency
89
- [ 2446 ] Support SNI for SSL/TLS client sockets
910
- [ 2455 ] Java classes in packages with __init__.py not found
@@ -35,6 +36,7 @@ Jython 2.7.1rc1
3536
- [ 1767 ] Rich comparisons
3637

3738
New Features
39+
- Support for CPython bytecode (.pyc-files) was updated to Python 2.7 bytecode (from 2.5).
3840
- Buffer API changes allow java.nio.ByteBuffer to provide the storage when a PyBuffer
3941
is exported. This is to support CPython extensions via JyNI, but has other uses too
4042
(including access to direct memory buffers from Python). There is no change at the

src/org/python/compiler/ClassFile.java

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,18 @@ public static String fixName(String n) {
4242
}
4343
return new String(c);
4444
}
45-
4645

4746
public static void visitAnnotations(AnnotationVisitor av, Map<String, Object> fields) {
4847
for (Entry<String, Object>field: fields.entrySet()) {
4948
visitAnnotation(av, field.getKey(), field.getValue());
5049
}
5150
}
52-
51+
5352
// See org.objectweb.asm.AnnotationVisitor for details
5453
// TODO Support annotation annotations and annotation array annotations
5554
public static void visitAnnotation(AnnotationVisitor av, String fieldName, Object fieldValue) {
5655
Class<?> fieldValueClass = fieldValue.getClass();
57-
56+
5857
if (fieldValue instanceof Class) {
5958
av.visit(fieldName, Type.getType((Class<?>)fieldValue));
6059
} else if (fieldValueClass.isEnum()) {
@@ -79,13 +78,14 @@ public ClassFile(String name) {
7978
public ClassFile(String name, String superclass, int access) {
8079
this(name, superclass, access, org.python.core.imp.NO_MTIME);
8180
}
81+
8282
public ClassFile(String name, String superclass, int access, long mtime) {
8383
this.name = fixName(name);
8484
this.superclass = fixName(superclass);
8585
this.interfaces = new String[0];
8686
this.access = access;
8787
this.mtime = mtime;
88-
88+
8989
cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
9090
methodVisitors = Collections.synchronizedList(new ArrayList<MethodVisitor>());
9191
fieldVisitors = Collections.synchronizedList(new ArrayList<FieldVisitor>());
@@ -96,7 +96,9 @@ public void setSource(String name) {
9696
sfilename = name;
9797
}
9898

99-
public void addInterface(String name) throws IOException {
99+
public void addInterface(String name)
100+
throws IOException
101+
{
100102
String[] new_interfaces = new String[interfaces.length+1];
101103
System.arraycopy(interfaces, 0, new_interfaces, 0, interfaces.length);
102104
new_interfaces[interfaces.length] = name;
@@ -111,15 +113,16 @@ public Code addMethod(String name, String type, int access)
111113
methodVisitors.add(pmv);
112114
return pmv;
113115
}
116+
114117
public Code addMethod(String name, String type, int access, String[] exceptions)
115-
throws IOException
116-
{
117-
MethodVisitor mv = cw.visitMethod(access, name, type, null, exceptions);
118-
Code pmv = new Code(mv, type, access);
119-
methodVisitors.add(pmv);
120-
return pmv;
121-
}
122-
118+
throws IOException
119+
{
120+
MethodVisitor mv = cw.visitMethod(access, name, type, null, exceptions);
121+
Code pmv = new Code(mv, type, access);
122+
methodVisitors.add(pmv);
123+
return pmv;
124+
}
125+
123126
public Code addMethod(String name, String type, int access, String[] exceptions,
124127
AnnotationDescr[]methodAnnotationDescrs, AnnotationDescr[][] parameterAnnotationDescrs)
125128
throws IOException
@@ -134,7 +137,7 @@ public Code addMethod(String name, String type, int access, String[] exceptions,
134137
}
135138
av.visitEnd();
136139
}
137-
140+
138141
// parameter annotations
139142
for (int i = 0; i < parameterAnnotationDescrs.length; i++) {
140143
for (AnnotationDescr ad: parameterAnnotationDescrs[i]) {
@@ -145,20 +148,20 @@ public Code addMethod(String name, String type, int access, String[] exceptions,
145148
av.visitEnd();
146149
}
147150
}
148-
151+
149152
Code pmv = new Code(mv, type, access);
150153
methodVisitors.add(pmv);
151154
return pmv;
152155
}
153-
156+
154157
public void addClassAnnotation(AnnotationDescr annotationDescr) {
155158
AnnotationVisitor av = cw.visitAnnotation(annotationDescr.getName(), true);
156159
if (annotationDescr.hasFields()) {
157160
visitAnnotations(av, annotationDescr.getFields());
158161
}
159162
annotationVisitors.add(av);
160163
}
161-
164+
162165
public void addField(String name, String type, int access)
163166
throws IOException
164167
{
@@ -190,7 +193,7 @@ public void endFields()
190193
fv.visitEnd();
191194
}
192195
}
193-
196+
194197
public void endMethods()
195198
throws IOException
196199
{
@@ -204,10 +207,12 @@ public void endMethods()
204207
public void endClassAnnotations() {
205208
for (AnnotationVisitor av: annotationVisitors) {
206209
av.visitEnd();
207-
}
210+
}
208211
}
209212

210-
public void write(OutputStream stream) throws IOException {
213+
public void write(OutputStream stream)
214+
throws IOException
215+
{
211216
cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, this.name, null, this.superclass, interfaces);
212217
AnnotationVisitor av = cw.visitAnnotation("Lorg/python/compiler/APIVersion;", true);
213218
// XXX: should imp.java really house this value or should imp.java point into

0 commit comments

Comments
 (0)