Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit df88846

Browse files
author
Michael W. Hudson
committed
This is my patch:
[ 1180995 ] binary formats for marshalling floats Adds 2 new type codes for marshal (binary floats and binary complexes), a new marshal version (2), updates MAGIC and fiddles the de-serializing of code objects to be less likely to clobber the real reason for failing if it fails.
1 parent 268e61c commit df88846

5 files changed

Lines changed: 196 additions & 68 deletions

File tree

Include/marshal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
extern "C" {
88
#endif
99

10-
#define Py_MARSHAL_VERSION 1
10+
#define Py_MARSHAL_VERSION 2
1111

1212
PyAPI_FUNC(void) PyMarshal_WriteLongToFile(long, FILE *, int);
1313
PyAPI_FUNC(void) PyMarshal_WriteObjectToFile(PyObject *, FILE *, int);

Lib/test/test_marshal.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,34 @@ def test_floats(self):
7373
n /= 123.4567
7474

7575
f = 0.0
76-
s = marshal.dumps(f)
76+
s = marshal.dumps(f, 2)
7777
got = marshal.loads(s)
7878
self.assertEqual(f, got)
79+
# and with version <= 1 (floats marshalled differently then)
80+
s = marshal.dumps(f, 1)
81+
got = marshal.loads(s)
82+
self.assertEqual(f, got)
7983

8084
n = sys.maxint * 3.7e-250
8185
while n < small:
8286
for expected in (-n, n):
8387
f = float(expected)
88+
8489
s = marshal.dumps(f)
8590
got = marshal.loads(s)
8691
self.assertEqual(f, got)
92+
93+
s = marshal.dumps(f, 1)
94+
got = marshal.loads(s)
95+
self.assertEqual(f, got)
96+
8797
marshal.dump(f, file(test_support.TESTFN, "wb"))
8898
got = marshal.load(file(test_support.TESTFN, "rb"))
8999
self.assertEqual(f, got)
100+
101+
marshal.dump(f, file(test_support.TESTFN, "wb"), 1)
102+
got = marshal.load(file(test_support.TESTFN, "rb"))
103+
self.assertEqual(f, got)
90104
n *= 123.4567
91105
os.unlink(test_support.TESTFN)
92106

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ What's New in Python 2.5 alpha 1?
1212
Core and builtins
1313
-----------------
1414

15+
- SF patch #1180995: marshal now uses a binary format by default when
16+
serializing floats.
17+
1518
- SF patch #1181301: on platforms that appear to use IEEE 754 floats,
1619
the routines that promise to produce IEEE 754 binary representations
1720
of floats now simply copy bytes around.

Python/import.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *);
5050
Python 2.4a0: 62041
5151
Python 2.4a3: 62051
5252
Python 2.4b1: 62061
53+
Python 2.5a0: 62071
5354
*/
54-
#define MAGIC (62061 | ((long)'\r'<<16) | ((long)'\n'<<24))
55+
#define MAGIC (62071 | ((long)'\r'<<16) | ((long)'\n'<<24))
5556

5657
/* Magic word as global; note that _PyImport_Init() can change the
5758
value of this global to accommodate for alterations of how the

Python/marshal.c

Lines changed: 175 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -15,28 +15,30 @@
1515
*/
1616
#define MAX_MARSHAL_STACK_DEPTH 5000
1717

18-
#define TYPE_NULL '0'
19-
#define TYPE_NONE 'N'
20-
#define TYPE_FALSE 'F'
21-
#define TYPE_TRUE 'T'
22-
#define TYPE_STOPITER 'S'
23-
#define TYPE_ELLIPSIS '.'
24-
#define TYPE_INT 'i'
25-
#define TYPE_INT64 'I'
26-
#define TYPE_FLOAT 'f'
27-
#define TYPE_COMPLEX 'x'
28-
#define TYPE_LONG 'l'
29-
#define TYPE_STRING 's'
30-
#define TYPE_INTERNED 't'
31-
#define TYPE_STRINGREF 'R'
32-
#define TYPE_TUPLE '('
33-
#define TYPE_LIST '['
34-
#define TYPE_DICT '{'
35-
#define TYPE_CODE 'c'
36-
#define TYPE_UNICODE 'u'
37-
#define TYPE_UNKNOWN '?'
38-
#define TYPE_SET '<'
39-
#define TYPE_FROZENSET '>'
18+
#define TYPE_NULL '0'
19+
#define TYPE_NONE 'N'
20+
#define TYPE_FALSE 'F'
21+
#define TYPE_TRUE 'T'
22+
#define TYPE_STOPITER 'S'
23+
#define TYPE_ELLIPSIS '.'
24+
#define TYPE_INT 'i'
25+
#define TYPE_INT64 'I'
26+
#define TYPE_FLOAT 'f'
27+
#define TYPE_BINARY_FLOAT 'g'
28+
#define TYPE_COMPLEX 'x'
29+
#define TYPE_BINARY_COMPLEX 'y'
30+
#define TYPE_LONG 'l'
31+
#define TYPE_STRING 's'
32+
#define TYPE_INTERNED 't'
33+
#define TYPE_STRINGREF 'R'
34+
#define TYPE_TUPLE '('
35+
#define TYPE_LIST '['
36+
#define TYPE_DICT '{'
37+
#define TYPE_CODE 'c'
38+
#define TYPE_UNICODE 'u'
39+
#define TYPE_UNKNOWN '?'
40+
#define TYPE_SET '<'
41+
#define TYPE_FROZENSET '>'
4042

