toke.c: Make _charnames check more robust
authorFather Chrysostomos <sprout@cpan.org>
Thu, 6 Dec 2012 07:10:25 +0000 (23:10 -0800)
committerFather Chrysostomos <sprout@cpan.org>
Sun, 9 Dec 2012 02:44:28 +0000 (18:44 -0800)
Assuming that $^H{charnames} exists and contains a code ref can result
in crashes.  See the tests in the diff.

It’s not a good idea to do $INC{"_charnames.pm"}++, but perl still
shouldn’t crash.

t/op/lex.t
toke.c

index 0789077..c009f2d 100644 (file)
@@ -4,7 +4,7 @@ use warnings;
 
 require './test.pl';
 
-plan(tests => 4);
+plan(tests => 7);
 
 {
     no warnings 'deprecated';
@@ -45,3 +45,26 @@ curr_test(3);
 
 }
 
+fresh_perl_is(
+  'BEGIN{ ++$_ for @INC{"charnames.pm","_charnames.pm"} } "\N{a}"',
+  'Constant(\N{a}) unknown at - line 1, within string' . "\n"
+ ."Execution of - aborted due to compilation errors.\n",
+   { stderr => 1 },
+  'correct output (and no crash) when charnames cannot load for \N{...}'
+);
+fresh_perl_is(
+  'BEGIN{ ++$_ for @INC{"charnames.pm","_charnames.pm"};
+          $^H{charnames} = "foo" } "\N{a}"',
+  "Undefined subroutine &main::foo called at - line 2.\n"
+ ."Propagated at - line 2, within string\n"
+ ."Execution of - aborted due to compilation errors.\n",
+   { stderr => 1 },
+  'no crash when charnames cannot load and %^H holds string'
+);
+fresh_perl_is(
+  'BEGIN{ ++$_ for @INC{"charnames.pm","_charnames.pm"} } "\N{a}"',
+  'Constant(\N{a}) unknown at - line 1, within string' . "\n"
+ ."Execution of - aborted due to compilation errors.\n",
+   { stderr => 1 },
+  'no crash when charnames cannot load and %^H holds string reference'
+);
diff --git a/toke.c b/toke.c
index bb81b4a..26057a5 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -2697,9 +2697,8 @@ S_get_and_check_backslash_N_name(pTHX_ const char* s, const char* const e)
      * validation. */
     table = GvHV(PL_hintgv);            /* ^H */
     cvp = hv_fetchs(table, "charnames", FALSE);
-    cv = *cvp;
-    if (((rv = SvRV(cv)) != NULL)
-        && ((stash = CvSTASH(rv)) != NULL))
+    if (cvp && (cv = *cvp) && SvROK(cv) && ((rv = SvRV(cv)) != NULL)
+        && SvTYPE(rv) == SVt_PVCV && ((stash = CvSTASH(rv)) != NULL))
     {
         const char * const name = HvNAME(stash);
         if strEQ(name, "_charnames") {