Fix crash in GList/GSList marshaling error handling path.
[pygobject.git] / gi / pygi-list.c
blobe3f3c6742bbb2e8d5075049035622d1221ddb2de
1 /* -*- Mode: C; c-basic-offset: 4 -*-
2 * vim: tabstop=4 shiftwidth=4 expandtab
4 * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>
5 * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "pygi-list.h"
22 #include "pygi-argument.h"
23 #include "pygi-private.h"
25 typedef PyGISequenceCache PyGIArgGList;
28 * GList and GSList from Python
30 static gboolean
31 _pygi_marshal_from_py_glist (PyGIInvokeState *state,
32 PyGICallableCache *callable_cache,
33 PyGIArgCache *arg_cache,
34 PyObject *py_arg,
35 GIArgument *arg,
36 gpointer *cleanup_data)
38 PyGIMarshalFromPyFunc from_py_marshaller;
39 int i;
40 Py_ssize_t length;
41 GList *list_ = NULL;
42 PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
45 if (py_arg == Py_None) {
46 arg->v_pointer = NULL;
47 return TRUE;
50 if (!PySequence_Check (py_arg)) {
51 PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
52 py_arg->ob_type->tp_name);
53 return FALSE;
56 length = PySequence_Length (py_arg);
57 if (length < 0)
58 return FALSE;
60 from_py_marshaller = sequence_cache->item_cache->from_py_marshaller;
61 for (i = 0; i < length; i++) {
62 GIArgument item = {0};
63 gpointer item_cleanup_data = NULL;
64 PyObject *py_item = PySequence_GetItem (py_arg, i);
65 if (py_item == NULL)
66 goto err;
68 if (!from_py_marshaller ( state,
69 callable_cache,
70 sequence_cache->item_cache,
71 py_item,
72 &item,
73 &item_cleanup_data))
74 goto err;
76 Py_DECREF (py_item);
77 list_ = g_list_prepend (list_, _pygi_arg_to_hash_pointer (&item, sequence_cache->item_cache->type_tag));
78 continue;
79 err:
80 /* FIXME: clean up list
81 if (sequence_cache->item_cache->from_py_cleanup != NULL) {
82 PyGIMarshalCleanupFunc cleanup = sequence_cache->item_cache->from_py_cleanup;
85 Py_XDECREF (py_item);
86 g_list_free (list_);
87 _PyGI_ERROR_PREFIX ("Item %i: ", i);
88 return FALSE;
91 arg->v_pointer = g_list_reverse (list_);
93 if (arg_cache->transfer == GI_TRANSFER_NOTHING) {
94 /* Free everything in cleanup. */
95 *cleanup_data = arg->v_pointer;
96 } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) {
97 /* Make a shallow copy so we can free the elements later in cleanup
98 * because it is possible invoke will free the list before our cleanup. */
99 *cleanup_data = g_list_copy (arg->v_pointer);
100 } else { /* GI_TRANSFER_EVERYTHING */
101 /* No cleanup, everything is given to the callee. */
102 *cleanup_data = NULL;
104 return TRUE;
108 static gboolean
109 _pygi_marshal_from_py_gslist (PyGIInvokeState *state,
110 PyGICallableCache *callable_cache,
111 PyGIArgCache *arg_cache,
112 PyObject *py_arg,
113 GIArgument *arg,
114 gpointer *cleanup_data)
116 PyGIMarshalFromPyFunc from_py_marshaller;
117 int i;
118 Py_ssize_t length;
119 GSList *list_ = NULL;
120 PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
122 if (py_arg == Py_None) {
123 arg->v_pointer = NULL;
124 return TRUE;
127 if (!PySequence_Check (py_arg)) {
128 PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
129 py_arg->ob_type->tp_name);
130 return FALSE;
133 length = PySequence_Length (py_arg);
134 if (length < 0)
135 return FALSE;
137 from_py_marshaller = sequence_cache->item_cache->from_py_marshaller;
138 for (i = 0; i < length; i++) {
139 GIArgument item = {0};
140 gpointer item_cleanup_data = NULL;
141 PyObject *py_item = PySequence_GetItem (py_arg, i);
142 if (py_item == NULL)
143 goto err;
145 if (!from_py_marshaller ( state,
146 callable_cache,
147 sequence_cache->item_cache,
148 py_item,
149 &item,
150 &item_cleanup_data))
151 goto err;
153 Py_DECREF (py_item);
154 list_ = g_slist_prepend (list_, _pygi_arg_to_hash_pointer (&item, sequence_cache->item_cache->type_tag));
155 continue;
156 err:
157 /* FIXME: Clean up list
158 if (sequence_cache->item_cache->from_py_cleanup != NULL) {
159 PyGIMarshalCleanupFunc cleanup = sequence_cache->item_cache->from_py_cleanup;
163 Py_XDECREF (py_item);
164 g_slist_free (list_);
165 _PyGI_ERROR_PREFIX ("Item %i: ", i);
166 return FALSE;
169 arg->v_pointer = g_slist_reverse (list_);
171 if (arg_cache->transfer == GI_TRANSFER_NOTHING) {
172 /* Free everything in cleanup. */
173 *cleanup_data = arg->v_pointer;
174 } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) {
175 /* Make a shallow copy so we can free the elements later in cleanup
176 * because it is possible invoke will free the list before our cleanup. */
177 *cleanup_data = g_slist_copy (arg->v_pointer);
178 } else { /* GI_TRANSFER_EVERYTHING */
179 /* No cleanup, everything is given to the callee. */
180 *cleanup_data = NULL;
183 return TRUE;
186 static void
187 _pygi_marshal_cleanup_from_py_glist (PyGIInvokeState *state,
188 PyGIArgCache *arg_cache,
189 PyObject *py_arg,
190 gpointer data,
191 gboolean was_processed)
193 if (was_processed) {
194 GSList *list_;
195 PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
197 list_ = (GSList *)data;
199 /* clean up items first */
200 if (sequence_cache->item_cache->from_py_cleanup != NULL) {
201 PyGIMarshalCleanupFunc cleanup_func =
202 sequence_cache->item_cache->from_py_cleanup;
203 GSList *node = list_;
204 gsize i = 0;
205 while (node != NULL) {
206 PyObject *py_item = PySequence_GetItem (py_arg, i);
207 cleanup_func (state,
208 sequence_cache->item_cache,
209 py_item,
210 node->data,
211 TRUE);
212 Py_XDECREF (py_item);
213 node = node->next;
214 i++;
218 if (arg_cache->type_tag == GI_TYPE_TAG_GLIST) {
219 g_list_free ( (GList *)list_);
220 } else if (arg_cache->type_tag == GI_TYPE_TAG_GSLIST) {
221 g_slist_free (list_);
222 } else {
223 g_assert_not_reached();
230 * GList and GSList to Python
232 static PyObject *
233 _pygi_marshal_to_py_glist (PyGIInvokeState *state,
234 PyGICallableCache *callable_cache,
235 PyGIArgCache *arg_cache,
236 GIArgument *arg)
238 GList *list_;
239 gsize length;
240 gsize i;
242 PyGIMarshalToPyFunc item_to_py_marshaller;
243 PyGIArgCache *item_arg_cache;
244 PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
246 PyObject *py_obj = NULL;
248 list_ = arg->v_pointer;
249 length = g_list_length (list_);
251 py_obj = PyList_New (length);
252 if (py_obj == NULL)
253 return NULL;
255 item_arg_cache = seq_cache->item_cache;
256 item_to_py_marshaller = item_arg_cache->to_py_marshaller;
258 for (i = 0; list_ != NULL; list_ = g_list_next (list_), i++) {
259 GIArgument item_arg;
260 PyObject *py_item;
262 item_arg.v_pointer = list_->data;
263 _pygi_hash_pointer_to_arg (&item_arg, item_arg_cache->type_tag);
264 py_item = item_to_py_marshaller (state,
265 callable_cache,
266 item_arg_cache,
267 &item_arg);
269 if (py_item == NULL) {
270 Py_CLEAR (py_obj);
271 _PyGI_ERROR_PREFIX ("Item %zu: ", i);
272 return NULL;
275 PyList_SET_ITEM (py_obj, i, py_item);
278 return py_obj;
281 static PyObject *
282 _pygi_marshal_to_py_gslist (PyGIInvokeState *state,
283 PyGICallableCache *callable_cache,
284 PyGIArgCache *arg_cache,
285 GIArgument *arg)
287 GSList *list_;
288 gsize length;
289 gsize i;
291 PyGIMarshalToPyFunc item_to_py_marshaller;
292 PyGIArgCache *item_arg_cache;
293 PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
295 PyObject *py_obj = NULL;
297 list_ = arg->v_pointer;
298 length = g_slist_length (list_);
300 py_obj = PyList_New (length);
301 if (py_obj == NULL)
302 return NULL;
304 item_arg_cache = seq_cache->item_cache;
305 item_to_py_marshaller = item_arg_cache->to_py_marshaller;
307 for (i = 0; list_ != NULL; list_ = g_slist_next (list_), i++) {
308 GIArgument item_arg;
309 PyObject *py_item;
311 item_arg.v_pointer = list_->data;
312 _pygi_hash_pointer_to_arg (&item_arg, item_arg_cache->type_tag);
313 py_item = item_to_py_marshaller (state,
314 callable_cache,
315 item_arg_cache,
316 &item_arg);
318 if (py_item == NULL) {
319 Py_CLEAR (py_obj);
320 _PyGI_ERROR_PREFIX ("Item %zu: ", i);
321 return NULL;
324 PyList_SET_ITEM (py_obj, i, py_item);
327 return py_obj;
330 static void
331 _pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state,
332 PyGIArgCache *arg_cache,
333 PyObject *dummy,
334 gpointer data,
335 gboolean was_processed)
337 PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
338 if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
339 arg_cache->transfer == GI_TRANSFER_CONTAINER) {
340 GSList *list_ = (GSList *)data;
342 if (sequence_cache->item_cache->to_py_cleanup != NULL) {
343 PyGIMarshalCleanupFunc cleanup_func =
344 sequence_cache->item_cache->to_py_cleanup;
345 GSList *node = list_;
347 while (node != NULL) {
348 cleanup_func (state,
349 sequence_cache->item_cache,
350 NULL,
351 node->data,
352 was_processed);
353 node = node->next;
357 if (arg_cache->type_tag == GI_TYPE_TAG_GLIST) {
358 g_list_free ( (GList *)list_);
359 } else if (arg_cache->type_tag == GI_TYPE_TAG_GSLIST) {
360 g_slist_free (list_);
361 } else {
362 g_assert_not_reached();
367 static void
368 _arg_cache_from_py_glist_setup (PyGIArgCache *arg_cache,
369 GITransfer transfer)
371 arg_cache->from_py_marshaller = _pygi_marshal_from_py_glist;
372 arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist;
375 static void
376 _arg_cache_to_py_glist_setup (PyGIArgCache *arg_cache,
377 GITransfer transfer)
379 arg_cache->to_py_marshaller = _pygi_marshal_to_py_glist;
380 arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist;
383 static void
384 _arg_cache_from_py_gslist_setup (PyGIArgCache *arg_cache,
385 GITransfer transfer)
387 arg_cache->from_py_marshaller = _pygi_marshal_from_py_gslist;
388 arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist;
391 static void
392 _arg_cache_to_py_gslist_setup (PyGIArgCache *arg_cache,
393 GITransfer transfer)
395 arg_cache->to_py_marshaller = _pygi_marshal_to_py_gslist;
396 arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist;
401 * GList/GSList Interface
404 static gboolean
405 pygi_arg_glist_setup_from_info (PyGIArgCache *arg_cache,
406 GITypeInfo *type_info,
407 GIArgInfo *arg_info,
408 GITransfer transfer,
409 PyGIDirection direction,
410 PyGICallableCache *callable_cache)
412 GITypeTag type_tag = g_type_info_get_tag (type_info);
414 if (!pygi_arg_sequence_setup ((PyGISequenceCache *)arg_cache,
415 type_info,
416 arg_info,
417 transfer,
418 direction,
419 callable_cache))
420 return FALSE;
422 switch (type_tag) {
423 case GI_TYPE_TAG_GLIST:
425 if (direction & PYGI_DIRECTION_FROM_PYTHON)
426 _arg_cache_from_py_glist_setup (arg_cache, transfer);
428 if (direction & PYGI_DIRECTION_TO_PYTHON)
429 _arg_cache_to_py_glist_setup (arg_cache, transfer);
430 break;
432 case GI_TYPE_TAG_GSLIST:
434 if (direction & PYGI_DIRECTION_FROM_PYTHON)
435 _arg_cache_from_py_gslist_setup (arg_cache, transfer);
437 if (direction & PYGI_DIRECTION_TO_PYTHON)
438 _arg_cache_to_py_gslist_setup (arg_cache, transfer);
440 break;
442 default:
443 g_assert_not_reached ();
446 return TRUE;
449 PyGIArgCache *
450 pygi_arg_glist_new_from_info (GITypeInfo *type_info,
451 GIArgInfo *arg_info,
452 GITransfer transfer,
453 PyGIDirection direction,
454 PyGICallableCache *callable_cache)
456 gboolean res = FALSE;
458 PyGIArgCache *arg_cache = (PyGIArgCache *) g_slice_new0 (PyGIArgGList);
459 if (arg_cache == NULL)
460 return NULL;
462 res = pygi_arg_glist_setup_from_info (arg_cache,
463 type_info,
464 arg_info,
465 transfer,
466 direction,
467 callable_cache);
468 if (res) {
469 return arg_cache;
470 } else {
471 pygi_arg_cache_free (arg_cache);
472 return NULL;