Merge lp:~gz/bzr/2.4_overflow_pack_stat_683191_706957 into lp:bzr/2.4

Proposed by Martin Packman
Status: Merged
Approved by: John A Meinel
Approved revision: no longer in the source branch.
Merged at revision: 6048
Proposed branch: lp:~gz/bzr/2.4_overflow_pack_stat_683191_706957
Merge into: lp:bzr/2.4
Diff against target: 122 lines (+68/-8)
4 files modified
bzrlib/_dirstate_helpers_pyx.pyx (+8/-6)
bzrlib/dirstate.py (+3/-2)
bzrlib/tests/test__dirstate_helpers.py (+53/-0)
doc/en/release-notes/bzr-2.4.txt (+4/-0)
To merge this branch: bzr merge lp:~gz/bzr/2.4_overflow_pack_stat_683191_706957
Reviewer Review Type Date Requested Status
John A Meinel Approve
Review via email: mp+77373@code.launchpad.net

Commit message

Truncate stat fields to 4 bytes in pack_stat functions used by dirstate

Description of the change

Fix on 2.4 branch for overflow issues with pack_stat, for a complete discussion of the change see the merge proposal for trunk:
<https://code.launchpad.net/~gz/bzr/overflow_pack_stat_683191_706957/+merge/77372>

There are a couple of things to remark on here in addition.

Firstly, only the version of pack_stat in dirstate that actually gets used in updated, but I haven't removed the old code as was done for trunk in <lp:~gz/bzr/move_pack_stat_to_dirstate_helpers> just in case.

Secondly, the tests here only cover the python implementation, exposing the pyrex version and parametrising against it is only done on trunk. As the code change is identical and the tests work there, this shouldn't matter too much.

To post a comment you must log in.
Revision history for this message
John A Meinel (jameinel) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 9/28/2011 7:41 PM, Martin Packman wrote:
> Martin Packman has proposed merging
> lp:~gz/bzr/2.4_overflow_pack_stat_683191_706957 into lp:bzr/2.4.
>
> Requested reviews: bzr-core (bzr-core) Related bugs: Bug #683191 in
> Bazaar: ""exceptions.OverflowError: long int too large to convert"
> in _dirstate_helpers_pyx.c"
> https://bugs.launchpad.net/bzr/+bug/683191 Bug #706957 in Bazaar:
> "OverflowError in _dirstate_helpers pack_stat"
> https://bugs.launchpad.net/bzr/+bug/706957
>
> For more details, see:
> https://code.launchpad.net/~gz/bzr/2.4_overflow_pack_stat_683191_706957/+merge/77373
>
> Fix on 2.4 branch for overflow issues with pack_stat, for a
> complete discussion of the change see the merge proposal for
> trunk:
> <https://code.launchpad.net/~gz/bzr/overflow_pack_stat_683191_706957/+merge/77372>
>
> There are a couple of things to remark on here in addition.
>
> Firstly, only the version of pack_stat in dirstate that actually
> gets used in updated, but I haven't removed the old code as was
> done for trunk in <lp:~gz/bzr/move_pack_stat_to_dirstate_helpers>
> just in case.
>
> Secondly, the tests here only cover the python implementation,
> exposing the pyrex version and parametrising against it is only
> done on trunk. As the code change is identical and the tests work
> there, this shouldn't matter too much.

 merge: approve

I don't really see why you couldn't copy across everything from the
2.5 implementation, but it isn't a big deal.

John
=:->
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk6DZ8cACgkQJdeBCYSNAAOx0QCbBkwMc4s+SflCplMbf180INWx
QJUAoJmu03qP9gZsgD60VCV+CMtzrPew
=Azyr
-----END PGP SIGNATURE-----

review: Approve
Revision history for this message
Martin Packman (gz) wrote :

> I don't really see why you couldn't copy across everything from the
> 2.5 implementation, but it isn't a big deal.