4143
typedef struct {
4244
FILE *fp;
@@ -47,6 +49,7 @@ typedef struct {
4749
char *ptr;
4850
char *end;
4951
PyObject *strings; /* dict on marshal, list on unmarshal */
52+
int version;
5053
} WFILE;
5154

5255
#define w_byte(c, p) if (((p)->fp)) putc((c), (p)->fp); \
@@ -165,32 +168,62 @@ w_object(PyObject *v, WFILE *p)
165168
w_short(ob->ob_digit[i], p);
166169
}
167170
else if (PyFloat_Check(v)) {
168-
char buf[256]; /* Plenty to format any double */
169-
PyFloat_AsReprString(buf, (PyFloatObject *)v);
170-
n = strlen(buf);
171-
w_byte(TYPE_FLOAT, p);
172-
w_byte(n, p);
173-
w_string(buf, n, p);
171+
if (p->version > 1) {
172+
char buf[8];
173+
if (_PyFloat_Pack8(PyFloat_AsDouble(v),
174+
buf, 1) < 0) {
175+
p->error = 1;
176+
return;
177+
}
178+
w_byte(TYPE_BINARY_FLOAT, p);
179+
w_string(buf, 8, p);
180+
}
181+
else {
182+
char buf[256]; /* Plenty to format any double */
183+
PyFloat_AsReprString(buf, (PyFloatObject *)v);
184+
n = strlen(buf);
185+
w_byte(TYPE_FLOAT, p);
186+
w_byte(n, p);
187+
w_string(buf, n, p);
188+
}
174189
}
175190
#ifndef WITHOUT_COMPLEX
176191
else if (PyComplex_Check(v)) {
177-
char buf[256]; /* Plenty to format any double */
178-
PyFloatObject *temp;
179-
w_byte(TYPE_COMPLEX, p);
180-
temp = (PyFloatObject*)PyFloat_FromDouble(
181-
PyComplex_RealAsDouble(v));
182-
PyFloat_AsReprString(buf, temp);
183-
Py_DECREF(temp);
184-
n = strlen(buf);
185-
w_byte(n, p);
186-
w_string(buf, n, p);
187-
temp = (PyFloatObject*)PyFloat_FromDouble(
188-
PyComplex_ImagAsDouble(v));
189-
PyFloat_AsReprString(buf, temp);
190-
Py_DECREF(temp);
191-
n = strlen(buf);
192-
w_byte(n, p);
193-
w_string(buf, n, p);
192+
if (p->version > 1) {
193+
char buf[8];
194+
if (_PyFloat_Pack8(PyComplex_RealAsDouble(v),
195+
buf, 1) < 0) {
196+
p->error = 1;
197+
return;
198+
}
199+
w_byte(TYPE_BINARY_COMPLEX, p);
200+
w_string(buf, 8, p);
201+
if (_PyFloat_Pack8(PyComplex_ImagAsDouble(v),
202+
buf, 1) < 0) {
203+
p->error = 1;
204+
return;
205+
}
206+
w_string(buf, 8, p);
207+
}
208+
else {
209+
char buf[256]; /* Plenty to format any double */
210+
PyFloatObject *temp;
211+
w_byte(TYPE_COMPLEX, p);
212+
temp = (PyFloatObject*)PyFloat_FromDouble(
213+
PyComplex_RealAsDouble(v));
214+
PyFloat_AsReprString(buf, temp);
215+
Py_DECREF(temp);
216+
n = strlen(buf);
217+
w_byte(n, p);
218+
w_string(buf, n, p);
219+
temp = (PyFloatObject*)PyFloat_FromDouble(
220+
PyComplex_ImagAsDouble(v));
221+
PyFloat_AsReprString(buf, temp);
222+
Py_DECREF(temp);
223+
n = strlen(buf);
224+
w_byte(n, p);
225+
w_string(buf, n, p);
226+
}
194227
}
195228
#endif
196229
else if (PyString_Check(v)) {
@@ -335,6 +368,7 @@ PyMarshal_WriteLongToFile(long x, FILE *fp, int version)
335368
wf.error = 0;
336369
wf.depth = 0;
337370
wf.strings = NULL;
371+
wf.version = version;
338372
w_long(x, &wf);
339373
}
340374

@@ -346,6 +380,7 @@ PyMarshal_WriteObjectToFile(PyObject *x, FILE *fp, int version)
346380
wf.error = 0;
347381
wf.depth = 0;
348382
wf.strings = (version > 0) ? PyDict_New() : NULL;
383+
wf.version = version;
349384
w_object(x, &wf);
350385
Py_XDECREF(wf.strings);
351386
}
@@ -519,6 +554,22 @@ r_object(RFILE *p)
519554
return PyFloat_FromDouble(dx);
520555
}
521556

