X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=bup.git;a=blobdiff_plain;f=lib%2Fbup%2F_helpers.c;h=312ecd4528a1376c7e9ced35e7fe33336b633628;hp=05b648ce98578d4f30501b181fa812e880245d94;hb=bf67f94dd4f4096de4eee07a7dc377d6c889a016;hpb=3c57e31f68b3e68bf7053a628fcfd7ccccf217cd diff --git a/lib/bup/_helpers.c b/lib/bup/_helpers.c index 05b648c..312ecd4 100644 --- a/lib/bup/_helpers.c +++ b/lib/bup/_helpers.c @@ -89,6 +89,31 @@ static state_t state; #endif // PY_MAJOR_VERSION >= 3 +static void *checked_malloc(size_t n, size_t size) +{ + size_t total; + if (__builtin_mul_overflow(n, size, &total)) + { + PyErr_Format(PyExc_OverflowError, + "request to allocate %lu items of size %lu is too large", + n, size); + return NULL; + } + void *result = malloc(total); + if (!result) + return PyErr_NoMemory(); + return result; +} + +static void *checked_calloc(size_t n, size_t size) +{ + void *result = calloc(n, size); + if (!result) + PyErr_NoMemory(); + return result; +} + + #ifndef htonll // This function should technically be macro'd out if it's going to be used // more than ocasionally. As of this writing, it'll actually never be called @@ -104,13 +129,6 @@ static uint64_t htonll(uint64_t value) #endif -#ifdef __clang__ -#define INTEGRAL_ASSIGNMENT_FITS(dest, src) \ - ({ \ - *(dest) = (src); \ - *(dest) == (src) && (*(dest) < 1) == ((src) < 1); \ - }) -#else // Disabling sign-compare here should be fine since we're explicitly // checking for a sign mismatch, i.e. if the signs don't match, then // it doesn't matter what the value comparison says. @@ -120,10 +138,10 @@ static uint64_t htonll(uint64_t value) _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wsign-compare\""); \ *(dest) = (src); \ - *(dest) == (src) && (*(dest) < 1) == ((src) < 1); \ + int result = *(dest) == (src) && (*(dest) < 1) == ((src) < 1); \ _Pragma("GCC diagnostic pop"); \ + result; \ }) -#endif // At the moment any code that calls INTEGER_TO_PY() will have to @@ -472,7 +490,7 @@ static PyObject *bup_write_sparsely(PyObject *self, PyObject *args) unsigned char *buf = NULL; Py_ssize_t sbuf_len; PyObject *py_min_sparse_len, *py_prev_sparse_len; - if (!PyArg_ParseTuple(args, "it#OO", + if (!PyArg_ParseTuple(args, "i" rbuf_argf "OO", &fd, &buf, &sbuf_len, &py_min_sparse_len, &py_prev_sparse_len)) return NULL; @@ -590,7 +608,7 @@ static PyObject *bitmatch(PyObject *self, PyObject *args) Py_ssize_t byte; int bit; - if (!PyArg_ParseTuple(args, "t#t#", &buf1, &len1, &buf2, &len2)) + if (!PyArg_ParseTuple(args, rbuf_argf rbuf_argf, &buf1, &len1, &buf2, &len2)) return NULL; bit = 0; @@ -617,7 +635,7 @@ static PyObject *firstword(PyObject *self, PyObject *args) Py_ssize_t len = 0; uint32_t v; - if (!PyArg_ParseTuple(args, "t#", &buf, &len)) + if (!PyArg_ParseTuple(args, rbuf_argf, &buf, &len)) return NULL; if (len < 4) @@ -795,7 +813,7 @@ static PyObject *extract_bits(PyObject *self, PyObject *args) Py_ssize_t len = 0; int nbits = 0; - if (!PyArg_ParseTuple(args, "t#i", &buf, &len, &nbits)) + if (!PyArg_ParseTuple(args, rbuf_argf "i", &buf, &len, &nbits)) return NULL; if (len < 4) @@ -824,7 +842,7 @@ struct idx { int name_base; }; -static void _fix_idx_order(struct idx **idxs, int *last_i) +static void _fix_idx_order(struct idx **idxs, Py_ssize_t *last_i) { struct idx *idx; int low, mid, high, c = 0; @@ -874,36 +892,51 @@ static uint32_t _get_idx_i(struct idx *idx) static PyObject *merge_into(PyObject *self, PyObject *args) { - PyObject *py_total, *ilist = NULL; - unsigned char *fmap = NULL; struct sha *sha_ptr, *sha_start = NULL; uint32_t *table_ptr, *name_ptr, *name_start; - struct idx **idxs = NULL; - Py_ssize_t flen = 0; - int bits = 0, i; + int i; unsigned int total; uint32_t count, prefix; - int num_i; - int last_i; - if (!PyArg_ParseTuple(args, "w#iOO", - &fmap, &flen, &bits, &py_total, &ilist)) + + Py_buffer fmap; + int bits;; + PyObject *py_total, *ilist = NULL; + if (!PyArg_ParseTuple(args, wbuf_argf "iOO", + &fmap, &bits, &py_total, &ilist)) return NULL; + PyObject *result = NULL; + struct idx **idxs = NULL; + Py_ssize_t num_i = 0; + int *idx_buf_init = NULL; + Py_buffer *idx_buf = NULL; + if (!bup_uint_from_py(&total, py_total, "total")) - return NULL; + goto clean_and_return; num_i = PyList_Size(ilist); - idxs = (struct idx **)PyMem_Malloc(num_i * sizeof(struct idx *)); + + if (!(idxs = checked_malloc(num_i, sizeof(struct idx *)))) + goto clean_and_return; + if (!(idx_buf_init = checked_calloc(num_i, sizeof(int)))) + goto clean_and_return; + if (!(idx_buf = checked_malloc(num_i, sizeof(Py_buffer)))) + goto clean_and_return; for (i = 0; i < num_i; i++) { long len, sha_ofs, name_map_ofs; - idxs[i] = (struct idx *)PyMem_Malloc(sizeof(struct idx)); + if (!(idxs[i] = checked_malloc(1, sizeof(struct idx)))) + goto clean_and_return; PyObject *itup = PyList_GetItem(ilist, i); - if (!PyArg_ParseTuple(itup, "t#llli", &idxs[i]->map, &idxs[i]->bytes, - &len, &sha_ofs, &name_map_ofs, &idxs[i]->name_base)) + if (!PyArg_ParseTuple(itup, wbuf_argf "llli", + &(idx_buf[i]), &len, &sha_ofs, &name_map_ofs, + &idxs[i]->name_base)) return NULL; + idx_buf_init[i] = 1; + idxs[i]->map = idx_buf[i].buf; + idxs[i]->bytes = idx_buf[i].len; idxs[i]->cur = (struct sha *)&idxs[i]->map[sha_ofs]; idxs[i]->end = &idxs[i]->cur[len]; if (name_map_ofs) @@ -911,11 +944,11 @@ static PyObject *merge_into(PyObject *self, PyObject *args) else idxs[i]->cur_name = NULL; } - table_ptr = (uint32_t *)&fmap[MIDX4_HEADERLEN]; + table_ptr = (uint32_t *) &((unsigned char *) fmap.buf)[MIDX4_HEADERLEN]; sha_start = sha_ptr = (struct sha *)&table_ptr[1<= 0) @@ -944,8 +977,25 @@ static PyObject *merge_into(PyObject *self, PyObject *args) assert(sha_ptr == sha_start+count); assert(name_ptr == name_start+count); - PyMem_Free(idxs); - return PyLong_FromUnsignedLong(count); + result = PyLong_FromUnsignedLong(count); + + clean_and_return: + if (idx_buf_init) + { + for (i = 0; i < num_i; i++) + if (idx_buf_init[i]) + PyBuffer_Release(&(idx_buf[i])); + free(idx_buf_init); + free(idx_buf); + } + if (idxs) + { + for (i = 0; i < num_i; i++) + free(idxs[i]); + free(idxs); + } + PyBuffer_Release(&fmap); + return result; } #define FAN_ENTRIES 256 @@ -955,8 +1005,6 @@ static PyObject *write_idx(PyObject *self, PyObject *args) char *filename = NULL; PyObject *py_total, *idx = NULL; PyObject *part; - unsigned char *fmap = NULL; - Py_ssize_t flen = 0; unsigned int total = 0; uint32_t count; int i, j, ofs64_count; @@ -964,21 +1012,27 @@ static PyObject *write_idx(PyObject *self, PyObject *args) uint64_t *ofs64_ptr; struct sha *sha_ptr; - if (!PyArg_ParseTuple(args, "sw#OO", - &filename, &fmap, &flen, &idx, &py_total)) + Py_buffer fmap; + if (!PyArg_ParseTuple(args, cstr_argf wbuf_argf "OO", + &filename, &fmap, &idx, &py_total)) return NULL; + PyObject *result = NULL; + if (!bup_uint_from_py(&total, py_total, "total")) - return NULL; + goto clean_and_return; if (PyList_Size (idx) != FAN_ENTRIES) // Check for list of the right length. - return PyErr_Format (PyExc_TypeError, "idx must contain %d entries", - FAN_ENTRIES); + { + result = PyErr_Format (PyExc_TypeError, "idx must contain %d entries", + FAN_ENTRIES); + goto clean_and_return; + } const char idx_header[] = "\377tOc\0\0\0\002"; - memcpy (fmap, idx_header, sizeof(idx_header) - 1); + memcpy (fmap.buf, idx_header, sizeof(idx_header) - 1); - fan_ptr = (uint32_t *)&fmap[sizeof(idx_header) - 1]; + fan_ptr = (uint32_t *)&((unsigned char *)fmap.buf)[sizeof(idx_header) - 1]; sha_ptr = (struct sha *)&fan_ptr[FAN_ENTRIES]; crc_ptr = (uint32_t *)&sha_ptr[total]; ofs_ptr = (uint32_t *)&crc_ptr[total]; @@ -1002,18 +1056,18 @@ static PyObject *write_idx(PyObject *self, PyObject *args) unsigned int crc; unsigned PY_LONG_LONG ofs_ull; uint64_t ofs; - if (!PyArg_ParseTuple(PyList_GET_ITEM(part, j), "t#OO", + if (!PyArg_ParseTuple(PyList_GET_ITEM(part, j), rbuf_argf "OO", &sha, &sha_len, &crc_py, &ofs_py)) - return NULL; + goto clean_and_return; if(!bup_uint_from_py(&crc, crc_py, "crc")) - return NULL; + goto clean_and_return; if(!bup_ullong_from_py(&ofs_ull, ofs_py, "ofs")) - return NULL; + goto clean_and_return; assert(crc <= UINT32_MAX); assert(ofs_ull <= UINT64_MAX); ofs = ofs_ull; if (sha_len != sizeof(struct sha)) - return NULL; + goto clean_and_return; memcpy(sha_ptr++, sha, sizeof(struct sha)); *crc_ptr++ = htonl(crc); if (ofs > 0x7fffffff) @@ -1025,11 +1079,18 @@ static PyObject *write_idx(PyObject *self, PyObject *args) } } - int rc = msync(fmap, flen, MS_ASYNC); + int rc = msync(fmap.buf, fmap.len, MS_ASYNC); if (rc != 0) - return PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename); + { + result = PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename); + goto clean_and_return; + } + + result = PyLong_FromUnsignedLong(count); - return PyLong_FromUnsignedLong(count); + clean_and_return: + PyBuffer_Release(&fmap); + return result; } @@ -1103,7 +1164,7 @@ static PyObject *random_sha(PyObject *self, PyObject *args) memset(shabuf, 0, sizeof(shabuf)); for (i=0; i < 20/4; i++) shabuf[i] = random(); - return Py_BuildValue("s#", shabuf, 20); + return Py_BuildValue(rbuf_argf, shabuf, 20); } @@ -1139,7 +1200,7 @@ static PyObject *open_noatime(PyObject *self, PyObject *args) { char *filename = NULL; int fd; - if (!PyArg_ParseTuple(args, "s", &filename)) + if (!PyArg_ParseTuple(args, cstr_argf, &filename)) return NULL; fd = _open_noatime(filename, 0); if (fd < 0) @@ -1186,7 +1247,7 @@ static PyObject *bup_get_linux_file_attr(PyObject *self, PyObject *args) char *path; int fd; - if (!PyArg_ParseTuple(args, "s", &path)) + if (!PyArg_ParseTuple(args, cstr_argf, &path)) return NULL; fd = _open_noatime(path, O_NONBLOCK); @@ -1218,7 +1279,7 @@ static PyObject *bup_set_linux_file_attr(PyObject *self, PyObject *args) PyObject *py_attr; int fd; - if (!PyArg_ParseTuple(args, "sO", &path, &py_attr)) + if (!PyArg_ParseTuple(args, cstr_argf "O", &path, &py_attr)) return NULL; if (!bup_uint_from_py(&attr, py_attr, "attr")) @@ -1679,6 +1740,7 @@ static void test_integral_assignment_fits(void) assert(sizeof(signed short) < sizeof(unsigned long long)); assert(sizeof(unsigned short) < sizeof(signed long long)); assert(sizeof(unsigned short) < sizeof(unsigned long long)); + assert(sizeof(Py_ssize_t) <= sizeof(size_t)); { signed short ss, ssmin = SHRT_MIN, ssmax = SHRT_MAX; unsigned short us, usmax = USHRT_MAX;