1 /*
2 * Copyright (C) 2009 Sippy Software, Inc., http://www.sippysoft.com
3 *
4 * This file is part of Kamailio, a free SIP server.
5 *
6 * Kamailio is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version
10 *
11 * Kamailio is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22 #include <Python.h>
23 #include <stdio.h>
24 #include <stdarg.h>
25
26 #include "../../core/dprint.h"
27 #include "../../core/mem/mem.h"
28
29 #include "app_python_mod.h"
30 #include "python_support.h"
31
32 static char *make_message(const char *fmt, va_list ap);
33
python_handle_exception(const char * fmt,...)34 void python_handle_exception(const char *fmt, ...)
35 {
36 PyObject *pResult;
37 const char *msg;
38 char *buf;
39 size_t buflen, msglen;
40 PyObject *exception, *v, *tb, *args;
41 PyObject *line;
42 int i;
43 char *srcbuf;
44 int exc_exit = 0;
45 va_list ap;
46
47 // We don't want to generate traceback when no errors occurred
48 if (!PyErr_Occurred())
49 return;
50
51 if (fmt == NULL)
52 srcbuf = NULL;
53 else {
54 va_start(ap, fmt);
55 srcbuf = make_message(fmt, ap);
56 va_end(ap);
57 }
58
59 PyErr_Fetch(&exception, &v, &tb);
60 PyErr_Clear();
61 if (exception == NULL) {
62 LM_ERR("Can't get traceback, PyErr_Fetch() has failed.\n");
63 if (srcbuf) pkg_free(srcbuf);
64 return;
65 }
66
67 PyErr_NormalizeException(&exception, &v, &tb);
68 if (exception == NULL) {
69 LM_ERR("Can't get traceback, PyErr_NormalizeException() has failed.\n");
70 if (srcbuf) pkg_free(srcbuf);
71 return;
72 }
73
74 exc_exit = PyErr_GivenExceptionMatches(exception, PyExc_SystemExit);
75 args = PyTuple_Pack(3, exception, v, tb ? tb : Py_None);
76 Py_XDECREF(exception);
77 Py_XDECREF(v);
78 Py_XDECREF(tb);
79 if (args == NULL) {
80 LM_ERR("Can't get traceback, PyTuple_Pack() has failed.\n");
81 if (srcbuf) pkg_free(srcbuf);
82 return;
83 }
84
85 pResult = PyObject_CallObject(format_exc_obj, args);
86 Py_DECREF(args);
87 if (pResult == NULL) {
88 LM_ERR("Can't get traceback, traceback.format_exception() has failed.\n");
89 if (srcbuf) pkg_free(srcbuf);
90 return;
91 }
92
93 buflen = 1;
94 buf = (char *)pkg_realloc(NULL, buflen * sizeof(char));
95 if (!buf)
96 {
97 PKG_MEM_ERROR;
98 if (srcbuf) pkg_free(srcbuf);
99 return;
100 }
101 memset(buf, 0, buflen * sizeof(char));
102
103 for (i = 0; i < PySequence_Size(pResult); i++) {
104 line = PySequence_GetItem(pResult, i);
105 if (line == NULL) {
106 LM_ERR("Can't get traceback, PySequence_GetItem() has failed.\n");
107 Py_DECREF(pResult);
108 if (buf)
109 pkg_free(buf);
110 if (srcbuf) pkg_free(srcbuf);
111 return;
112 }
113
114 msg = PyString_AsString(line);
115
116 if (msg == NULL) {
117 LM_ERR("Can't get traceback, PyString_AsString() has failed.\n");
118 Py_DECREF(line);
119 Py_DECREF(pResult);
120 if (buf)
121 pkg_free(buf);
122 if (srcbuf) pkg_free(srcbuf);
123 return;
124 }
125
126 msglen = strlen(msg);
127 buflen += ++msglen;
128
129 buf = (char *)pkg_reallocxf(buf, buflen * sizeof(char));
130 if (!buf)
131 {
132 PKG_MEM_ERROR;
133 Py_DECREF(line);
134 Py_DECREF(pResult);
135 if (srcbuf) pkg_free(srcbuf);
136 return;
137 }
138
139 strncat(buf, msg, msglen >= buflen ? buflen-1 : msglen);
140
141 Py_DECREF(line);
142 }
143
144 if (srcbuf == NULL) {
145 if(exc_exit) {
146 LM_DBG("Unhandled exception in the Python code:\n%s", buf);
147 } else {
148 LM_ERR("Unhandled exception in the Python code:\n%s", buf);
149 }
150 } else {
151 if(exc_exit) {
152 LM_DBG("%s: Unhandled exception in the Python code:\n%s", srcbuf, buf);
153 } else {
154 LM_ERR("%s: Unhandled exception in the Python code:\n%s", srcbuf, buf);
155 }
156 }
157
158 if (buf)
159 pkg_free(buf);
160
161 if (srcbuf)
162 pkg_free(srcbuf);
163
164 Py_DECREF(pResult);
165 }
166
167
InitTracebackModule()168 PyObject *InitTracebackModule()
169 {
170 PyObject *pModule, *pTracebackObject;
171
172 pModule = PyImport_ImportModule("traceback");
173 if (pModule == NULL) {
174 LM_ERR("Cannot import module 'traceback'.\n");
175 return NULL;
176 }
177
178 pTracebackObject = PyObject_GetAttrString(pModule, "format_exception");
179 Py_DECREF(pModule);
180 if (pTracebackObject == NULL || !PyCallable_Check(pTracebackObject)) {
181 LM_ERR("AttributeError: 'module' object 'traceback' has no attribute"
182 " 'format_exception'.\n");
183 Py_XDECREF(pTracebackObject);
184 return NULL;
185 }
186
187 return pTracebackObject;
188 }
189
190
make_message(const char * fmt,va_list ap)191 static char *make_message(const char *fmt, va_list ap)
192 {
193 int n;
194 size_t size;
195 char *p, *np;
196
197 size = 100; /* Guess we need no more than 100 bytes. */
198 p = (char *)pkg_realloc(NULL, size * sizeof(char));
199 if (!p)
200 {
201 PKG_MEM_ERROR;
202 return NULL;
203 }
204 memset(p, 0, size * sizeof(char));
205
206 while (1)
207 {
208 n = vsnprintf(p, size, fmt, ap);
209
210 if (n > -1 && n < size)
211 return p;
212
213 if (n > -1) /* glibc 2.1 */
214 size = n+1;
215 else /* glibc 2.0 */
216 size *= 2;
217
218 np = (char *)pkg_realloc(p, size * sizeof(char));
219 if (!np)
220 {
221 PKG_MEM_ERROR;
222 if (p)
223 pkg_free(p);
224 return NULL;
225 }
226 else
227 p = np;
228 }
229
230 return NULL; // shall not happened, but who knows ;)
231 }
232
get_class_name(PyObject * y)233 char *get_class_name(PyObject *y)
234 {
235 PyObject *p;
236 char *name;
237
238 p = PyObject_GetAttrString(y, "__name__");
239 if (p == NULL || p == Py_None)
240 {
241 Py_XDECREF(p);
242 return NULL;
243 }
244
245 name = PyString_AsString(p);
246 Py_XDECREF(p);
247
248 return name;
249 }
250
251
get_instance_class_name(PyObject * y)252 char *get_instance_class_name(PyObject *y)
253 {
254 PyObject *p, *n;
255 char *name;
256
257 n = PyObject_GetAttrString(y, "__class__");
258 if (n == NULL || n == Py_None)
259 {
260 Py_XDECREF(n);
261 return NULL;
262 }
263
264 p = PyObject_GetAttrString(n, "__name__");
265 if (p == NULL || p == Py_None)
266 {
267 Py_XDECREF(p);
268 return NULL;
269 }
270
271 name = PyString_AsString(p);
272 Py_XDECREF(p);
273 Py_XDECREF(n);
274
275 return name;
276 }
277