@@ -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 = PyString_AsString (e_type_o );
194
- if (e_type_s )
207
+ if (e_module_o )
195
208
e_module_s = PyString_AsString (e_module_o );
196
209
197
210
if (v && ((vob = PyObject_Str (v )) != NULL ))
@@ -219,18 +232,24 @@ PLy_traceback(PyObject *e, PyObject *v, PyObject *tb,
219
232
appendStringInfo (& xstr , ": %s" , vstr );
220
233
221
234
* xmsg = xstr .data ;
235
+ }
236
+ PG_FINALLY ();
237
+ {
238
+ Py_XDECREF (e_type_o );
239
+ Py_XDECREF (e_module_o );
240
+ Py_XDECREF (vob );
241
+ }
242
+ PG_END_TRY ();
222
243
223
244
/*
224
245
* Now format the traceback and put it in tbmsg.
225
246
*/
226
-
227
247
* tb_depth = 0 ;
228
248
initStringInfo (& tbstr );
229
249
/* Mimic Python traceback reporting as close as possible. */
230
250
appendStringInfoString (& tbstr , "Traceback (most recent call last):" );
231
251
while (tb != NULL && tb != Py_None )
232
252
{
233
- PyObject * volatile tb_prev = NULL ;
234
253
PyObject * volatile frame = NULL ;
235
254
PyObject * volatile code = NULL ;
236
255
PyObject * volatile name = NULL ;
@@ -258,17 +277,6 @@ PLy_traceback(PyObject *e, PyObject *v, PyObject *tb,
258
277
filename = PyObject_GetAttrString (code , "co_filename" );
259
278
if (filename == NULL )
260
279
elog (ERROR , "could not get file name from Python code object" );
261
- }
262
- PG_CATCH ();
263
- {
264
- Py_XDECREF (frame );
265
- Py_XDECREF (code );
266
- Py_XDECREF (name );
267
- Py_XDECREF (lineno );
268
- Py_XDECREF (filename );
269
- PG_RE_THROW ();
270
- }
271
- PG_END_TRY ();
272
280
273
281
/* The first frame always points at <module>, skip it. */
274
282
if (* tb_depth > 0 )
@@ -324,29 +332,26 @@ PLy_traceback(PyObject *e, PyObject *v, PyObject *tb,
324
332
}
325
333
}
326
334
}
335
+ }
336
+ PG_FINALLY ();
337
+ {
338
+ Py_XDECREF (frame );
339
+ Py_XDECREF (code );
340
+ Py_XDECREF (name );
341
+ Py_XDECREF (lineno );
342
+ Py_XDECREF (filename );
343
+ }
344
+ PG_END_TRY ();
327
345
328
- Py_DECREF (frame );
329
- Py_DECREF (code );
330
- Py_DECREF (name );
331
- Py_DECREF (lineno );
332
- Py_DECREF (filename );
333
-
334
- /* Release the current frame and go to the next one. */
335
- tb_prev = tb ;
346
+ /* Advance to the next frame. */
336
347
tb = PyObject_GetAttrString (tb , "tb_next" );
337
- Assert (tb_prev != Py_None );
338
- Py_DECREF (tb_prev );
339
348
if (tb == NULL )
340
349
elog (ERROR , "could not traverse Python traceback" );
341
350
(* tb_depth )++ ;
342
351
}
343
352
344
353
/* Return the traceback. */
345
354
* tbmsg = tbstr .data ;
346
-
347
- Py_XDECREF (e_type_o );
348
- Py_XDECREF (e_module_o );
349
- Py_XDECREF (vob );
350
355
}
351
356
352
357
/*
0 commit comments