mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-02-12 07:10:33 +03:00
More careful memory management
- Check return value of PyErr_Malloc and set an exception in case of error - Avoid exposing variables with refcount 0 as connection attributes. - PyErr_Free guards itself for NULL input
This commit is contained in:
parent
143dc2e911
commit
c1715f66fe
|
@ -984,14 +984,22 @@ conn_set_client_encoding(connectionObject *self, const char *enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no error, we can proceeed and store the new encoding */
|
/* no error, we can proceeed and store the new encoding */
|
||||||
PyMem_Free(self->encoding);
|
{
|
||||||
|
char *tmp = self->encoding;
|
||||||
|
self->encoding = NULL;
|
||||||
|
PyMem_Free(tmp);
|
||||||
|
}
|
||||||
if (!(self->encoding = psycopg_strdup(enc, 0))) {
|
if (!(self->encoding = psycopg_strdup(enc, 0))) {
|
||||||
res = 1; /* don't call pq_complete_error below */
|
res = 1; /* don't call pq_complete_error below */
|
||||||
goto endlock;
|
goto endlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store the python codec too. */
|
/* Store the python codec too. */
|
||||||
PyMem_Free(self->codec);
|
{
|
||||||
|
char *tmp = self->codec;
|
||||||
|
self->codec = NULL;
|
||||||
|
PyMem_Free(tmp);
|
||||||
|
}
|
||||||
self->codec = codec;
|
self->codec = codec;
|
||||||
|
|
||||||
Dprintf("conn_set_client_encoding: set encoding to %s (codec: %s)",
|
Dprintf("conn_set_client_encoding: set encoding to %s (codec: %s)",
|
||||||
|
|
|
@ -1011,7 +1011,9 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
/* allocate some memory, build the SQL and create a PyString from it */
|
/* allocate some memory, build the SQL and create a PyString from it */
|
||||||
sl = procname_len + 17 + nparameters*3 - (nparameters ? 1 : 0);
|
sl = procname_len + 17 + nparameters*3 - (nparameters ? 1 : 0);
|
||||||
sql = (char*)PyMem_Malloc(sl);
|
sql = (char*)PyMem_Malloc(sl);
|
||||||
if (sql == NULL) return NULL;
|
if (sql == NULL) {
|
||||||
|
return PyErr_NoMemory();
|
||||||
|
}
|
||||||
|
|
||||||
sprintf(sql, "SELECT * FROM %s(", procname);
|
sprintf(sql, "SELECT * FROM %s(", procname);
|
||||||
for(i=0; i<nparameters; i++) {
|
for(i=0; i<nparameters; i++) {
|
||||||
|
@ -1233,15 +1235,16 @@ _psyco_curs_has_read_check(PyObject* o, void* var)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs)
|
psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
|
char *query = NULL;
|
||||||
char query_buffer[DEFAULT_COPYBUFF];
|
char query_buffer[DEFAULT_COPYBUFF];
|
||||||
Py_ssize_t query_size;
|
Py_ssize_t query_size;
|
||||||
char *query;
|
|
||||||
const char *table_name;
|
const char *table_name;
|
||||||
const char *sep = "\t", *null = NULL;
|
const char *sep = "\t", *null = NULL;
|
||||||
Py_ssize_t bufsize = DEFAULT_COPYBUFF;
|
Py_ssize_t bufsize = DEFAULT_COPYBUFF;
|
||||||
PyObject *file, *columns = NULL, *res = NULL;
|
PyObject *file, *columns = NULL, *res = NULL;
|
||||||
char columnlist[DEFAULT_COPYBUFF];
|
char columnlist[DEFAULT_COPYBUFF];
|
||||||
char *quoted_delimiter;
|
char *quoted_delimiter = NULL;
|
||||||
|
char *quoted_null = NULL;
|
||||||
|
|
||||||
static char *kwlist[] = {
|
static char *kwlist[] = {
|
||||||
"file", "table", "sep", "null", "size", "columns", NULL};
|
"file", "table", "sep", "null", "size", "columns", NULL};
|
||||||
|
@ -1262,32 +1265,32 @@ psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
EXC_IF_GREEN(copy_from);
|
EXC_IF_GREEN(copy_from);
|
||||||
EXC_IF_TPC_PREPARED(self->conn, copy_from);
|
EXC_IF_TPC_PREPARED(self->conn, copy_from);
|
||||||
|
|
||||||
|
if (!(quoted_delimiter = psycopg_escape_string(
|
||||||
quoted_delimiter = psycopg_escape_string((PyObject*)self->conn, sep, 0, NULL, NULL);
|
(PyObject*)self->conn, sep, 0, NULL, NULL))) {
|
||||||
if (quoted_delimiter == NULL) {
|
|
||||||
PyErr_NoMemory();
|
PyErr_NoMemory();
|
||||||
return NULL;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
query = query_buffer;
|
query = query_buffer;
|
||||||
if (null) {
|
if (null) {
|
||||||
char *quoted_null = psycopg_escape_string((PyObject*)self->conn, null, 0, NULL, NULL);
|
if (!(quoted_null = psycopg_escape_string(
|
||||||
if (quoted_null == NULL) {
|
(PyObject*)self->conn, null, 0, NULL, NULL))) {
|
||||||
PyMem_Free(quoted_delimiter);
|
|
||||||
PyErr_NoMemory();
|
PyErr_NoMemory();
|
||||||
return NULL;
|
goto exit;
|
||||||
}
|
}
|
||||||
query_size = PyOS_snprintf(query, DEFAULT_COPYBUFF,
|
query_size = PyOS_snprintf(query, DEFAULT_COPYBUFF,
|
||||||
"COPY %s%s FROM stdin WITH DELIMITER AS %s NULL AS %s",
|
"COPY %s%s FROM stdin WITH DELIMITER AS %s NULL AS %s",
|
||||||
table_name, columnlist, quoted_delimiter, quoted_null);
|
table_name, columnlist, quoted_delimiter, quoted_null);
|
||||||
if (query_size >= DEFAULT_COPYBUFF) {
|
if (query_size >= DEFAULT_COPYBUFF) {
|
||||||
/* Got truncated, allocate dynamically */
|
/* Got truncated, allocate dynamically */
|
||||||
query = (char *)PyMem_Malloc((query_size + 1) * sizeof(char));
|
if (!(query = PyMem_New(char, query_size + 1))) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
PyOS_snprintf(query, query_size + 1,
|
PyOS_snprintf(query, query_size + 1,
|
||||||
"COPY %s%s FROM stdin WITH DELIMITER AS %s NULL AS %s",
|
"COPY %s%s FROM stdin WITH DELIMITER AS %s NULL AS %s",
|
||||||
table_name, columnlist, quoted_delimiter, quoted_null);
|
table_name, columnlist, quoted_delimiter, quoted_null);
|
||||||
}
|
}
|
||||||
PyMem_Free(quoted_null);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
query_size = PyOS_snprintf(query, DEFAULT_COPYBUFF,
|
query_size = PyOS_snprintf(query, DEFAULT_COPYBUFF,
|
||||||
|
@ -1295,13 +1298,15 @@ psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
table_name, columnlist, quoted_delimiter);
|
table_name, columnlist, quoted_delimiter);
|
||||||
if (query_size >= DEFAULT_COPYBUFF) {
|
if (query_size >= DEFAULT_COPYBUFF) {
|
||||||
/* Got truncated, allocate dynamically */
|
/* Got truncated, allocate dynamically */
|
||||||
query = (char *)PyMem_Malloc((query_size + 1) * sizeof(char));
|
if (!(query = PyMem_New(char, query_size + 1))) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
PyOS_snprintf(query, query_size + 1,
|
PyOS_snprintf(query, query_size + 1,
|
||||||
"COPY %s%s FROM stdin WITH DELIMITER AS %s",
|
"COPY %s%s FROM stdin WITH DELIMITER AS %s",
|
||||||
table_name, columnlist, quoted_delimiter);
|
table_name, columnlist, quoted_delimiter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PyMem_Free(quoted_delimiter);
|
|
||||||
|
|
||||||
Dprintf("psyco_curs_copy_from: query = %s", query);
|
Dprintf("psyco_curs_copy_from: query = %s", query);
|
||||||
|
|
||||||
|
@ -1313,11 +1318,13 @@ psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (query && (query != query_buffer)) {
|
|
||||||
PyMem_Free(query);
|
|
||||||
}
|
|
||||||
self->copyfile = NULL;
|
self->copyfile = NULL;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
PyMem_Free(quoted_delimiter);
|
||||||
|
PyMem_Free(quoted_null);
|
||||||
|
if (query != query_buffer) { PyMem_Free(query); }
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1352,7 +1359,8 @@ psyco_curs_copy_to(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
const char *table_name;
|
const char *table_name;
|
||||||
const char *sep = "\t", *null = NULL;
|
const char *sep = "\t", *null = NULL;
|
||||||
PyObject *file, *columns = NULL, *res = NULL;
|
PyObject *file, *columns = NULL, *res = NULL;
|
||||||
char *quoted_delimiter;
|
char *quoted_delimiter = NULL;
|
||||||
|
char *quoted_null = NULL;
|
||||||
|
|
||||||
static char *kwlist[] = {"file", "table", "sep", "null", "columns", NULL};
|
static char *kwlist[] = {"file", "table", "sep", "null", "columns", NULL};
|
||||||
|
|
||||||
|
@ -1370,31 +1378,32 @@ psyco_curs_copy_to(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
EXC_IF_GREEN(copy_to);
|
EXC_IF_GREEN(copy_to);
|
||||||
EXC_IF_TPC_PREPARED(self->conn, copy_to);
|
EXC_IF_TPC_PREPARED(self->conn, copy_to);
|
||||||
|
|
||||||
quoted_delimiter = psycopg_escape_string((PyObject*)self->conn, sep, 0, NULL, NULL);
|
if (!(quoted_delimiter = psycopg_escape_string(
|
||||||
if (quoted_delimiter == NULL) {
|
(PyObject*)self->conn, sep, 0, NULL, NULL))) {
|
||||||
PyErr_NoMemory();
|
PyErr_NoMemory();
|
||||||
return NULL;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
query = query_buffer;
|
query = query_buffer;
|
||||||
if (null) {
|
if (null) {
|
||||||
char *quoted_null = psycopg_escape_string((PyObject*)self->conn, null, 0, NULL, NULL);
|
if (!(quoted_null = psycopg_escape_string(
|
||||||
if (NULL == quoted_null) {
|
(PyObject*)self->conn, null, 0, NULL, NULL))) {
|
||||||
PyMem_Free(quoted_delimiter);
|
|
||||||
PyErr_NoMemory();
|
PyErr_NoMemory();
|
||||||
return NULL;
|
goto exit;
|
||||||
}
|
}
|
||||||
query_size = PyOS_snprintf(query, DEFAULT_COPYBUFF,
|
query_size = PyOS_snprintf(query, DEFAULT_COPYBUFF,
|
||||||
"COPY %s%s TO stdout WITH DELIMITER AS %s"
|
"COPY %s%s TO stdout WITH DELIMITER AS %s"
|
||||||
" NULL AS %s", table_name, columnlist, quoted_delimiter, quoted_null);
|
" NULL AS %s", table_name, columnlist, quoted_delimiter, quoted_null);
|
||||||
if (query_size >= DEFAULT_COPYBUFF) {
|
if (query_size >= DEFAULT_COPYBUFF) {
|
||||||
/* Got truncated, allocate dynamically */
|
/* Got truncated, allocate dynamically */
|
||||||
query = (char *)PyMem_Malloc((query_size + 1) * sizeof(char));
|
if (!(query = PyMem_New(char, query_size + 1))) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
PyOS_snprintf(query, query_size + 1,
|
PyOS_snprintf(query, query_size + 1,
|
||||||
"COPY %s%s TO stdout WITH DELIMITER AS %s"
|
"COPY %s%s TO stdout WITH DELIMITER AS %s"
|
||||||
" NULL AS %s", table_name, columnlist, quoted_delimiter, quoted_null);
|
" NULL AS %s", table_name, columnlist, quoted_delimiter, quoted_null);
|
||||||
}
|
}
|
||||||
PyMem_Free(quoted_null);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
query_size = PyOS_snprintf(query, DEFAULT_COPYBUFF,
|
query_size = PyOS_snprintf(query, DEFAULT_COPYBUFF,
|
||||||
|
@ -1402,13 +1411,15 @@ psyco_curs_copy_to(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
table_name, columnlist, quoted_delimiter);
|
table_name, columnlist, quoted_delimiter);
|
||||||
if (query_size >= DEFAULT_COPYBUFF) {
|
if (query_size >= DEFAULT_COPYBUFF) {
|
||||||
/* Got truncated, allocate dynamically */
|
/* Got truncated, allocate dynamically */
|
||||||
query = (char *)PyMem_Malloc((query_size + 1) * sizeof(char));
|
if (!(query = PyMem_New(char, query_size + 1))) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
PyOS_snprintf(query, query_size + 1,
|
PyOS_snprintf(query, query_size + 1,
|
||||||
"COPY %s%s TO stdout WITH DELIMITER AS %s",
|
"COPY %s%s TO stdout WITH DELIMITER AS %s",
|
||||||
table_name, columnlist, quoted_delimiter);
|
table_name, columnlist, quoted_delimiter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PyMem_Free(quoted_delimiter);
|
|
||||||
|
|
||||||
Dprintf("psyco_curs_copy_to: query = %s", query);
|
Dprintf("psyco_curs_copy_to: query = %s", query);
|
||||||
|
|
||||||
|
@ -1419,11 +1430,13 @@ psyco_curs_copy_to(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
res = Py_None;
|
res = Py_None;
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
}
|
}
|
||||||
if (query && (query != query_buffer)) {
|
|
||||||
PyMem_Free(query);
|
|
||||||
}
|
|
||||||
self->copyfile = NULL;
|
self->copyfile = NULL;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
PyMem_Free(quoted_delimiter);
|
||||||
|
PyMem_Free(quoted_null);
|
||||||
|
if (query != query_buffer) { PyMem_Free(query); }
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1653,8 +1666,10 @@ cursor_setup(cursorObject *self, connectionObject *conn, const char *name)
|
||||||
Dprintf("cursor_setup: parameters: name = %s, conn = %p", name, conn);
|
Dprintf("cursor_setup: parameters: name = %s, conn = %p", name, conn);
|
||||||
|
|
||||||
if (name) {
|
if (name) {
|
||||||
self->name = PyMem_Malloc(strlen(name)+1);
|
if (!(self->name = PyMem_Malloc(strlen(name)+1))) {
|
||||||
if (self->name == NULL) return 1;
|
PyErr_NoMemory();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
strncpy(self->name, name, strlen(name)+1);
|
strncpy(self->name, name, strlen(name)+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1715,7 +1730,7 @@ cursor_dealloc(PyObject* obj)
|
||||||
|
|
||||||
PyObject_GC_UnTrack(self);
|
PyObject_GC_UnTrack(self);
|
||||||
|
|
||||||
if (self->name) PyMem_Free(self->name);
|
PyMem_Free(self->name);
|
||||||
|
|
||||||
Py_CLEAR(self->conn);
|
Py_CLEAR(self->conn);
|
||||||
Py_CLEAR(self->casts);
|
Py_CLEAR(self->casts);
|
||||||
|
|
|
@ -110,6 +110,8 @@ _lobject_parse_mode(const char *mode)
|
||||||
/* Return a string representing the lobject mode.
|
/* Return a string representing the lobject mode.
|
||||||
*
|
*
|
||||||
* The return value is a new string allocated on the Python heap.
|
* The return value is a new string allocated on the Python heap.
|
||||||
|
*
|
||||||
|
* The function must be called holding the GIL.
|
||||||
*/
|
*/
|
||||||
static char *
|
static char *
|
||||||
_lobject_unparse_mode(int mode)
|
_lobject_unparse_mode(int mode)
|
||||||
|
@ -118,7 +120,10 @@ _lobject_unparse_mode(int mode)
|
||||||
char *c;
|
char *c;
|
||||||
|
|
||||||
/* the longest is 'rwt' */
|
/* the longest is 'rwt' */
|
||||||
c = buf = PyMem_Malloc(4);
|
if (!(c = buf = PyMem_Malloc(4))) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (mode & LOBJECT_READ) { *c++ = 'r'; }
|
if (mode & LOBJECT_READ) { *c++ = 'r'; }
|
||||||
if (mode & LOBJECT_WRITE) { *c++ = 'w'; }
|
if (mode & LOBJECT_WRITE) { *c++ = 'w'; }
|
||||||
|
@ -204,7 +209,14 @@ lobject_open(lobjectObject *self, connectionObject *conn,
|
||||||
|
|
||||||
/* set the mode for future reference */
|
/* set the mode for future reference */
|
||||||
self->mode = mode;
|
self->mode = mode;
|
||||||
|
Py_BLOCK_THREADS;
|
||||||
self->smode = _lobject_unparse_mode(mode);
|
self->smode = _lobject_unparse_mode(mode);
|
||||||
|
Py_UNBLOCK_THREADS;
|
||||||
|
if (NULL == self->smode) {
|
||||||
|
retvalue = 1; /* exception already set */
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
retvalue = 0;
|
retvalue = 0;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
@ -213,6 +225,8 @@ lobject_open(lobjectObject *self, connectionObject *conn,
|
||||||
|
|
||||||
if (retvalue < 0)
|
if (retvalue < 0)
|
||||||
pq_complete_error(self->conn, &pgres, &error);
|
pq_complete_error(self->conn, &pgres, &error);
|
||||||
|
/* if retvalue > 0, an exception is already set */
|
||||||
|
|
||||||
return retvalue;
|
return retvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -344,7 +344,7 @@ lobject_setup(lobjectObject *self, connectionObject *conn,
|
||||||
self->fd = -1;
|
self->fd = -1;
|
||||||
self->oid = InvalidOid;
|
self->oid = InvalidOid;
|
||||||
|
|
||||||
if (lobject_open(self, conn, oid, smode, new_oid, new_file) == -1)
|
if (0 != lobject_open(self, conn, oid, smode, new_oid, new_file))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
Dprintf("lobject_setup: good lobject object at %p, refcnt = "
|
Dprintf("lobject_setup: good lobject object at %p, refcnt = "
|
||||||
|
|
|
@ -135,7 +135,10 @@ typecast_array_tokenize(const char *str, Py_ssize_t strlength,
|
||||||
if (res == ASCAN_QUOTED) {
|
if (res == ASCAN_QUOTED) {
|
||||||
Py_ssize_t j;
|
Py_ssize_t j;
|
||||||
char *buffer = PyMem_Malloc(l+1);
|
char *buffer = PyMem_Malloc(l+1);
|
||||||
if (buffer == NULL) return ASCAN_ERROR;
|
if (buffer == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return ASCAN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
*token = buffer;
|
*token = buffer;
|
||||||
|
|
||||||
|
|
|
@ -201,10 +201,8 @@ typecast_BINARY_cast(const char *s, Py_ssize_t l, PyObject *curs)
|
||||||
/* str's mem was allocated by PQunescapeBytea; must use PQfreemem: */
|
/* str's mem was allocated by PQunescapeBytea; must use PQfreemem: */
|
||||||
PQfreemem(str);
|
PQfreemem(str);
|
||||||
}
|
}
|
||||||
if (buffer != NULL) {
|
|
||||||
/* We allocated buffer with PyMem_Malloc; must use PyMem_Free: */
|
/* We allocated buffer with PyMem_Malloc; must use PyMem_Free: */
|
||||||
PyMem_Free(buffer);
|
PyMem_Free(buffer);
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -436,7 +436,6 @@ _xid_decode64(PyObject *s)
|
||||||
* in order to allow some form of interoperation.
|
* in order to allow some form of interoperation.
|
||||||
*
|
*
|
||||||
* The function must be called while holding the GIL.
|
* The function must be called while holding the GIL.
|
||||||
* Return a buffer allocated with PyMem_Malloc. Use PyMem_Free to free it.
|
|
||||||
*
|
*
|
||||||
* see also: the pgjdbc implementation
|
* see also: the pgjdbc implementation
|
||||||
* http://cvs.pgfoundry.org/cgi-bin/cvsweb.cgi/jdbc/pgjdbc/org/postgresql/xa/RecoveredXid.java?rev=1.2
|
* http://cvs.pgfoundry.org/cgi-bin/cvsweb.cgi/jdbc/pgjdbc/org/postgresql/xa/RecoveredXid.java?rev=1.2
|
||||||
|
|
Loading…
Reference in New Issue
Block a user