diff -r 5d88c1d413b9 Lib/test/test_compile.py --- a/Lib/test/test_compile.py Thu Nov 19 12:59:39 2015 +1000 +++ b/Lib/test/test_compile.py Fri Nov 20 10:54:40 2015 -0600 @@ -571,6 +571,19 @@ test_support.rmtree(tmpd) self.assertIn(b"Non-ASCII", err) + def test_null_terminated(self): + # The source code is null-terminated internally, but bytes-like + # objects are accepted, which could be not terminated. + with self.assertRaisesRegexp(TypeError, "without null bytes"): + compile(u"123\x00", "", "eval") + with self.assertRaisesRegexp(TypeError, "without null bytes"): + compile(buffer("123\x00"), "", "eval") + code = compile(buffer("123\x00")[1:-1], "", "eval") + self.assertEqual(eval(code), 23) + code = compile(buffer("1234")[1:-1], "", "eval") + self.assertEqual(eval(code), 23) + code = compile(buffer("$23$")[1:-1], "", "eval") + self.assertEqual(eval(code), 23) class TestStackSize(unittest.TestCase): # These tests check that the computed stack size for a code object diff -r 5d88c1d413b9 Lib/test/test_float.py --- a/Lib/test/test_float.py Thu Nov 19 12:59:39 2015 +1000 +++ b/Lib/test/test_float.py Fri Nov 20 10:54:40 2015 -0600 @@ -53,6 +53,35 @@ float('.' + '1'*1000) float(unicode('.' + '1'*1000)) + def test_non_numeric_input_types(self): + # Test possible non-numeric types for the argument x, including + # subclasses of the explicitly documented accepted types. + class CustomUnicode(unicode): pass + class CustomStr(str): pass + class CustomByteArray(bytearray): pass + + factories = [ + str, + bytearray, + lambda b: CustomUnicode(b.decode()), + CustomStr, + CustomByteArray, + buffer, + ] + + for f in factories: + x = f(" 3.14 ") + self.assertEqual(float(x), 3.14) + with self.assertRaisesRegexp(ValueError, "could not convert"): + float(f('A' * 0x10)) + + def test_float_buffer(self): + self.assertEqual(float(buffer('12.3')[1:4]), 2.3) + self.assertEqual(float(buffer('12.3\x00')[1:4]), 2.3) + self.assertEqual(float(buffer('12.3 ')[1:4]), 2.3) + self.assertEqual(float(buffer('12.3A')[1:4]), 2.3) + self.assertEqual(float(buffer('12.34')[1:4]), 2.3) + def check_conversion_to_int(self, x): """Check that int(x) has the correct value and type, for a float x.""" n = int(x) diff -r 5d88c1d413b9 Lib/test/test_int.py --- a/Lib/test/test_int.py Thu Nov 19 12:59:39 2015 +1000 +++ b/Lib/test/test_int.py Fri Nov 20 10:54:40 2015 -0600 @@ -376,6 +376,41 @@ self.assertIs(int(u'10'), 10) self.assertIs(int(u'-1'), -1) + def test_non_numeric_input_types(self): + # Test possible non-numeric types for the argument x, including + # subclasses of the explicitly documented accepted types. + class CustomUnicode(unicode): pass + class CustomStr(str): pass + class CustomByteArray(bytearray): pass + + factories = [ + str, + bytearray, + lambda b: CustomUnicode(b.decode()), + CustomStr, + CustomByteArray, + buffer, + ] + + for f in factories: + x = f('100') + self.assertEqual(int(x), 100) + if isinstance(x, (unicode, str)): + self.assertEqual(int(x, 2), 4) + else: + msg = "can't convert non-string" + with self.assertRaisesRegexp(TypeError, msg): + int(x, 2) + with self.assertRaisesRegexp(ValueError, 'invalid literal'): + int(f('A' * 0x10)) + + def test_int_buffer(self): + self.assertEqual(int(buffer('123')[1:3]), 23) + self.assertEqual(int(buffer('123\x00')[1:3]), 23) + self.assertEqual(int(buffer('123 ')[1:3]), 23) + self.assertEqual(int(buffer('123A')[1:3]), 23) + self.assertEqual(int(buffer('1234')[1:3]), 23) + def test_intconversion(self): # Test __int__() class ClassicMissingMethods: diff -r 5d88c1d413b9 Objects/abstract.c --- a/Objects/abstract.c Thu Nov 19 12:59:39 2015 +1000 +++ b/Objects/abstract.c Fri Nov 20 10:54:40 2015 -0600 @@ -1666,8 +1666,17 @@ PyUnicode_GET_SIZE(o), 10); #endif - if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len)) - return int_from_string((char*)buffer, buffer_len); + if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len)) { + PyObject *result, *str; + + /* Copy to NUL-terminated buffer. */ + str = PyString_FromStringAndSize((const char *)buffer, buffer_len); + if (str == NULL) + return NULL; + result = int_from_string(PyString_AS_STRING(str), buffer_len); + Py_DECREF(str); + return result; + } return type_error("int() argument must be a string or a " "number, not '%.200s'", o); @@ -1765,9 +1774,17 @@ PyUnicode_GET_SIZE(o), 10); #endif - if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len)) - return long_from_string(buffer, buffer_len); - + if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len)) { + PyObject *result, *str; + + /* Copy to NUL-terminated buffer. */ + str = PyString_FromStringAndSize((const char *)buffer, buffer_len); + if (str == NULL) + return NULL; + result = long_from_string(PyString_AS_STRING(str), buffer_len); + Py_DECREF(str); + return result; + } return type_error("long() argument must be a string or a " "number, not '%.200s'", o); } diff -r 5d88c1d413b9 Objects/complexobject.c --- a/Objects/complexobject.c Thu Nov 19 12:59:39 2015 +1000 +++ b/Objects/complexobject.c Fri Nov 20 10:54:40 2015 -0600 @@ -1000,7 +1000,7 @@ len = strlen(s); } #endif - else if (PyObject_AsCharBuffer(v, &s, &len)) { + else { PyErr_SetString(PyExc_TypeError, "complex() arg is not a string"); return NULL; diff -r 5d88c1d413b9 Objects/floatobject.c --- a/Objects/floatobject.c Thu Nov 19 12:59:39 2015 +1000 +++ b/Objects/floatobject.c Fri Nov 20 10:54:40 2015 -0600 @@ -180,6 +180,7 @@ char *s_buffer = NULL; #endif Py_ssize_t len; + PyObject *str = NULL; PyObject *result = NULL; if (pend) @@ -202,7 +203,14 @@ len = strlen(s); } #endif - else if (PyObject_AsCharBuffer(v, &s, &len)) { + else if (!PyObject_AsCharBuffer(v, &s, &len)) { + /* Copy to NUL-terminated buffer. */ + str = PyString_FromStringAndSize(s, len); + if (str == NULL) + return NULL; + s = PyString_AS_STRING(str); + } + else { PyErr_SetString(PyExc_TypeError, "float() argument must be a string or a number"); return NULL; @@ -233,6 +241,7 @@ if (s_buffer) PyMem_FREE(s_buffer); #endif + Py_XDECREF(str); return result; } diff -r 5d88c1d413b9 Python/bltinmodule.c --- a/Python/bltinmodule.c Thu Nov 19 12:59:39 2015 +1000 +++ b/Python/bltinmodule.c Fri Nov 20 10:54:40 2015 -0600 @@ -538,18 +538,29 @@ } return result; } - + if (PyString_Check(cmd)) { + str = PyString_AS_STRING(cmd); + length = PyString_GET_SIZE(cmd); + } #ifdef Py_USING_UNICODE - if (PyUnicode_Check(cmd)) { + else if (PyUnicode_Check(cmd)) { tmp = PyUnicode_AsUTF8String(cmd); if (tmp == NULL) return NULL; - cmd = tmp; cf.cf_flags |= PyCF_SOURCE_IS_UTF8; + str = PyString_AS_STRING(tmp); + length = PyString_GET_SIZE(tmp); } #endif - - if (PyObject_AsReadBuffer(cmd, (const void **)&str, &length)) + else if (!PyObject_AsReadBuffer(cmd, (const void **)&str, &length)) { + /* Copy to NUL-terminated buffer. */ + tmp = PyString_FromStringAndSize(str, length); + if (tmp == NULL) + return NULL; + str = PyString_AS_STRING(tmp); + length = PyString_GET_SIZE(tmp); + } + else goto cleanup; if ((size_t)length != strlen(str)) { PyErr_SetString(PyExc_TypeError,