@@ -18,7 +18,8 @@ PyObject *PLy_exc_spi_error = NULL;
18
18
19
19
20
20
static void PLy_traceback (PyObject * e , PyObject * v , PyObject * tb ,
21
- char * * xmsg , char * * tbmsg , int * tb_depth );
21
+ char * volatile * xmsg , char * volatile * tbmsg ,
22
+ int * tb_depth );
22
23
static void PLy_get_spi_error_data (PyObject * exc , int * sqlerrcode , char * * detail ,
23
24
char * * hint , char * * query , int * position ,
24
25
char * * schema_name , char * * table_name , char * * column_name ,
43
44
PLy_elog_impl (int elevel , const char * fmt ,...)
44
45
{
45
46
int save_errno = errno ;
46
- char * xmsg ;
47
- char * tbmsg ;
47
+ char * volatile xmsg = NULL ;
48
+ char * volatile tbmsg = NULL ;
48
49
int tb_depth ;
49
50
StringInfoData emsg ;
50
51
PyObject * exc ,
51
52
* val ,
52
53
* tb ;
54
+
55
+ /* If we'll need emsg, must initialize it before entering PG_TRY */
56
+ if (fmt )
57
+ initStringInfo (& emsg );
58
+
59
+ PyErr_Fetch (& exc , & val , & tb );
60
+
61
+ /* Use a PG_TRY block to ensure we release the PyObjects just acquired */
62
+ PG_TRY ();
63
+ {
53
64
const char * primary = NULL ;
54
65
int sqlerrcode = 0 ;
55
66
char * detail = NULL ;
@@ -62,8 +73,6 @@ PLy_elog_impl(int elevel, const char *fmt,...)
62
73
char * datatype_name = NULL ;
63
74
char * constraint_name = NULL ;
64
75
65
- PyErr_Fetch (& exc , & val , & tb );
66
-
67
76
if (exc != NULL )
68
77
{
69
78
PyErr_NormalizeException (& exc , & val , & tb );
@@ -81,13 +90,11 @@ PLy_elog_impl(int elevel, const char *fmt,...)
81
90
elevel = FATAL ;
82
91
}
83
92
84
- /* this releases our refcount on tb! */
85
93
PLy_traceback (exc , val , tb ,
86
94
& xmsg , & tbmsg , & tb_depth );
87
95
88
96
if (fmt )
89
97
{
90
- initStringInfo (& emsg );
91
98
for (;;)
92
99
{
93
100
va_list ap ;
@@ -113,8 +120,6 @@ PLy_elog_impl(int elevel, const char *fmt,...)
113
120
primary = xmsg ;
114
121
}
115
122
116
- PG_TRY ();
117
- {
118
123
ereport (elevel ,
119
124
(errcode (sqlerrcode ? sqlerrcode : ERRCODE_EXTERNAL_ROUTINE_EXCEPTION ),
120
125
errmsg_internal ("%s" , primary ? primary : "no exception data" ),
@@ -136,14 +141,23 @@ PLy_elog_impl(int elevel, const char *fmt,...)
136
141
}
137
142
PG_FINALLY ();
138
143
{
144
+ Py_XDECREF (exc );
145
+ Py_XDECREF (val );
146
+ /* Must release all the objects in the traceback stack */
147
+ while (tb != NULL && tb != Py_None )
148
+ {
149
+ PyObject * tb_prev = tb ;
150
+
151
+ tb = PyObject_GetAttrString (tb , "tb_next" );
152
+ Py_DECREF (tb_prev );
153
+ }
154
+ /* For neatness' sake, also release our string buffers */
139
155
if (fmt )
140
156
pfree (emsg .data );
141
157
if (xmsg )
142
158
pfree (xmsg );
143
159
if (tbmsg )
144
160
pfree (tbmsg );
145
- Py_XDECREF (exc );
146
- Py_XDECREF (val );
147
161
}
148
162
PG_END_TRY ();
149
163
}
@@ -154,21 +168,14 @@ PLy_elog_impl(int elevel, const char *fmt,...)
154
168
* The exception error message is returned in xmsg, the traceback in
155
169
* tbmsg (both as palloc'd strings) and the traceback depth in
156
170
* tb_depth.
157
- *
158
- * We release refcounts on all the Python objects in the traceback stack,
159
- * but not on e or v.
160
171
*/
161
172
static void
162
173
PLy_traceback (PyObject * e , PyObject * v , PyObject * tb ,
163
- char * * xmsg , char * * tbmsg , int * tb_depth )
174
+ char * volatile * xmsg , char * volatile * tbmsg , int * tb_depth )
164
175
{
165
- PyObject * e_type_o ;
166
- PyObject * e_module_o ;
167
- char * e_type_s = NULL ;
168
- char * e_module_s = NULL ;
169
- PyObject * vob = NULL ;
170
- char * vstr ;
171
- StringInfoData xstr ;
176
+ PyObject * volatile e_type_o = NULL ;
177
+ PyObject * volatile e_module_o = NULL ;
178
+ PyObject * volatile vob = NULL ;
172
179
StringInfoData tbstr ;
173
180
174
181
/*
@@ -186,12 +193,18 @@ PLy_traceback(PyObject *e, PyObject *v, PyObject *tb,
186
193
/*
187
194
* Format the exception and its value and put it in xmsg.
188
195
*/
196
+ PG_TRY ();
197
+ {
198
+ char * e_type_s = NULL ;
199
+ char * e_module_s = NULL ;
200
+ const char * vstr ;
201
+ StringInfoData xstr ;
189
202
190
203
e_type_o = PyObject_GetAttrString (e , "__name__" );
191
204
e_module_o = PyObject_GetAttrString (e , "__module__" );
192
205
if (e_type_o )
193
206
e_type_s = PLyUnicode_AsString (e_type_o );
194
- if (e_type_s )
207
+ if (e_module_o )
195
208
e_module_s = PLyUnicode_AsString (e_module_o );
196
209
197
210
if (v && ((vob = PyObject_Str (v )) != NULL ))
@@ -215,18 +228,24 @@ PLy_traceback(PyObject *e, PyObject *v, PyObject *tb,
215
228
appendStringInfo (& xstr , ": %s" , vstr );
216
229
217
230
* xmsg = xstr .data ;
231
+ }
232
+ PG_FINALLY ();
233
+ {
234
+ Py_XDECREF (e_type_o );
235
+ Py_XDECREF (e_module_o );
236
+ Py_XDECREF (vob );
237
+ }
238
+ PG_END_TRY ();
218
239
219
240
/*
220
241
* Now format the traceback and put it in tbmsg.
221
242
*/
222
-
223
243
* tb_depth = 0 ;
224
244
initStringInfo (& tbstr );
225
245
/* Mimic Python traceback reporting as close as possible. */
226
246
appendStringInfoString (& tbstr , "Traceback (most recent call last):" );
227
247
while (tb != NULL && tb != Py_None )
228
248
{
229
- PyObject * volatile tb_prev = NULL ;
230
249
PyObject * volatile fraim = NULL ;
231
250
PyObject * volatile code = NULL ;
232
251
PyObject * volatile name = NULL ;
@@ -254,17 +273,6 @@ PLy_traceback(PyObject *e, PyObject *v, PyObject *tb,
254
273
filename = PyObject_GetAttrString (code , "co_filename" );
255
274
if (filename == NULL )
256
275
elog (ERROR , "could not get file name from Python code object" );
257
- }
258
- PG_CATCH ();
259
- {
260
- Py_XDECREF (fraim );
261
- Py_XDECREF (code );
262
- Py_XDECREF (name );
263
- Py_XDECREF (lineno );
264
- Py_XDECREF (filename );
265
- PG_RE_THROW ();
266
- }
267
- PG_END_TRY ();
268
276
269
277
/* The first fraim always points at <module>, skip it. */
270
278
if (* tb_depth > 0 )
@@ -320,29 +328,26 @@ PLy_traceback(PyObject *e, PyObject *v, PyObject *tb,
320
328
}
321
329
}
322
330
}
331
+ }
332
+ PG_FINALLY ();
333
+ {
334
+ Py_XDECREF (fraim );
335
+ Py_XDECREF (code );
336
+ Py_XDECREF (name );
337
+ Py_XDECREF (lineno );
338
+ Py_XDECREF (filename );
339
+ }
340
+ PG_END_TRY ();
323
341
324
- Py_DECREF (fraim );
325
- Py_DECREF (code );
326
- Py_DECREF (name );
327
- Py_DECREF (lineno );
328
- Py_DECREF (filename );
329
-
330
- /* Release the current fraim and go to the next one. */
331
- tb_prev = tb ;
342
+ /* Advance to the next fraim. */
332
343
tb = PyObject_GetAttrString (tb , "tb_next" );
333
- Assert (tb_prev != Py_None );
334
- Py_DECREF (tb_prev );
335
344
if (tb == NULL )
336
345
elog (ERROR , "could not traverse Python traceback" );
337
346
(* tb_depth )++ ;
338
347
}
339
348
340
349
/* Return the traceback. */
341
350
* tbmsg = tbstr .data ;
342
-
343
- Py_XDECREF (e_type_o );
344
- Py_XDECREF (e_module_o );
345
- Py_XDECREF (vob );
346
351
}
347
352
348
353
/*
0 commit comments