Bug Summary

File:baul-python.c
Warning:line 173, column 6
Potential leak of memory pointed to by 'modulename'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name baul-python.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/src -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I .. -I .. -I .. -D G_LOG_DOMAIN="Baul-Python" -D DATADIR="/usr/share" -D LIBDIR="/usr/lib" -D PYTHON_VERSION="3.12" -D PYTHON_ABIFLAGS="" -D PY_LIB_LOC="/usr/lib/x86_64-linux-gnu" -I /usr/include/pygobject-3.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/baul -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/python3.12 -D PIC -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-12-24-114702-46556-1 -x c baul-python.c
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2/*
3 * Copyright (C) 2004,2005 Johan Dahlin
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20#ifdef HAVE_CONFIG_H1
21# include <config.h>
22#endif
23
24#include <Python.h>
25#include <structmember.h>
26#include <pygobject.h>
27#include <gmodule.h>
28#include <ctk/ctk.h>
29
30#include "baul-python.h"
31#include "baul-python-object.h"
32
33#include <libbaul-extension/baul-extension-types.h>
34
35static const GDebugKey baul_python_debug_keys[] = {
36 {"misc", BAUL_PYTHON_DEBUG_MISC},
37};
38static const guint baul_python_ndebug_keys = sizeof (baul_python_debug_keys) / sizeof (GDebugKey);
39BaulPythonDebug baul_python_debug;
40
41static gboolean baul_python_init_python(void);
42
43static GArray *all_types = NULL((void*)0);
44static GList *all_pyfiles = NULL((void*)0);
45
46
47/* Baul.OperationHandle value access. */
48static PyObject *
49baul_operationhandle_get_handle(PyGBoxed *self, void *closure)
50{
51 return PyLong_FromSsize_t((Py_ssize_t) (size_t) self->boxed);
52}
53
54static int
55baul_operationhandle_set_handle(PyGBoxed *self, PyObject *value, void *closure)
56{
57 Py_ssize_t val = PyLong_AsSsize_t(value);
58
59 if (!PyErr_Occurred()) {
60 if (val) {
61 self->boxed = (void *) val;
62 return 0;
63 }
64 PyErr_SetString(PyExc_ValueError, "invalid operation handle value");
65 }
66 return -1;
67}
68
69static PyGetSetDef baul_operationhandle_handle = {
70 "handle",
71 (getter) baul_operationhandle_get_handle,
72 (setter) baul_operationhandle_set_handle,
73 "Operation handle value",
74 NULL((void*)0)
75};
76
77
78static inline gboolean
79np_init_pygobject(void)
80{
81 PyObject *gobject = pygobject_init (PYGOBJECT_MAJOR_VERSION3, PYGOBJECT_MINOR_VERSION0, PYGOBJECT_MICRO_VERSION0);
82
83 if (gobject == NULL((void*)0)) {
84 PyErr_Print ();
85 return FALSE(0);
86 }
87
88 return TRUE(!(0));
89}
90
91static void
92baul_python_load_file(GTypeModule *type_module,
93 const gchar *filename)
94{
95 PyObject *main_module, *main_locals, *locals, *key, *value;
96 PyObject *module;
97 GType gtype;
98 Py_ssize_t pos = 0;
99
100 debug_enter_args("filename=%s", filename){ if (baul_python_debug & BAUL_PYTHON_DEBUG_MISC) g_printf
("%s: entered " "filename=%s" "\n", __FUNCTION__, filename); }
;
101
102 main_module = PyImport_AddModule("__main__");
103 if (main_module == NULL((void*)0))
104 {
105 g_warning("Could not get __main__.");
106 return;
107 }
108
109 main_locals = PyModule_GetDict(main_module);
110 module = PyImport_ImportModuleEx((char *) filename, main_locals, main_locals, NULL)PyImport_ImportModuleLevel(((char *) filename), (main_locals)
, (main_locals), (((void*)0)), 0)
;
111 if (!module)
112 {
113 PyErr_Print();
114 return;
115 }
116
117 locals = PyModule_GetDict(module);
118
119 while (PyDict_Next(locals, &pos, &key, &value))
120 {
121 if (!PyType_Check(value)PyType_Check(((PyObject*)((value)))))
122 continue;
123
124 if (PyObject_IsSubclass(value, (PyObject*)&PyBaulColumnProvider_Type(*_PyBaulColumnProvider_Type)) ||
125 PyObject_IsSubclass(value, (PyObject*)&PyBaulInfoProvider_Type(*_PyBaulInfoProvider_Type)) ||
126 PyObject_IsSubclass(value, (PyObject*)&PyBaulLocationWidgetProvider_Type(*_PyBaulLocationWidgetProvider_Type)) ||
127 PyObject_IsSubclass(value, (PyObject*)&PyBaulMenuProvider_Type(*_PyBaulMenuProvider_Type)) ||
128 PyObject_IsSubclass(value, (PyObject*)&PyBaulPropertyPageProvider_Type(*_PyBaulPropertyPageProvider_Type)))
129 {
130 gtype = baul_python_object_get_type(type_module, value);
131 g_array_append_val(all_types, gtype)g_array_append_vals (all_types, &(gtype), 1);
132
133 all_pyfiles = g_list_append(all_pyfiles, (gchar*)filename);
134 }
135 }
136
137 debug("Loaded python modules"){ if (baul_python_debug & BAUL_PYTHON_DEBUG_MISC) g_printf
( "baul-python:" "Loaded python modules" "\n"); }
;
138}
139
140static void
141baul_python_load_dir (GTypeModule *module,
142 const char *dirname)
143{
144 GDir *dir;
145 const char *name;
146 gboolean initialized = FALSE(0);
147
148 debug_enter_args("dirname=%s", dirname){ if (baul_python_debug & BAUL_PYTHON_DEBUG_MISC) g_printf
("%s: entered " "dirname=%s" "\n", __FUNCTION__, dirname); }
;
6
Assuming the condition is false
7
Taking false branch
149
150 dir = g_dir_open(dirname, 0, NULL((void*)0));
151 if (!dir)
8
Assuming 'dir' is non-null
9
Taking false branch
152 return;
153
154 while ((name = g_dir_read_name(dir)))
10
Loop condition is true. Entering loop body
155 {
156 if (g_str_has_suffix(name, ".py")(__builtin_constant_p (".py")? __extension__ ({ const char * const
__str = (name); const char * const __suffix = (".py"); gboolean
__result = (0); if (__str == ((void*)0) || __suffix == ((void
*)0)) __result = (g_str_has_suffix) (__str, __suffix); else {
const size_t __str_len = strlen (((__str) + !(__str))); const
size_t __suffix_len = strlen (((__suffix) + !(__suffix))); if
(__str_len >= __suffix_len) __result = memcmp (__str + __str_len
- __suffix_len, ((__suffix) + !(__suffix)), __suffix_len) ==
0; } __result; }) : (g_str_has_suffix) (name, ".py") )
)
11
'?' condition is true
12
Taking false branch
13
Assuming '__str_len' is >= '__suffix_len'
14
Taking true branch
15
Assuming the condition is true
16
Taking true branch
157 {
158 char *modulename;
159 int len;
160
161 len = strlen(name) - 3;
162 modulename = g_new0(char, len + 1 )((char *) g_malloc0_n ((len + 1), sizeof (char)));
17
Memory is allocated
163 strncpy(modulename, name, len);
164
165 if (!initialized
17.1
'initialized' is 0
)
18
Taking true branch
166 {
167 PyObject *sys_path, *py_path;
168
169 /* n-p python part is initialized on demand (or not
170 * at all if no extensions are found) */
171 if (!baul_python_init_python())
19
Taking true branch
172 {
173 g_warning("baul_python_init_python failed");
20
Potential leak of memory pointed to by 'modulename'
174 g_dir_close(dir);
175 break;
176 }
177
178 /* sys.path.insert(0, dirname) */
179 sys_path = PySys_GetObject("path");
180 py_path = PyUnicode_FromString(dirname);
181 PyList_Insert(sys_path, 0, py_path);
182 Py_DECREF(py_path)Py_DECREF(((PyObject*)((py_path))));
183 }
184 baul_python_load_file(module, modulename);
185 }
186 }
187}
188
189static gboolean
190baul_python_init_python (void)
191{
192 PyObject *gi, *require_version, *args, *baul, *descr;
193 GModule *libpython;
194
195 if (Py_IsInitialized())
196 return TRUE(!(0));
197
198 debug("g_module_open " PY_LIB_LOC "/libpython" PYTHON_VERSION PYTHON_ABIFLAGS "." G_MODULE_SUFFIX ".1.0"){ if (baul_python_debug & BAUL_PYTHON_DEBUG_MISC) g_printf
( "baul-python:" "g_module_open " "/usr/lib/x86_64-linux-gnu"
"/libpython" "3.12" "" "." "so" ".1.0" "\n"); }
;
199 libpython = g_module_open(PY_LIB_LOC"/usr/lib/x86_64-linux-gnu" "/libpython" PYTHON_VERSION"3.12" PYTHON_ABIFLAGS"" "." G_MODULE_SUFFIX"so" ".1.0", 0);
200 if (!libpython)
201 g_warning("g_module_open libpython failed: %s", g_module_error());
202
203 debug("Py_Initialize"){ if (baul_python_debug & BAUL_PYTHON_DEBUG_MISC) g_printf
( "baul-python:" "Py_Initialize" "\n"); }
;
204 Py_Initialize();
205 if (PyErr_Occurred())
206 {
207 PyErr_Print();
208 return FALSE(0);
209 }
210
211 debug("Sanitize the python search path and set sys.argv"){ if (baul_python_debug & BAUL_PYTHON_DEBUG_MISC) g_printf
( "baul-python:" "Sanitize the python search path and set sys.argv"
"\n"); }
;
212 PyRun_SimpleString("import sys; "PyRun_SimpleStringFlags(("import sys; " "sys.path = list(filter(None, sys.path)); "
"sys.argv = ['baul']"), ((void*)0))
213 "sys.path = list(filter(None, sys.path)); "PyRun_SimpleStringFlags(("import sys; " "sys.path = list(filter(None, sys.path)); "
"sys.argv = ['baul']"), ((void*)0))
214 "sys.argv = ['baul']")PyRun_SimpleStringFlags(("import sys; " "sys.path = list(filter(None, sys.path)); "
"sys.argv = ['baul']"), ((void*)0))
;
215 if (PyErr_Occurred())
216 {
217 PyErr_Print();
218 return FALSE(0);
219 }
220
221 /* import gobject */
222 debug("init_pygobject"){ if (baul_python_debug & BAUL_PYTHON_DEBUG_MISC) g_printf
( "baul-python:" "init_pygobject" "\n"); }
;
223 if (!np_init_pygobject())
224 {
225 g_warning("pygobject initialization failed");
226 return FALSE(0);
227 }
228
229 /* import baul */
230 g_setenv("INSIDE_BAUL_PYTHON", "", FALSE(0));
231 debug("import baul"){ if (baul_python_debug & BAUL_PYTHON_DEBUG_MISC) g_printf
( "baul-python:" "import baul" "\n"); }
;
232 gi = PyImport_ImportModule ("gi");
233 if (!gi) {
234 PyErr_Print();
235 return FALSE(0);
236 }
237
238 require_version = PyObject_GetAttrString (gi, (char *) "require_version");
239 args = PyTuple_Pack (2, PyUnicode_FromString ("Baul"),
240 PyUnicode_FromString ("2.0"));
241 PyObject_CallObject (require_version, args);
242 Py_DECREF (require_version)Py_DECREF(((PyObject*)((require_version))));
243 Py_DECREF (args)Py_DECREF(((PyObject*)((args))));
244 Py_DECREF (gi)Py_DECREF(((PyObject*)((gi))));
245 baul = PyImport_ImportModule("gi.repository.Baul");
246 if (!baul)
247 {
248 PyErr_Print();
249 return FALSE(0);
250 }
251
252 _PyCtkWidget_Type = pygobject_lookup_class(_PyGObject_API->lookup_class)(CTK_TYPE_WIDGET(ctk_widget_get_type ()));
253 g_assert(_PyCtkWidget_Type != NULL)do { if (_PyCtkWidget_Type != ((void*)0)) ; else g_assertion_message_expr
("Baul-Python", "baul-python.c", 253, ((const char*) (__func__
)), "_PyCtkWidget_Type != NULL"); } while (0)
;
254
255#define IMPORT(x, y) \
256 _PyBaul##x##_Type = (PyTypeObject *)PyObject_GetAttrString(baul, y); \
257 if (_PyBaul##x##_Type == NULL((void*)0)) { \
258 PyErr_Print(); \
259 return FALSE(0); \
260 }
261
262 IMPORT(Column, "Column");
263 IMPORT(ColumnProvider, "ColumnProvider");
264 IMPORT(InfoProvider, "InfoProvider");
265 IMPORT(LocationWidgetProvider, "LocationWidgetProvider");
266 IMPORT(Menu, "Menu");
267 IMPORT(MenuItem, "MenuItem");
268 IMPORT(MenuProvider, "MenuProvider");
269 IMPORT(PropertyPage, "PropertyPage");
270 IMPORT(PropertyPageProvider, "PropertyPageProvider");
271 IMPORT(OperationHandle, "OperationHandle");
272
273#undef IMPORT
274
275 /* Add the "handle" member to the OperationHandle type. */
276 descr = PyDescr_NewGetSet(_PyBaulOperationHandle_Type,
277 &baul_operationhandle_handle);
278 if (!descr) {
279 PyErr_Print();
280 return FALSE(0);
281 }
282 if (PyDict_SetItemString(_PyBaulOperationHandle_Type->tp_dict,
283 baul_operationhandle_handle.name, descr)) {
284 Py_DECREF(descr)Py_DECREF(((PyObject*)((descr))));
285 PyErr_Print();
286 return FALSE(0);
287 }
288 Py_DECREF(descr)Py_DECREF(((PyObject*)((descr))));
289
290 return TRUE(!(0));
291}
292
293void
294baul_module_initialize(GTypeModule *module)
295{
296 gchar *user_extensions_dir;
297 const gchar *env_string;
298
299 env_string = g_getenv("BAUL_PYTHON_DEBUG");
300 if (env_string != NULL((void*)0))
1
Assuming 'env_string' is equal to NULL
2
Taking false branch
301 {
302 baul_python_debug = g_parse_debug_string(env_string,
303 baul_python_debug_keys,
304 baul_python_ndebug_keys);
305 env_string = NULL((void*)0);
306 }
307
308 debug_enter(){ if (baul_python_debug & BAUL_PYTHON_DEBUG_MISC) g_printf
("%s: entered\n", __FUNCTION__); }
;
3
Assuming the condition is false
4
Taking false branch
309
310 all_types = g_array_new(FALSE(0), FALSE(0), sizeof(GType));
311
312 // Look in the new global path, $DATADIR/baul-python/extensions
313 baul_python_load_dir(module, DATADIR"/usr/share" "/baul-python/extensions");
5
Calling 'baul_python_load_dir'
314
315 // Look in XDG_DATA_DIR, ~/.local/share/baul-python/extensions
316 user_extensions_dir = g_build_filename(g_get_user_data_dir(),
317 "baul-python", "extensions", NULL((void*)0));
318 baul_python_load_dir(module, user_extensions_dir);
319}
320
321void
322baul_module_shutdown(void)
323{
324 debug_enter(){ if (baul_python_debug & BAUL_PYTHON_DEBUG_MISC) g_printf
("%s: entered\n", __FUNCTION__); }
;
325
326 if (Py_IsInitialized())
327 Py_Finalize();
328
329 g_array_free(all_types, TRUE(!(0)));
330 g_list_free (all_pyfiles);
331}
332
333void
334baul_module_list_types(const GType **types,
335 int *num_types)
336{
337 debug_enter(){ if (baul_python_debug & BAUL_PYTHON_DEBUG_MISC) g_printf
("%s: entered\n", __FUNCTION__); }
;
338
339 *types = (GType*)all_types->data;
340 *num_types = all_types->len;
341}
342
343void
344baul_module_list_pyfiles(GList **pyfiles)
345{
346 debug_enter(){ if (baul_python_debug & BAUL_PYTHON_DEBUG_MISC) g_printf
("%s: entered\n", __FUNCTION__); }
;
347
348 *pyfiles = all_pyfiles;
349}