Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fix use of PyLong_FromString for reading large integers.

  • Loading branch information...
commit 211b5093e256a14d6430f74874393ce53dd4b97a 1 parent 2c251f1
@rfk authored
Showing with 38 additions and 6 deletions.
  1. +31 −5 tnetstring/_tnetstring.c
  2. +7 −1 tnetstring/tests/test_format.py
View
36 tnetstring/_tnetstring.c
@@ -478,13 +478,39 @@ tns_parse_integer(const tns_ops *ops, const char *data, size_t len)
}
return PyLong_FromLongLong(ll * sign);
}
- // Really big numbers must be parsed by python.
- // Technically this allows whitespace around the number, which
- // isn't valid in a tnetstring. But I don't want to waste the
- // time checking and I am *not* reimplementing arbitrary-precision
- // strtod for python.
+ // Really big numbers are passed to python's native parser.
else {
+ // PyLong_FromString allows leading whitespace, so we have to check
+ // that there is none present in the string.
+ c = *data;
+ switch(c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ break;
+ case '+':
+ case '-':
+ c = *(data+1);
+ check(c >= '0' && c <= '9', "invalid integer literal");
+ break;
+ default:
+ sentinel("invalid integer literal");
+ }
+ // PyLong_FromString insists that the string end in a NULL byte.
+ // I am *not* copying all that data. Instead we lie a little bit
+ // about the const-ness of data, write a NULL over the format terminator
+ // and restore the original character when we're done.
+ c = data[len];
+ ((char*)data)[len] = '\0';
v = PyLong_FromString((char *)data, &dataend, 10);
+ ((char*)data)[len] = c;
check(dataend == data + len, "invalid integer literal");
return v;
}
View
8 tnetstring/tests/test_format.py
@@ -2,6 +2,7 @@
import sys
import unittest
import random
+import math
import StringIO
@@ -97,6 +98,12 @@ def test_roundtrip_format_unicode(self):
self.assertEqual(v,tnetstring.loads(tnetstring.dumps(v,"utf8"),"utf8"))
self.assertEqual((v,""),tnetstring.pop(tnetstring.dumps(v,"utf16"),"utf16"))
+ def test_roundtrip_big_integer(self):
+ i1 = math.factorial(30000)
+ s = tnetstring.dumps(i1)
+ i2 = tnetstring.loads(s)
+ self.assertEquals(i1, i2)
+
class Test_FileLoading(unittest.TestCase):
@@ -131,4 +138,3 @@ def test_error_on_absurd_lengths(self):
s.seek(0)
self.assertRaises(ValueError,tnetstring.load,s)
self.assertEquals(s.read(1),":")
-
Please sign in to comment.
Something went wrong with that request. Please try again.