I moved a bunch of code around on trunk (see the trunk version's prerequisite mp <https://code.launchpad.net/~gz/bzr/move_pack_stat_to_dirstate_helpers/+merge/77013>) which seemed more disruptive than the plain fix here.

Revision history for this message
Martin Packman (gz) wrote :

sent to pqm by email

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bzrlib/_dirstate_helpers_pyx.pyx'
2--- bzrlib/_dirstate_helpers_pyx.pyx 2011-04-22 14:12:22 +0000
3+++ bzrlib/_dirstate_helpers_pyx.pyx 2011-09-28 17:40:34 +0000
4@@ -97,6 +97,7 @@
5 object PyTuple_GetItem_void_object "PyTuple_GET_ITEM" (void* tpl, int index)
6 object PyTuple_GET_ITEM(object tpl, Py_ssize_t index)
7
8+ unsigned long PyInt_AsUnsignedLongMask(object number) except? -1
9
10 char *PyString_AsString(object p)
11 char *PyString_AsString_obj "PyString_AsString" (PyObject *string)
12@@ -821,12 +822,13 @@
13 cdef char result[6*4] # 6 long ints
14 cdef int *aliased
15 aliased = <int *>result
16- aliased[0] = htonl(stat_value.st_size)
17- aliased[1] = htonl(int(stat_value.st_mtime))
18- aliased[2] = htonl(int(stat_value.st_ctime))
19- aliased[3] = htonl(stat_value.st_dev)
20- aliased[4] = htonl(stat_value.st_ino & 0xFFFFFFFF)
21- aliased[5] = htonl(stat_value.st_mode)
22+ aliased[0] = htonl(PyInt_AsUnsignedLongMask(stat_value.st_size))
23+ # mtime and ctime will often be floats but get converted to PyInt within
24+ aliased[1] = htonl(PyInt_AsUnsignedLongMask(stat_value.st_mtime))
25+ aliased[2] = htonl(PyInt_AsUnsignedLongMask(stat_value.st_ctime))
26+ aliased[3] = htonl(PyInt_AsUnsignedLongMask(stat_value.st_dev))
27+ aliased[4] = htonl(PyInt_AsUnsignedLongMask(stat_value.st_ino))
28+ aliased[5] = htonl(PyInt_AsUnsignedLongMask(stat_value.st_mode))
29 packed = PyString_FromStringAndSize(result, 6*4)
30 return _encode(packed)[:-1]
31
32
33=== modified file 'bzrlib/dirstate.py'
34--- bzrlib/dirstate.py 2011-07-25 07:11:56 +0000
35+++ bzrlib/dirstate.py 2011-09-28 17:40:34 +0000
36@@ -255,8 +255,9 @@
37 # Cannot pre-compile the dirstate pack_stat
38 def pack_stat(st, _encode=binascii.b2a_base64, _pack=struct.pack):
39 """Convert stat values into a packed representation."""
40- return _encode(_pack('>LLLLLL', st.st_size, int(st.st_mtime),
41- int(st.st_ctime), st.st_dev, st.st_ino & 0xFFFFFFFF,
42+ return _encode(_pack('>LLLLLL', st.st_size & 0xFFFFFFFF,
43+ int(st.st_mtime) & 0xFFFFFFFF, int(st.st_ctime) & 0xFFFFFFFF,
44+ st.st_dev & 0xFFFFFFFF, st.st_ino & 0xFFFFFFFF,
45 st.st_mode))[:-1]
46 else:
47 # compile the struct compiler we need, so as to only do it once
48
49=== modified file 'bzrlib/tests/test__dirstate_helpers.py'
50--- bzrlib/tests/test__dirstate_helpers.py 2011-05-06 15:15:44 +0000
51+++ bzrlib/tests/test__dirstate_helpers.py 2011-09-28 17:40:34 +0000
52@@ -1334,3 +1334,56 @@
53 state._sha1_provider = UppercaseSHA1Provider()
54 self.assertChangedFileIds(['file-id'], tree)
55
56+
57+class TestPackStat(tests.TestCase):
58+ """Check packed representaton of stat values is robust on all inputs"""
59+
60+ # GZ 2011-09-26: Should parametrise against all pack_stat implementations
61+
62+ @staticmethod
63+ def pack(statlike_tuple):
64+ return dirstate.pack_stat(os.stat_result(statlike_tuple))
65+
66+ @staticmethod
67+ def unpack_field(packed_string, stat_field):
68+ return dirstate._unpack_stat(packed_string)[stat_field]
69+
70+ def test_result(self):
71+ self.assertEqual("AAAQAAAAABAAAAARAAAAAgAAAAEAAIHk",
72+ self.pack((33252, 1, 2, 0, 0, 0, 4096, 15.5, 16.5, 17.5)))
73+
74+ def test_giant_inode(self):
75+ packed = self.pack((33252, 0xF80000ABC, 0, 0, 0, 0, 0, 0, 0, 0))
76+ self.assertEqual(0x80000ABC, self.unpack_field(packed, "st_ino"))
77+
78+ def test_giant_size(self):
79+ packed = self.pack((33252, 0, 0, 0, 0, 0, (1 << 33) + 4096, 0, 0, 0))
80+ self.assertEqual(4096, self.unpack_field(packed, "st_size"))
81+
82+ def test_fractional_mtime(self):
83+ packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 16.9375, 0))
84+ self.assertEqual(16, self.unpack_field(packed, "st_mtime"))
85+
86+ def test_ancient_mtime(self):
87+ packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, -11644473600.0, 0))
88+ self.assertEqual(1240428288, self.unpack_field(packed, "st_mtime"))
89+
90+ def test_distant_mtime(self):
91+ packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 64060588800.0, 0))
92+ self.assertEqual(3931046656, self.unpack_field(packed, "st_mtime"))
93+
94+ def test_fractional_ctime(self):
95+ packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, 17.5625))
96+ self.assertEqual(17, self.unpack_field(packed, "st_ctime"))
97+
98+ def test_ancient_ctime(self):
99+ packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, -11644473600.0))
100+ self.assertEqual(1240428288, self.unpack_field(packed, "st_ctime"))
101+
102+ def test_distant_ctime(self):
103+ packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, 64060588800.0))
104+ self.assertEqual(3931046656, self.unpack_field(packed, "st_ctime"))
105+
106+ def test_negative_dev(self):
107+ packed = self.pack((33252, 0, -0xFFFFFCDE, 0, 0, 0, 0, 0, 0, 0))
108+ self.assertEqual(0x322, self.unpack_field(packed, "st_dev"))
109
110=== modified file 'doc/en/release-notes/bzr-2.4.txt'
111--- doc/en/release-notes/bzr-2.4.txt 2011-09-26 08:48:20 +0000
112+++ doc/en/release-notes/bzr-2.4.txt 2011-09-28 17:40:34 +0000
113@@ -35,6 +35,10 @@
114 * Fixed loading of external merge tools from config to properly decode
115 command-lines which contain embedded quotes. (Gordon Tyler, #828803)
116
117+* Prevent several kinds of OverflowError and other fallout from failing to fit
118+ stat fields into four bytes in dirstate pack_stat implementations.
119+ (Martin Packman, #683191 #706957)
120+
121 Documentation
122 *************
123

Subscribers

People subscribed via source and target branches