summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog2
-rw-r--r--psycopg/typecast_binary.c71
2 files changed, 56 insertions, 17 deletions
diff --git a/ChangeLog b/ChangeLog
index 1d828b3..0f847ef 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,7 @@
2007-04-13 Federico Di Gregorio <fog@initd.org>
+ * Applied patch from David Rushby: typecast_binary.c cleanup.
+
* Applied patch from David Rushby for int->size_t transition.
2007-04-12 Federico Di Gregorio <fog@initd.org>
diff --git a/psycopg/typecast_binary.c b/psycopg/typecast_binary.c
index 63c5c22..52674dd 100644
--- a/psycopg/typecast_binary.c
+++ b/psycopg/typecast_binary.c
@@ -156,11 +156,11 @@ typecast_BINARY_cast_unescape(unsigned char *str, size_t *to_length)
#endif
static PyObject *
-typecast_BINARY_cast(char *s, int l, PyObject *curs)
+typecast_BINARY_cast(char *s, Py_ssize_t l, PyObject *curs)
{
- chunkObject *chunk;
- PyObject *res;
- char *str, *buffer = NULL;
+ chunkObject *chunk = NULL;
+ PyObject *res = NULL;
+ char *str = NULL, *buffer = NULL;
size_t len;
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
@@ -169,28 +169,65 @@ typecast_BINARY_cast(char *s, int l, PyObject *curs)
want to copy the whole buffer, right? Wrong, but there isn't any other
way <g> */
if (s[l] != '\0') {
- if ((buffer = PyMem_Malloc(l+1)) == NULL)
+ if ((buffer = PyMem_Malloc(l+1)) == NULL) {
PyErr_NoMemory();
- strncpy(buffer, s, l);
+ goto fail;
+ }
+ /* Py_ssize_t->size_t cast is safe, as long as the Py_ssize_t is
+ * >= 0: */
+ assert (l >= 0);
+ strncpy(buffer, s, (size_t) l);
+
buffer[l] = '\0';
s = buffer;
}
str = (char*)PQunescapeBytea((unsigned char*)s, &len);
Dprintf("typecast_BINARY_cast: unescaped " FORMAT_CODE_SIZE_T " bytes",
len);
- if (buffer) PyMem_Free(buffer);
+
+ /* The type of the second parameter to PQunescapeBytea is size_t *, so it's
+ * possible (especially with Python < 2.5) to get a return value too large
+ * to fit into a Python container. */
+ if (len > (size_t) PY_SSIZE_T_MAX) {
+ PyErr_SetString(PyExc_IndexError, "PG buffer too large to fit in Python"
+ " buffer.");
+ goto fail;
+ }
chunk = (chunkObject *) PyObject_New(chunkObject, &chunkType);
- if (chunk == NULL) return NULL;
+ if (chunk == NULL) goto fail;
+ /* **Transfer** ownership of str's memory to the chunkObject: */
chunk->base = str;
- chunk->len = len;
- if ((res = PyBuffer_FromObject((PyObject *)chunk, 0, len)) == NULL)
- return NULL;
-
- /* PyBuffer_FromObject() created a new reference. Release our reference so
- that the memory can be freed once the buffer is garbage collected. */
- Py_DECREF(chunk);
-
- return res;
+ str = NULL;
+
+ /* size_t->Py_ssize_t cast was validated above: */
+ chunk->len = (Py_ssize_t) len;
+ if ((res = PyBuffer_FromObject((PyObject *)chunk, 0, chunk->len)) == NULL)
+ goto fail;
+ /* PyBuffer_FromObject() created a new reference. We'll release our
+ * reference held in 'chunk' in the 'cleanup' clause. */
+
+ goto cleanup;
+ fail:
+ assert (PyErr_Occurred());
+ if (res != NULL) {
+ Py_DECREF(res);
+ res = NULL;
+ }
+ /* Fall through to cleanup: */
+ cleanup:
+ if (chunk != NULL) {
+ Py_DECREF((PyObject *) chunk);
+ }
+ if (str != NULL) {
+ /* str's mem was allocated by PQunescapeBytea; must use free: */
+ free(str);
+ }
+ if (buffer != NULL) {
+ /* We allocated buffer with PyMem_Malloc; must use PyMem_Free: */
+ PyMem_Free(buffer);
+ }
+
+ return res;
}