557+
case TYPE_BINARY_FLOAT:
558+
{
559+
char buf[8];
560+
double x;
561+
if (r_string(buf, 8, p) != 8) {
562+
PyErr_SetString(PyExc_EOFError,
563+
"EOF read where object expected");
564+
return NULL;
565+
}
566+
x = _PyFloat_Unpack8(buf, 1);
567+
if (x == -1.0 && PyErr_Occurred()) {
568+
return NULL;
569+
}
570+
return PyFloat_FromDouble(x);
571+
}
572+
522573
#ifndef WITHOUT_COMPLEX
523574
case TYPE_COMPLEX:
524575
{
@@ -546,6 +597,31 @@ r_object(RFILE *p)
546597
PyFPE_END_PROTECT(c)
547598
return PyComplex_FromCComplex(c);
548599
}
600+
601+
case TYPE_BINARY_COMPLEX:
602+
{
603+
char buf[8];
604+
Py_complex c;
605+
if (r_string(buf, 8, p) != 8) {
606+
PyErr_SetString(PyExc_EOFError,
607+
"EOF read where object expected");
608+
return NULL;
609+
}
610+
c.real = _PyFloat_Unpack8(buf, 1);
611+
if (c.real == -1.0 && PyErr_Occurred()) {
612+
return NULL;
613+
}
614+
if (r_string(buf, 8, p) != 8) {
615+
PyErr_SetString(PyExc_EOFError,
616+
"EOF read where object expected");
617+
return NULL;
618+
}
619+
c.imag = _PyFloat_Unpack8(buf, 1);
620+
if (c.imag == -1.0 && PyErr_Occurred()) {
621+
return NULL;
622+
}
623+
return PyComplex_FromCComplex(c);
624+
}
549625
#endif
550626

551627
case TYPE_INTERNED:
@@ -707,30 +783,63 @@ r_object(RFILE *p)
707783
return NULL;
708784
}
709785
else {
710-
int argcount = r_long(p);
711-
int nlocals = r_long(p);
712-
int stacksize = r_long(p);
713-
int flags = r_long(p);
714-
PyObject *code = r_object(p);
715-
PyObject *consts = r_object(p);
716-
PyObject *names = r_object(p);
717-
PyObject *varnames = r_object(p);
718-
PyObject *freevars = r_object(p);
719-
PyObject *cellvars = r_object(p);
720-
PyObject *filename = r_object(p);
721-
PyObject *name = r_object(p);
722-
int firstlineno = r_long(p);
723-
PyObject *lnotab = r_object(p);
724-
725-
if (!PyErr_Occurred()) {
726-
v = (PyObject *) PyCode_New(
786+
int argcount;
787+
int nlocals;
788+
int stacksize;
789+
int flags;
790+
PyObject *code = NULL;
791+
PyObject *consts = NULL;
792+
PyObject *names = NULL;
793+
PyObject *varnames = NULL;
794+
PyObject *freevars = NULL;
795+
PyObject *cellvars = NULL;
796+
PyObject *filename = NULL;
797+
PyObject *name = NULL;
798+
int firstlineno;
799+
PyObject *lnotab = NULL;
800+
801+
v = NULL;
802+
803+
argcount = r_long(p);
804+
nlocals = r_long(p);
805+
stacksize = r_long(p);
806+
flags = r_long(p);
807+
code = r_object(p);
808+
if (code == NULL)
809+
goto code_error;
810+
consts = r_object(p);
811+
if (consts == NULL)
812+
goto code_error;
813+
names = r_object(p);
814+
if (names == NULL)
815+
goto code_error;
816+
varnames = r_object(p);
817+
if (varnames == NULL)
818+
goto code_error;
819+
freevars = r_object(p);
820+
if (freevars == NULL)
821+
goto code_error;
822+
cellvars = r_object(p);
823+
if (cellvars == NULL)
824+
goto code_error;
825+
filename = r_object(p);
826+
if (filename == NULL)
827+
goto code_error;
828+
name = r_object(p);
829+
if (name == NULL)
830+
goto code_error;
831+
firstlineno = r_long(p);
832+
lnotab = r_object(p);
833+
if (lnotab == NULL)
834+
goto code_error;
835+
836+
v = (PyObject *) PyCode_New(
727837
argcount, nlocals, stacksize, flags,
728838
code, consts, names, varnames,
729839
freevars, cellvars, filename, name,
730840
firstlineno, lnotab);
731-
}
732-
else
733-
v = NULL;
841+
842+
code_error:
734843
Py_XDECREF(code);
735844
Py_XDECREF(consts);
736845
Py_XDECREF(names);
@@ -882,6 +991,7 @@ PyMarshal_WriteObjectToString(PyObject *x, int version)
882991
wf.end = wf.ptr + PyString_Size(wf.str);
883992
wf.error = 0;
884993
wf.depth = 0;
994+
wf.version = version;
885995
wf.strings = (version > 0) ? PyDict_New() : NULL;
886996
w_object(x, &wf);
887997
Py_XDECREF(wf.strings);

0 commit comments

Comments
 (0)