My favorites
▼
|
Sign in
pyodbc
Python ODBC library
Project Home
Downloads
Wiki
READ-ONLY: This project has been
archived
. For more information see
this post
.
Search
Search within:
All issues
Open issues
New issues
Issues to verify
for
Advanced search
Search tips
Subscriptions
Issue
145
attachment: pyodbc-paramleak-fix.patch
(2.6 KB)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
diff --git a/src/cursor.h b/src/cursor.h
index e7be1c9..d69cd4f 100644
--- a/src/cursor.h
+++ b/src/cursor.h
@@ -52,6 +52,10 @@ struct ParamInfo
// If true, the memory in ParameterValuePtr was allocated via malloc and must be freed.
bool allocated;
+ // The python object containing the parameter value. A reference to this
+ // object should be held until we have finished using memory owned by it.
+ PyObject *pyParameterValue;
+
// Optional data. If used, ParameterValuePtr will point into this.
union
{
diff --git a/src/params.cpp b/src/params.cpp
index 4180bc0..3fbab48 100644
--- a/src/params.cpp
+++ b/src/params.cpp
@@ -20,8 +20,11 @@ static bool GetParamType(Cursor* cur, Py_ssize_t iParam, SQLSMALLINT& type);
static void FreeInfos(ParamInfo* a, Py_ssize_t count)
{
for (Py_ssize_t i = 0; i < count; i++)
+ {
if (a[i].allocated)
pyodbc_free(a[i].ParameterValuePtr);
+ Py_DECREF(a[i].pyParameterValue);
+ }
pyodbc_free(a);
}
@@ -454,6 +457,10 @@ static bool GetParameterInfo(Cursor* cur, Py_ssize_t index, PyObject* param, Par
{
// Binds the given parameter and populates `info`.
+ // Hold a reference to param until info is freed, because info will often be
+ // holding data borrowed from param.
+ info.pyParameterValue = param;
+
if (param == Py_None)
return GetNullInfo(cur, index, info);
@@ -560,8 +567,7 @@ bool PrepareAndBind(Cursor* cur, PyObject* pSql, PyObject* original_params, bool
//
// Since we may replace parameters (we replace objects with Py_True/Py_False when writing to a bit/bool column),
- // allocate an array and use it instead of the original sequence. Since we don't change ownership we don't bother
- // with incref. (That is, PySequence_GetItem will INCREF and ~ObjectArrayHolder will DECREF.)
+ // allocate an array and use it instead of the original sequence.
int params_offset = skip_first ? 1 : 0;
Py_ssize_t cParams = original_params == 0 ? 0 : PySequence_Length(original_params) - params_offset;
@@ -641,7 +647,10 @@ bool PrepareAndBind(Cursor* cur, PyObject* pSql, PyObject* original_params, bool
for (Py_ssize_t i = 0; i < cParams; i++)
{
+ // PySequence_GetItem returns a *new* reference
PyObject* param = PySequence_GetItem(original_params, i + params_offset);
+ // cur->paramInfos[i] assumes ownership of param reference here;
+ // it will be released when FreeInfos is called.
if (!GetParameterInfo(cur, i, param, cur->paramInfos[i]))
{
FreeInfos(cur->paramInfos, cParams);
Powered by
Google Project Hosting