[perl-Glib] Make the stack handling of some marshallers more robust
- From: Torsten SchÃnfeld <tsch src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [perl-Glib] Make the stack handling of some marshallers more robust
- Date: Sat, 7 Jul 2012 20:06:48 +0000 (UTC)
commit bf736478fa21541b1a162b99d95cc3cee160ba3c
Author: Torsten SchÃnfeld <kaffeetisch gmx de>
Date: Sat Jun 23 17:11:54 2012 +0200
Make the stack handling of some marshallers more robust
Specifically, correctly synchronize the local stack pointer with the one in
thread-local storage. This is mainly in preparation for custom Glib::Boxed
converters that call back into Perl code, as Glib::Object::Introspection will
provide.
GBoxed.xs | 7 ++++++-
GClosure.xs | 6 +++---
GObject.xs | 4 ++--
GParamSpec.xs | 2 ++
GSignal.xs | 5 +++--
GType.xs | 10 +++++-----
GValue.xs | 12 ++++++++++--
NEWS | 3 +++
gperl-private.h | 19 +++++++++++++++++++
gperl_marshal.h | 2 ++
10 files changed, 55 insertions(+), 15 deletions(-)
---
diff --git a/GBoxed.xs b/GBoxed.xs
index 2a53c36..66d346a 100644
--- a/GBoxed.xs
+++ b/GBoxed.xs
@@ -442,6 +442,10 @@ the boxed structure should be destroyed when the wrapper is destroyed
(controlled by I<own>; if the wrapper owns the object, the wrapper is in
charge of destroying it's data).
+This function might end up calling other Perl code, so if you use it in XS code
+for a generic GType, make sure the stack pointer is set up correctly before the
+call, and restore it after the call.
+
=cut
SV *
gperl_new_boxed (gpointer boxed,
@@ -815,7 +819,8 @@ copy (SV * sv)
g_type_name (boxed_info->gtype), boxed_info->package);
boxed = class->unwrap (boxed_info->gtype, boxed_info->package, sv);
-
+
+ /* No PUTBACK/SPAGAIN needed here. */
RETVAL = class->wrap (boxed_info->gtype, boxed_info->package,
g_boxed_copy (boxed_info->gtype, boxed), TRUE);
OUTPUT:
diff --git a/GClosure.xs b/GClosure.xs
index 56d10ae..988ad1a 100644
--- a/GClosure.xs
+++ b/GClosure.xs
@@ -122,8 +122,8 @@ gperl_closure_marshal (GClosure * closure,
/* the rest of the params should be quite straightforward. */
for (i = 1; i < n_param_values; i++) {
- SV * arg;
- arg = gperl_sv_from_value ((GValue*) param_values + i);
+ SV * arg = SAVED_STACK_SV (
+ gperl_sv_from_value ((GValue*) param_values + i));
/* make these mortal as they go onto the stack */
XPUSHs (sv_2mortal (arg));
}
@@ -488,7 +488,7 @@ gperl_callback_invoke (GPerlCallback * callback,
/* this won't return */
croak ("%s", SvPV_nolen (errstr));
}
- sv = gperl_sv_from_value (&v);
+ sv = SAVED_STACK_SV (gperl_sv_from_value (&v));
g_value_unset (&v);
if (!sv) {
/* this should be very rare, too. */
diff --git a/GObject.xs b/GObject.xs
index adcdafe..53ee0cc 100644
--- a/GObject.xs
+++ b/GObject.xs
@@ -1403,8 +1403,8 @@ g_object_get (object, ...)
int i;
CODE:
/* Use CODE: instead of PPCODE: so we can handle the stack ourselves in
- * order to avoid that xsubs called by g_object_get_property overwrite
- * what we put on the stack. */
+ * order to avoid that xsubs called by g_object_get_property or
+ * _gperl_sv_from_value_internal overwrite what we put on the stack. */
PERL_UNUSED_VAR (ix);
for (i = 1; i < items; i++) {
char *name = SvPV_nolen (ST (i));
diff --git a/GParamSpec.xs b/GParamSpec.xs
index 5da046d..718f2bd 100644
--- a/GParamSpec.xs
+++ b/GParamSpec.xs
@@ -755,6 +755,7 @@ get_default_value (GParamSpec * pspec)
} else {
plain_gvalue:
+ /* No PUTBACK/SPAGAIN needed here. */
RETVAL = gperl_sv_from_value (&v);
}
g_value_unset (&v);
@@ -809,6 +810,7 @@ g_param_value_validate (GParamSpec * pspec, SV *value)
retcount = 2;
if (modify)
+ /* No PUTBACK/SPAGAIN needed here. */
ST(1) = sv_2mortal (_gperl_sv_from_value_internal(&v,TRUE));
}
g_value_unset (&v);
diff --git a/GSignal.xs b/GSignal.xs
index c3ed3aa..c89562d 100644
--- a/GSignal.xs
+++ b/GSignal.xs
@@ -28,6 +28,7 @@
/* #define NOISY */
#include "gperl.h"
+#include "gperl-private.h" /* for SAVED_STACK_SV */
/*
* here's a nice G_LOCK-like front-end to GStaticRecMutex. we need this
@@ -663,7 +664,7 @@ g_signal_emit (instance, name, ...)
g_value_init (&ret, query.return_type);
g_signal_emitv (params, signal_id, detail, &ret);
EXTEND (SP, 1);
- PUSHs (sv_2mortal (gperl_sv_from_value (&ret)));
+ SAVED_STACK_PUSHs (sv_2mortal (gperl_sv_from_value (&ret)));
g_value_unset (&ret);
} else {
g_signal_emitv (params, signal_id, detail, NULL);
@@ -1112,6 +1113,6 @@ g_signal_chain_from_overridden (GObject * instance, ...)
g_free (instance_and_params);
if (G_TYPE_NONE != (query.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE)) {
- XPUSHs (sv_2mortal (gperl_sv_from_value (&return_value)));
+ SAVED_STACK_XPUSHs (sv_2mortal (gperl_sv_from_value (&return_value)));
g_value_unset (&return_value);
}
diff --git a/GType.xs b/GType.xs
index 78641ac..02e24a4 100644
--- a/GType.xs
+++ b/GType.xs
@@ -977,7 +977,7 @@ gperl_signal_class_closure_marshal (GClosure *closure,
* objects. */
EXTEND (SP, (int)n_param_values);
for (i = 0; i < n_param_values; i++)
- PUSHs (sv_2mortal (gperl_sv_from_value
+ SAVED_STACK_PUSHs (sv_2mortal (gperl_sv_from_value
((GValue*) ¶m_values[i])));
PUTBACK;
@@ -1091,8 +1091,8 @@ gperl_real_signal_accumulator (GSignalInvocationHint *ihint,
PUSHMARK (SP);
PUSHs (sv_2mortal (newSVGSignalInvocationHint (ihint)));
- PUSHs (sv_2mortal (gperl_sv_from_value (return_accu)));
- PUSHs (sv_2mortal (gperl_sv_from_value (handler_return)));
+ SAVED_STACK_PUSHs (sv_2mortal (gperl_sv_from_value (return_accu)));
+ SAVED_STACK_PUSHs (sv_2mortal (gperl_sv_from_value (handler_return)));
if (callback->data)
XPUSHs (callback->data);
@@ -1624,7 +1624,7 @@ gperl_type_set_property (GObject * object,
SAVETMPS;
PUSHMARK (SP);
PUSHs (sv_2mortal (gperl_new_object (object, FALSE)));
- XPUSHs (sv_2mortal (gperl_sv_from_value (value)));
+ SAVED_STACK_XPUSHs (sv_2mortal (gperl_sv_from_value (value)));
PUTBACK;
call_sv (setter, G_VOID|G_DISCARD);
SPAGAIN;
@@ -1647,7 +1647,7 @@ gperl_type_set_property (GObject * object,
PUSHMARK (SP);
XPUSHs (sv_2mortal (gperl_new_object (object, FALSE)));
XPUSHs (sv_2mortal (newSVGParamSpec (pspec)));
- XPUSHs (sv_2mortal (gperl_sv_from_value (value)));
+ SAVED_STACK_XPUSHs (sv_2mortal (gperl_sv_from_value (value)));
PUTBACK;
call_sv ((SV *)GvCV (*slot), G_VOID|G_DISCARD);
diff --git a/GValue.xs b/GValue.xs
index 7eb6882..0243d2b 100644
--- a/GValue.xs
+++ b/GValue.xs
@@ -177,9 +177,13 @@ gperl_value_from_sv (GValue * value,
* Coerce whatever is in I<value> into a perl scalar and return it.
* If I<copy_boxed> is true, boxed values will be copied. Values of type
* GPERL_TYPE_SV are always copied (since that is merely a ref).
- *
+ *
* Croaks if the code doesn't know how to perform the conversion.
- *
+ *
+ * Might end up calling other Perl code. So if you use this function in XS
+ * code for a generic GType, make sure the stack pointer is set up correctly
+ * before the call, and restore it after the call.
+ *
* =cut
*/
SV *
@@ -304,6 +308,10 @@ Coerce whatever is in I<value> into a perl scalar and return it.
Croaks if the code doesn't know how to perform the conversion.
+Might end up calling other Perl code. So if you use this function in XS code
+for a generic GType, make sure the stack pointer is set up correctly before the
+call, and restore it after the call.
+
=cut
SV *
gperl_sv_from_value (const GValue * value)
diff --git a/NEWS b/NEWS
index 06149b1..f3fd4e9 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,9 @@ Overview of changes in Glib <next>
==================================
* Correctly handle the boxed type for GError.
+* Make the stack handling of some marshallers more robust, in
+ preparation for custom Glib::Boxed converters that call back into Perl
+ code.
Overview of changes in Glib 1.261 (stable)
==========================================
diff --git a/gperl-private.h b/gperl-private.h
index 68f7ce0..d3c99b4 100644
--- a/gperl-private.h
+++ b/gperl-private.h
@@ -39,4 +39,23 @@ SV * _gperl_sv_from_value_internal (const GValue * value, gboolean copy_boxed);
SV * _gperl_fetch_wrapper_key (GObject * object, const char * name, gboolean create);
+#define SAVED_STACK_SV(expr) \
+ ({ \
+ SV *_saved_stack_sv; \
+ PUTBACK; \
+ _saved_stack_sv = expr; \
+ SPAGAIN; \
+ _saved_stack_sv; \
+ })
+#define SAVED_STACK_PUSHs(expr) \
+ (void) ({ \
+ SV *_saved_stack_sv = SAVED_STACK_SV (expr); \
+ PUSHs (_saved_stack_sv); \
+ })
+#define SAVED_STACK_XPUSHs(expr) \
+ (void) ({ \
+ SV *_saved_stack_sv = SAVED_STACK_SV (expr); \
+ XPUSHs (_saved_stack_sv); \
+ })
+
#endif /* _GPERL_PRIVATE_H_ */
diff --git a/gperl_marshal.h b/gperl_marshal.h
index 23af292..6951a4d 100644
--- a/gperl_marshal.h
+++ b/gperl_marshal.h
@@ -126,6 +126,7 @@ This assumes that n_param_values > 1.
*/
/* note -- keep an eye on the refcounts of instance and data! */
#define GPERL_CLOSURE_MARSHAL_PUSH_INSTANCE(param_values) \
+ PUTBACK; \
if (GPERL_CLOSURE_SWAP_DATA (pc)) { \
/* swap instance and data */ \
data = gperl_sv_from_value (param_values); \
@@ -135,6 +136,7 @@ This assumes that n_param_values > 1.
instance = gperl_sv_from_value (param_values); \
data = SvREFCNT_inc (pc->data); \
} \
+ SPAGAIN; \
if (!instance) \
instance = &PL_sv_undef; \
/* the instance is always the first item in @_ */ \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]