Skip to content

Commit

Permalink
no longer trust custom repr for int/long/float subclasses #118
Browse files Browse the repository at this point in the history
  • Loading branch information
etrepum committed May 18, 2015
1 parent f9e8ca4 commit da14c26
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 8 deletions.
7 changes: 7 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
Version 3.7.0 released 2015-05-18

* simplejson no longer trusts custom str/repr methods for int, long, float
subclasses. These instances are now formatted as if they were exact
instances of those types.
https://github.com/simplejson/simplejson/issues/118

Version 3.6.5 released 2014-10-24

* Importing bug fix for reference leak when an error occurs during
Expand Down
4 changes: 2 additions & 2 deletions conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@
# other places throughout the built documents.
#
# The short X.Y version.
version = '3.6'
version = '3.7'
# The full version, including alpha/beta/rc tags.
release = '3.6.5'
release = '3.7.0'

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
DistutilsPlatformError

IS_PYPY = hasattr(sys, 'pypy_translation_info')
VERSION = '3.6.5'
VERSION = '3.7.0'
DESCRIPTION = "Simple, fast, extensible JSON encoder/decoder for Python"

with open('README.rst', 'r') as f:
Expand Down
2 changes: 1 addition & 1 deletion simplejson/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
Expecting property name: line 1 column 3 (char 2)
"""
from __future__ import absolute_import
__version__ = '3.6.5'
__version__ = '3.7.0'
__all__ = [
'dump', 'dumps', 'load', 'loads',
'JSONDecoder', 'JSONDecodeError', 'JSONEncoder',
Expand Down
47 changes: 43 additions & 4 deletions simplejson/_speedups.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define PyString_AS_STRING PyBytes_AS_STRING
#define PyString_FromStringAndSize PyBytes_FromStringAndSize
#define PyInt_Check(obj) 0
#define PyInt_CheckExact(obj) 0
#define JSON_UNICHR Py_UCS4
#define JSON_InternFromString PyUnicode_InternFromString
#define JSON_Intern_GET_SIZE PyUnicode_GET_SIZE
Expand Down Expand Up @@ -660,7 +661,19 @@ encoder_stringify_key(PyEncoderObject *s, PyObject *key)
return _encoded_const(key);
}
else if (PyInt_Check(key) || PyLong_Check(key)) {
return PyObject_Str(key);
if (!(PyInt_CheckExact(key) || PyLong_CheckExact(key))) {
/* See #118, do not trust custom str/repr */
PyObject *tmp = PyObject_CallFunctionObjArgs((PyObject *)&PyLong_Type, key, NULL);
if (tmp == NULL) {
return NULL;
}
PyObject *res = PyObject_Str(tmp);
Py_DECREF(tmp);
return res;
}
else {
return PyObject_Str(key);
}
}
else if (s->use_decimal && PyObject_TypeCheck(key, (PyTypeObject *)s->Decimal)) {
return PyObject_Str(key);
Expand Down Expand Up @@ -2637,7 +2650,7 @@ encoder_init(PyObject *self, PyObject *args, PyObject *kwds)
s->tuple_as_array = PyObject_IsTrue(tuple_as_array);
if (PyInt_Check(int_as_string_bitcount) || PyLong_Check(int_as_string_bitcount)) {
static const unsigned int long_long_bitsize = SIZEOF_LONG_LONG * 8;
int int_as_string_bitcount_val = PyLong_AsLong(int_as_string_bitcount);
int int_as_string_bitcount_val = (int)PyLong_AsLong(int_as_string_bitcount);
if (int_as_string_bitcount_val > 0 && int_as_string_bitcount_val < long_long_bitsize) {
s->max_long_size = PyLong_FromUnsignedLongLong(1ULL << int_as_string_bitcount_val);
s->min_long_size = PyLong_FromLongLong(-1LL << int_as_string_bitcount_val);
Expand Down Expand Up @@ -2800,7 +2813,19 @@ encoder_encode_float(PyEncoderObject *s, PyObject *obj)
}
}
/* Use a better float format here? */
return PyObject_Repr(obj);
if (PyFloat_CheckExact(obj)) {
return PyObject_Repr(obj);
}
else {
/* See #118, do not trust custom str/repr */
PyObject *tmp = PyObject_CallFunctionObjArgs((PyObject *)&PyFloat_Type, obj, NULL);
if (tmp == NULL) {
return NULL;
}
PyObject *res = PyObject_Repr(tmp);
Py_DECREF(tmp);
return res;
}
}

static PyObject *
Expand Down Expand Up @@ -2840,7 +2865,21 @@ encoder_listencode_obj(PyEncoderObject *s, JSON_Accu *rval, PyObject *obj, Py_ss
rv = _steal_accumulate(rval, encoded);
}
else if (PyInt_Check(obj) || PyLong_Check(obj)) {
PyObject *encoded = PyObject_Str(obj);
PyObject *encoded;
if (PyInt_CheckExact(obj) || PyLong_CheckExact(obj)) {
encoded = PyObject_Str(obj);
}
else {
/* See #118, do not trust custom str/repr */
PyObject *tmp = PyObject_CallFunctionObjArgs((PyObject *)&PyLong_Type, obj, NULL);
if (tmp == NULL) {
encoded = NULL;
}
else {
encoded = PyObject_Str(tmp);
Py_DECREF(tmp);
}
}
if (encoded != NULL) {
encoded = maybe_quote_bigint(s, encoded, obj);
if (encoded == NULL)
Expand Down
9 changes: 9 additions & 0 deletions simplejson/encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,9 @@ def floatstr(o, allow_nan=self.allow_nan, ignore_nan=self.ignore_nan,
elif o == _neginf:
text = '-Infinity'
else:
if type(o) != float:
# See #118, do not trust custom str/repr
o = float(o)
return _repr(o)

if ignore_nan:
Expand Down Expand Up @@ -412,6 +415,9 @@ def _encode_int(value):
or
_int_as_string_bitcount < 1
)
if type(value) not in integer_types:
# See #118, do not trust custom str/repr
value = int(value)
if (
skip_quoting or
(-1 << _int_as_string_bitcount)
Expand Down Expand Up @@ -501,6 +507,9 @@ def _stringify_key(key):
elif key is None:
key = 'null'
elif isinstance(key, integer_types):
if key not in integer_types:
# See #118, do not trust custom str/repr
key = int(key)
key = str(key)
elif _use_decimal and isinstance(key, Decimal):
key = str(key)
Expand Down
1 change: 1 addition & 0 deletions simplejson/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def get_suite():
'simplejson.tests.test_namedtuple',
'simplejson.tests.test_tool',
'simplejson.tests.test_for_json',
'simplejson.tests.test_subclass',
]))
suite = get_suite()
import simplejson
Expand Down

0 comments on commit da14c26

Please sign in to comment.