Skip to content

Commit 1634d26

Browse files
committed
Improve Python error handling and memory management
Enhanced getPythonError to handle null pointers, memory allocation failures, and fallback error formatting. Replaced Py_DecRef with malloc.free for native strings and ensured proper reference counting and cleanup to prevent memory leaks.
1 parent c6433f8 commit 1634d26

File tree

1 file changed

+77
-5
lines changed

1 file changed

+77
-5
lines changed

src/serious_python_android/lib/src/cpython.dart

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,45 +164,117 @@ String _runPythonProgram(
164164

165165
String getPythonError(CPython cpython) {
166166
// get error object
167-
var exPtr = cpython.PyErr_GetRaisedException();
167+
final exPtr = cpython.PyErr_GetRaisedException();
168+
if (exPtr == nullptr) {
169+
return "Unknown Python error (no exception set).";
170+
}
168171

169172
// use 'traceback' module to format exception
170173
final tracebackModuleNamePtr = "traceback".toNativeUtf8();
171174
var tracebackModulePtr =
172175
cpython.PyImport_ImportModule(tracebackModuleNamePtr.cast<Char>());
173-
cpython.Py_DecRef(tracebackModuleNamePtr.cast());
176+
malloc.free(tracebackModuleNamePtr);
174177

175178
if (tracebackModulePtr != nullptr) {
176179
//spDebug("Traceback module loaded");
177180

178181
final formatFuncName = "format_exception".toNativeUtf8();
179182
final pFormatFunc = cpython.PyObject_GetAttrString(
180183
tracebackModulePtr, formatFuncName.cast());
181-
cpython.Py_DecRef(tracebackModuleNamePtr.cast());
184+
malloc.free(formatFuncName);
182185

183186
if (pFormatFunc != nullptr && cpython.PyCallable_Check(pFormatFunc) != 0) {
184187
// call `traceback.format_exception()` method
185188
final pArgs = cpython.PyTuple_New(1);
189+
if (pArgs == nullptr) {
190+
final fallback = cpython.PyObject_Str(exPtr);
191+
if (fallback == nullptr) {
192+
cpython.Py_DecRef(pFormatFunc);
193+
cpython.Py_DecRef(tracebackModulePtr);
194+
cpython.Py_DecRef(exPtr);
195+
return "Failed to allocate args to format Python exception.";
196+
}
197+
final s = cpython
198+
.PyUnicode_AsUTF8(fallback)
199+
.cast<Utf8>()
200+
.toDartString();
201+
cpython.Py_DecRef(fallback);
202+
cpython.Py_DecRef(pFormatFunc);
203+
cpython.Py_DecRef(tracebackModulePtr);
204+
cpython.Py_DecRef(exPtr);
205+
return s;
206+
}
207+
// Keep a reference for fallback error formatting.
208+
cpython.Py_IncRef(exPtr);
186209
cpython.PyTuple_SetItem(pArgs, 0, exPtr);
187210

188211
// result is a list
189212
var listPtr = cpython.PyObject_CallObject(pFormatFunc, pArgs);
213+
cpython.Py_DecRef(pArgs);
214+
cpython.Py_DecRef(pFormatFunc);
215+
cpython.Py_DecRef(tracebackModulePtr);
190216

191217
// get and combine list items
192218
var exLines = [];
219+
if (listPtr == nullptr) {
220+
final fallback = cpython.PyObject_Str(exPtr);
221+
if (fallback == nullptr) {
222+
cpython.Py_DecRef(exPtr);
223+
return "Failed to format Python exception.";
224+
}
225+
final s = cpython
226+
.PyUnicode_AsUTF8(fallback)
227+
.cast<Utf8>()
228+
.toDartString();
229+
cpython.Py_DecRef(fallback);
230+
cpython.Py_DecRef(exPtr);
231+
return s;
232+
}
233+
193234
var listSize = cpython.PyList_Size(listPtr);
235+
if (listSize < 0) {
236+
cpython.Py_DecRef(listPtr);
237+
final fallback = cpython.PyObject_Str(exPtr);
238+
if (fallback == nullptr) {
239+
cpython.Py_DecRef(exPtr);
240+
return "Failed to format Python exception.";
241+
}
242+
final s = cpython
243+
.PyUnicode_AsUTF8(fallback)
244+
.cast<Utf8>()
245+
.toDartString();
246+
cpython.Py_DecRef(fallback);
247+
cpython.Py_DecRef(exPtr);
248+
return s;
249+
}
194250
for (var i = 0; i < listSize; i++) {
195251
var itemObj = cpython.PyList_GetItem(listPtr, i);
196252
var itemObjStr = cpython.PyObject_Str(itemObj);
197-
var s =
198-
cpython.PyUnicode_AsUTF8(itemObjStr).cast<Utf8>().toDartString();
253+
if (itemObjStr == nullptr) {
254+
continue;
255+
}
256+
final cStr = cpython.PyUnicode_AsUTF8(itemObjStr);
257+
if (cStr == nullptr) {
258+
cpython.Py_DecRef(itemObjStr);
259+
continue;
260+
}
261+
var s = cStr.cast<Utf8>().toDartString();
262+
cpython.Py_DecRef(itemObjStr);
199263
exLines.add(s);
200264
}
265+
cpython.Py_DecRef(listPtr);
266+
cpython.Py_DecRef(exPtr);
201267
return exLines.join("");
202268
} else {
269+
if (pFormatFunc != nullptr) {
270+
cpython.Py_DecRef(pFormatFunc);
271+
}
272+
cpython.Py_DecRef(tracebackModulePtr);
273+
cpython.Py_DecRef(exPtr);
203274
return "traceback.format_exception() method not found.";
204275
}
205276
} else {
277+
cpython.Py_DecRef(exPtr);
206278
return "Error loading traceback module.";
207279
}
208280
}

0 commit comments

Comments
 (0)