Skip to content

pp_ctl.c: Unreachable code identified #23958

@jkeenan

Description

@jkeenan

This issue addresses case JJJ mentioned in #23889 (comment). It requires some background. Let's go back in time to November/December 2022.

v5.37.6

Suppose I checkout v5.37.6, and then, for debugging purposes, mangle one of the exception messages in pp_ctl.c.

$ git status
HEAD detached at v5.37.6
...

$ git diff
diff --git a/pp_ctl.c b/pp_ctl.c
index d0b5d8d013..defc89fd6e 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -2928,7 +2928,7 @@ PP(pp_goto)
             for(ix = cxstack_ix; ix > cxix; ix--) {
                 if(CxTYPE(&cxstack[ix]) == CXt_DEFER)
                     /* diag_listed_as: Can't "%s" out of a "defer" block */
-                    Perl_croak(aTHX_ "Can't \"%s\" out of a \"%s\" block",
+                    Perl_croak(aTHX_ "Can't \"%s\" JJJ:out of a \"%s\" block",
                             "goto", S_defer_blockname(&cxstack[ix]));
             }

Running make test_harness at this point reveals a failure in t/op/defer.t (also porting/bench.t, but I think that's a separate concern). When I run t/op/defer.t, I get:

$ cd t;./perl harness -v op/defer.t; cd -
ok 1 - defer block is invoked
ok 2 - defer block can contain multiple statements
...
ok 25 - Cannot goto out of defer block
ok 26 - Cannot goto into defer block
not ok 27 - Cannot goto &SUB out of a "defer" block
ok 28 - Cannot last out of defer block
...
# Failed test 27 - Cannot goto &SUB out of a "defer" block at op/defer.t line 303
#      got 'Can\'t \"goto\" JJJ:out of a \"defer\" block at op/defer.t line 298.\n'
# expected /(?^:^Can't "goto" out of a "defer" block at )/
Failed 1/30 subtests 

Test Summary Report
-------------------
op/defer.t (Wstat: 0 Tests: 30 Failed: 1)
  Failed test:  27
Files=1, Tests=30,  0 wallclock secs ( 0.00 usr +  0.00 sys =  0.00 CPU)

I get one test failure which merely reflects the mangled message, but that does indicate that this section of pp_ctl.c is exercised (covered) by the test suite.

v5.37.7

Now suppose I checkout v5.37.7, then cherry-pick the same one-line exception message revision I did for v5.37.6. If I then run t/op/defer.t, I do not get any test failures. But that's misleading, because there are 4 fewer unit tests in that file, and test Cannot goto &SUB out of a "defer" block is one of the ones that no longer appears. The 4 tests were essentially transferred to t/lib/croak/op in abf573d. (When I run make test_harness the only failures I get are, once again, in t/porting/bench.t.)

Now suppose I mangle one more exception message, this time in op.c:

$ git diff
diff --git a/op.c b/op.c
index 887f2fc7ad..cdfd9be19c 100644
--- a/op.c
+++ b/op.c
@@ -5176,7 +5176,7 @@ static void walk_ops_forbid(pTHX_ OP *o, U32 flags, HV *permittedloops, const ch
 forbid:
             /* diag_listed_as: Can't "%s" out of a "defer" block */
             /* diag_listed_as: Can't "%s" out of a "finally" block */
-            croak("Can't \"%s\" out of %s", PL_op_name[o->op_type], blockname);
+            croak("Can't \"%s\" ZZZ:out of %s", PL_op_name[o->op_type], blockname);
 
         default:
             break;

This change leads to 6 test failures in t/lib/croak.t and demonstrates that the croak statement with ZZZ: in it is the source of the failures. This is not really surprising; the commit message for abf573d:

commit abf573d1658ed41e29b6dae390645908838b313b
Author: Paul Evans <leonerd@leonerd.org.uk>
Date:   Wed Dec 14 12:24:09 2022 +0000

    Detect forbidden flow at compiletime of `defer` or `finally`
    
    Using the new `forbid_outofblock_ops()`, many kinds of forbidden control
    flow out of a `defer` or `finally` block can be detected statically with
    this function by analysing the optree, rather than leaving it until
    runtime when the attempt is actually made.

Inference:

We have a block of code in pp_ctl.c that can no longer be reached. It can be removed without causing any test failures. Pull request forthcoming.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions