From 35a886e791140edfe70a6aca8c0cbb140bc3b826 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 14 Jan 2010 12:45:39 +0100 Subject: [PATCH] fix output string length for binascii.b2a_uu() binascii_b2a_uu() estimate the output string length using 2+bin_len*2. It's almost correct... except for bin_len=1. The result is a memory write into unallocated memory: $ ./python -c "import binascii; binascii.b2a_uu('x')" Debug memory block at address p=0x87da568: API 'o' 33 bytes originally requested The 3 pad bytes at p-3 are FORBIDDENBYTE, as expected. The 4 pad bytes at tail=0x87da589 are not all FORBIDDENBYTE (0xfb): at tail+0: 0x0a *** OUCH at tail+1: 0xfb at tail+2: 0xfb at tail+3: 0xfb The block was made by call #25195 to debug malloc/realloc. Data at p: 00 00 00 00 00 00 00 00 ... 00 00 00 21 3e 20 20 20 Fatal Python error: bad trailing pad byte Abandon Current output string length estimation for input string 0..10: >>> [len(binascii.b2a_uu("x"*bin_len)) for bin_len in xrange(10)] [2, 6, 6, 6, 10, 10, 10, 14, 14, 14] >>> [(2+bin_len*2) for bin_len in xrange(10)] [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] The estimation is correct for all lengths... except for bin_len=1. And it's oversized for bin_len >= 9. The exact length is: 2+ceil(bin_len*8/6) <=> 2+(bin_len+5)//6*8 <=> 2+(bin_len+2)//3*4 Example with length 0..10: >>> [len(binascii.b2a_uu("x"*bin_len)) for bin_len in xrange(10)] [2, 6, 6, 6, 10, 10, 10, 14, 14, 14] >>> [(2+(bin_len+2)//3*4) for bin_len in xrange(10)] [2, 6, 6, 6, 10, 10, 10, 14, 14, 14] Attached patch uses the correct estimation. --- Modules/binascii.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/binascii.c b/Modules/binascii.c index bcbafcf..00d0ffd 100644 --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -282,7 +282,7 @@ binascii_b2a_uu(PyObject *self, PyObject *args) } /* We're lazy and allocate to much (fixed up later) */ - if ( (rv=PyString_FromStringAndSize(NULL, bin_len*2+2)) == NULL ) + if ( (rv=PyString_FromStringAndSize(NULL, 2 + (bin_len+2)/3*4)) == NULL ) return NULL; ascii_data = (unsigned char *)PyString_AsString(rv); -- 1.6.6