STATIC SV *indirect_tag(pTHX_ SV *value) {
#define indirect_tag(V) indirect_tag(aTHX_ (V))
indirect_hint_t *h;
- SV *code = NULL;
+ SV *code = NULL;
+#if I_THREADSAFE
+ dMY_CXT;
+
+ if (!MY_CXT.tbl)
+ return newSViv(0);
+#endif /* I_THREADSAFE */
if (SvROK(value)) {
value = SvRV(value);
#endif /* !I_HINT_STRUCT */
#if I_THREADSAFE
- {
- dMY_CXT;
- /* We only need for the key to be an unique tag for looking up the value later
- * Allocated memory provides convenient unique identifiers, so that's why we
- * use the hint as the key itself. */
- ptable_hints_store(MY_CXT.tbl, h, h);
- }
+ /* We only need for the key to be an unique tag for looking up the value later
+ * Allocated memory provides convenient unique identifiers, so that's why we
+ * use the hint as the key itself. */
+ ptable_hints_store(MY_CXT.tbl, h, h);
#endif /* I_THREADSAFE */
return newSViv(PTR2IV(h));
dMY_CXT;
#endif
+#if I_THREADSAFE
+ if (!MY_CXT.tbl)
+ return NULL;
+#endif /* I_THREADSAFE */
+
h = INT2PTR(indirect_hint_t *, SvIVX(hint));
#if I_THREADSAFE
h = ptable_fetch(MY_CXT.tbl, h);
STRLEN len;
dMY_CXT;
+ /* No need to check for MY_CXT.map != NULL because this code path is always
+ * guarded by indirect_hint(). */
+
if (!(oi = ptable_fetch(MY_CXT.map, o))) {
Newx(oi, 1, indirect_op_info_t);
ptable_store(MY_CXT.map, o, oi);
#define indirect_map_fetch(O) indirect_map_fetch(aTHX_ (O))
dMY_CXT;
+ /* No need to check for MY_CXT.map != NULL because this code path is always
+ * guarded by indirect_hint(). */
+
return ptable_fetch(MY_CXT.map, o);
}
#define indirect_map_delete(O) indirect_map_delete(aTHX_ (O))
dMY_CXT;
- ptable_delete(MY_CXT.map, o);
+ if (MY_CXT.map)
+ ptable_delete(MY_CXT.map, o);
}
/* --- Check functions ----------------------------------------------------- */
With 5.8 perls, the pragma does not propagate into C<eval STRING>.
This is due to a shortcoming in the way perl handles the hints hash, which is addressed in perl 5.10.
+Indirect constructs that appear in code C<eval>'d during the global destruction phase of a spawned thread or pseudo-fork (the processes used internally for the C<fork> emulation on Windows) are not reported.
+
The search for indirect method calls happens before constant folding.
Hence C<my $x = new Class if 0> will be caught.
use VPIT::TestHelpers;
use indirect::TestThreads;
-use Test::Leaner tests => 1;
+use Test::Leaner tests => 3;
SKIP:
{
RUN
is $status, 0, 'loading the pragma in a thread and using it outside doesn\'t segfault';
}
+
+{
+ my $status = run_perl <<' RUN';
+ use threads;
+ BEGIN { require indirect; }
+ sub X::DESTROY { eval 'no indirect; 1'; exit 1 if $@ }
+ threads->create(sub {
+ my $x = bless { }, 'X';
+ $x->{self} = $x;
+ return;
+ })->join;
+ exit $code;
+ RUN
+ is $status, 0, 'indirect can be loaded in eval STRING during global destruction at the end of a thread';
+}
+
+{
+ my $status = run_perl <<' RUN';
+ use threads;
+ use threads::shared;
+ my $code : shared;
+ $code = 0;
+ no indirect cb => sub { lock $code; ++$code };
+ sub X::DESTROY { eval $_[0]->{code} }
+ threads->create(sub {
+ my $x = bless { code => 'new Z' }, 'X';
+ $x->{self} = $x;
+ return;
+ })->join;
+ exit $code;
+ RUN
+ is $status, 0, 'indirect does not check eval STRING during global destruction at the end of a thread';
+}