From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 13738 invoked by alias); 28 Aug 2018 22:25:08 -0000 Mailing-List: contact systemtap-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: systemtap-owner@sourceware.org Received: (qmail 13536 invoked by uid 89); 28 Aug 2018 22:24:55 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=AWL,BAYES_00,FREEMAIL_FROM,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.2 spammy=874, H*r:sk:d9-v6so X-HELO: mail-pl1-f196.google.com Received: from mail-pl1-f196.google.com (HELO mail-pl1-f196.google.com) (209.85.214.196) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 28 Aug 2018 22:24:49 +0000 Received: by mail-pl1-f196.google.com with SMTP id d9-v6so1355040plr.2 for ; Tue, 28 Aug 2018 15:24:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=cCRe0ibslQ0NNYlv8A3NTsgqQASvCE+LnADG/IEZCkY=; b=Yb4jtDRDoUWuOwSXNWFxKPLIY9Rqh2pF3xZi2Jgdp7ms5Ck80PzODLUxftIRKASeps U3RMo56ETuItmM30T/yYlvaaiOWAcA2RfspLFXmw6K3eJqp8AtlmJpmjDhhcSlmULlJT x867pxdsp35G6ED/vIgpyJC+gtB5uOH4DzZAzQcQ54z5zSb9YK6G+FUuwDfA3am9Q5FQ BwWPxJA7pKBkLOlch0yluoP4oJeFGaGktDKltDeUAr+JRvzJrlosTRIxGfvKHsjFLb8C bVHZPwBrPuouAhWl/oOAvhO38IL5T93vY8EZ4xtp7vQ/D/jRPT/n39JcNkxs5J+boxbh WLdQ== Return-Path: Received: from localhost.localdomain (c-73-158-61-143.hsd1.ca.comcast.net. [73.158.61.143]) by smtp.gmail.com with ESMTPSA id p19-v6sm3010321pgh.60.2018.08.28.15.24.36 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 28 Aug 2018 15:24:37 -0700 (PDT) From: "Yichun Zhang (agentzh)" To: systemtap@sourceware.org Cc: "Yichun Zhang (agentzh)" Subject: [PATCH v3] Add support for return statements without values Date: Tue, 28 Aug 2018 22:25:00 -0000 Message-Id: <20180828222432.32141-1-agentzh@gmail.com> In-Reply-To: <20180828205312.125366-1-agentzh@gmail.com> References: <20180828205312.125366-1-agentzh@gmail.com> X-IsSubscribed: yes X-SW-Source: 2018-q3/txt/msg00139.txt.bz2 For user-defined stap functions which do not return any values, it can be convenient to allow *bare* return statements to take shortcuts in the control flow of the function body. The parser treats a following semicolon (';'), a closing curly bracket ('}'), or a statement prefix keyword like 'if', 'while', and 'delete', as a terminator for such bare return statements. Added tests to cover various cases like use of plain 'return' in a function actually returning some values. Also added tests to make sure the pretty-printer adds a trailing semicolon for such bare return stateuments for various arrangements. Both the "kernel" and "dyninst" runtimes are covered. A fix for the bpf translator is also included. Updated NEWS to document this new feature. --- NEWS | 8 + bpf-translate.cxx | 3 +- elaborate.cxx | 8 + parse.cxx | 17 +- staptree.cxx | 8 +- testsuite/systemtap.base/return_no_val.exp | 874 ++++++++++++++++++++++++++ testsuite/systemtap.base/return_no_val_1.stp | 10 + testsuite/systemtap.base/return_no_val_10.stp | 10 + testsuite/systemtap.base/return_no_val_11.stp | 12 + testsuite/systemtap.base/return_no_val_12.stp | 14 + testsuite/systemtap.base/return_no_val_13.stp | 12 + testsuite/systemtap.base/return_no_val_14.stp | 12 + testsuite/systemtap.base/return_no_val_15.stp | 7 + testsuite/systemtap.base/return_no_val_16.stp | 10 + testsuite/systemtap.base/return_no_val_17.stp | 10 + testsuite/systemtap.base/return_no_val_18.stp | 10 + testsuite/systemtap.base/return_no_val_19.stp | 9 + testsuite/systemtap.base/return_no_val_2.stp | 10 + testsuite/systemtap.base/return_no_val_20.stp | 11 + testsuite/systemtap.base/return_no_val_3.stp | 10 + testsuite/systemtap.base/return_no_val_4.stp | 9 + testsuite/systemtap.base/return_no_val_5.stp | 12 + testsuite/systemtap.base/return_no_val_6.stp | 13 + testsuite/systemtap.base/return_no_val_7.stp | 13 + testsuite/systemtap.base/return_no_val_8.stp | 15 + testsuite/systemtap.base/return_no_val_9.stp | 10 + translate.cxx | 11 +- 27 files changed, 1142 insertions(+), 6 deletions(-) create mode 100644 testsuite/systemtap.base/return_no_val.exp create mode 100644 testsuite/systemtap.base/return_no_val_1.stp create mode 100644 testsuite/systemtap.base/return_no_val_10.stp create mode 100644 testsuite/systemtap.base/return_no_val_11.stp create mode 100644 testsuite/systemtap.base/return_no_val_12.stp create mode 100644 testsuite/systemtap.base/return_no_val_13.stp create mode 100644 testsuite/systemtap.base/return_no_val_14.stp create mode 100644 testsuite/systemtap.base/return_no_val_15.stp create mode 100644 testsuite/systemtap.base/return_no_val_16.stp create mode 100644 testsuite/systemtap.base/return_no_val_17.stp create mode 100644 testsuite/systemtap.base/return_no_val_18.stp create mode 100644 testsuite/systemtap.base/return_no_val_19.stp create mode 100644 testsuite/systemtap.base/return_no_val_2.stp create mode 100644 testsuite/systemtap.base/return_no_val_20.stp create mode 100644 testsuite/systemtap.base/return_no_val_3.stp create mode 100644 testsuite/systemtap.base/return_no_val_4.stp create mode 100644 testsuite/systemtap.base/return_no_val_5.stp create mode 100644 testsuite/systemtap.base/return_no_val_6.stp create mode 100644 testsuite/systemtap.base/return_no_val_7.stp create mode 100644 testsuite/systemtap.base/return_no_val_8.stp create mode 100644 testsuite/systemtap.base/return_no_val_9.stp diff --git a/NEWS b/NEWS index ab20986bf..29c2e737d 100644 --- a/NEWS +++ b/NEWS @@ -34,6 +34,14 @@ '+=', just like the C language. The original operator precedence can be restored by the '--compatible 3.3' option. +- The script language now supports the use of bare 'return' statements + (without any return values) inside functions which do not return any + values. A trailing semincolon is recommended for such return + statements to avoid any potential ambiguity. The parser treats a + following semicolon (';'), a closing curly bracket ('}'), or a + statement prefix keyword like 'if', 'while', and 'delete', as a + terminator for such bare return statements. + * What's new in version 3.3, 2018-06-08 - A new "stap --example FOO.stp" mode searches the example scripts diff --git a/bpf-translate.cxx b/bpf-translate.cxx index 95c68ce8d..26ceb9fcf 100644 --- a/bpf-translate.cxx +++ b/bpf-translate.cxx @@ -915,7 +915,8 @@ bpf_unparser::visit_return_statement (return_statement* s) if (func_return.empty ()) throw SEMANTIC_ERROR (_("cannot 'return' outside function"), s->tok); assert (!func_return_val.empty ()); - emit_mov (func_return_val.back (), emit_expr (s->value)); + if (s->value) + emit_mov (func_return_val.back (), emit_expr (s->value)); emit_jmp (func_return.back ()); } diff --git a/elaborate.cxx b/elaborate.cxx index c55818f02..cd03df408 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -6892,6 +6892,14 @@ typeresolution_info::visit_return_statement (return_statement* e) exp_type& e_type = current_function->type; t = current_function->type; + + if (!e->value) + { + if (e_type != pe_unknown) + mismatch (e->tok, pe_unknown, current_function); + return; + } + e->value->visit (this); if (e_type != pe_unknown && e->value->type != pe_unknown diff --git a/parse.cxx b/parse.cxx index 7904e0dff..5656d322e 100644 --- a/parse.cxx +++ b/parse.cxx @@ -2868,7 +2868,22 @@ parser::parse_return_statement () throw PARSE_ERROR (_("found 'return' not in function context")); return_statement* s = new return_statement; s->tok = t; - s->value = parse_expression (); + + t = peek (); + if ((t->type == tok_operator && (t->content == ";" || t->content == "}")) + || (t->type == tok_keyword && (t->content == "delete" + || t->content == "if" + || t->content == "for" + || t->content == "foreach" + || t->content == "return" + || t->content == "next" + || t->content == "try" + || t->content == "while" + || t->content == "break" + || t->content == "continue"))) + s->value = NULL; // no return value + else + s->value = parse_expression (); return s; } diff --git a/staptree.cxx b/staptree.cxx index d1193e336..25cc9fe7c 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -1313,7 +1313,10 @@ void expr_statement::print (ostream& o) const void return_statement::print (ostream& o) const { - o << "return " << *value; + if (value) + o << "return " << *value; + else + o << "return"; } @@ -1964,7 +1967,8 @@ traversing_visitor::visit_foreach_loop (foreach_loop* s) void traversing_visitor::visit_return_statement (return_statement* s) { - s->value->visit (this); + if (s->value) + s->value->visit (this); } void diff --git a/testsuite/systemtap.base/return_no_val.exp b/testsuite/systemtap.base/return_no_val.exp new file mode 100644 index 000000000..c42289bee --- /dev/null +++ b/testsuite/systemtap.base/return_no_val.exp @@ -0,0 +1,874 @@ +set test "return_no_val" +set testpath "$srcdir/$subdir" + +if {! [installtest_p]} { untested "$test"; return } + +# --- TEST 1 --- + +set subtest1 "TEST 1: return no value in void type func (in the middle)" +foreach runtime [get_runtime_list] { + if {$runtime eq ""} { + set runtime "kernel" + } + set test_name "$test: $subtest1 ($runtime)" + + set cmd "stap --runtime=$runtime '$srcdir/$subdir/${test}_1.stp'" + send_log "executing: $cmd\n" + set pipe [open "| sh -c {$cmd}" r] + set out [read $pipe] + set failed 0 + if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } + } + + set exp_out "enter f\nexit\n" + regsub -all -- {\n} $exp_out {\n} escaped_exp_out + if {$out eq $exp_out} { + pass "${test_name}: stdout matches \"$escaped_exp_out\"" + } else { + fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\"" + } + + set stderr_pat "\\AWARNING: statement will never be reached: identifier 'println' at \[^\\n\]*?\\.stp:4:5\\n source: println\\(\"leave f\"\\);\\n \\^\\n\\Z" + regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat + if {[regexp -linestop -- $stderr_pat $stderr]} { + pass "${test_name}: stderr matches \"$escaped_stderr_pat\"" + } else { + fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\"" + } + + if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" + } else { + pass "${test_name}: exit code is zero" + } +} + +# --- TEST 2 --- + +set subtest2 "TEST 2: return no value in void type func (at the end, no-op)" +foreach runtime [get_runtime_list] { + if {$runtime eq ""} { + set runtime "kernel" + } + set test_name "$test: $subtest2 ($runtime)" + + set cmd "stap --runtime=$runtime '$srcdir/$subdir/${test}_2.stp'" + send_log "executing: $cmd\n" + set pipe [open "| sh -c {$cmd}" r] + set out [read $pipe] + set failed 0 + if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } + } + + set exp_out "enter f\nleave f\nexit\n" + regsub -all -- {\n} $exp_out {\n} escaped_exp_out + if {$out eq $exp_out} { + pass "${test_name}: stdout matches \"$escaped_exp_out\"" + } else { + fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\"" + } + + set exp_stderr "" + regsub -all -- {\n} $exp_stderr {\n} escaped_exp_stderr + if {$stderr eq $exp_stderr} { + pass "${test_name}: stderr matches \"$escaped_exp_stderr\"" + } else { + fail "${test_name}: stderr fails to match \"$escaped_exp_stderr\": got \"$stderr\"" + } + + if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" + } else { + pass "${test_name}: exit code is zero" + } +} + +# --- TEST 3 --- + +set subtest3 "TEST 3: return nothing in long type func (inferred by another return stmt)" +set test_name "$test: $subtest3" + +set cmd "stap '$srcdir/$subdir/${test}_3.stp'" +send_log "executing: $cmd\n" +set pipe [open "| sh -c {$cmd}" r] +set out [read $pipe] +set failed 0 +if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } +} + +set exp_out "" +regsub -all -- {\n} $exp_out {\n} escaped_exp_out +if {$out eq $exp_out} { + pass "${test_name}: stdout matches \"$escaped_exp_out\"" +} else { + fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\"" +} + +if {$failed} { + pass "${test_name}: exit code should be non-zero" +} else { + fail "${test_name}: exit code should be non-zero but is zero" +} + +set stderr_pat "\\Asemantic error: type mismatch \\(unknown\\): keyword at \[^\\n\]*?\\.stp:3:9\\n source: return;\\n \\^\\n\\nsemantic error: type was first inferred here \\(long\\): number '1' at :5:12\\n source: return 1;\\n \\^\\n" +regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat +if {[regexp -linestop -- $stderr_pat $stderr]} { + pass "${test_name}: stderr matches \"$escaped_stderr_pat\"" +} else { + fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\"" +} + +# --- TEST 4 --- + +set subtest4 "TEST 4: return nothing in long type func (inferred by caller)" +set test_name "$test: $subtest4" + +set cmd "stap '$srcdir/$subdir/${test}_4.stp'" +send_log "executing: $cmd\n" +set pipe [open "| sh -c {$cmd}" r] +set out [read $pipe] +set failed 0 +if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } +} + +set exp_out "" +regsub -all -- {\n} $exp_out {\n} escaped_exp_out +if {$out eq $exp_out} { + pass "${test_name}: stdout matches \"$escaped_exp_out\"" +} else { + fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\"" +} + +if {$failed} { + pass "${test_name}: exit code should be non-zero" +} else { + fail "${test_name}: exit code should be non-zero but is zero" +} + +set stderr_pat "\\Asemantic error: type mismatch \\(unknown\\): keyword at \[^\\n\]*?\\.stp:3:9\\n source: return;\\n \\^\\n\\nsemantic error: type was first inferred here \\(long\\): identifier 'f' at :8:17\\n source: println\\(1 \\+ f\\(3\\)\\)\\n \\^\\n\\n" +regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat +if {[regexp -linestop -- $stderr_pat $stderr]} { + pass "${test_name}: stderr matches \"$escaped_stderr_pat\"" +} else { + fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\"" +} + +# --- TEST 5 --- + +set subtest5 "TEST 5: 'return' right before 'if'" +foreach runtime [get_runtime_list] { + if {$runtime eq ""} { + set runtime "kernel" + } + set test_name "$test: $subtest5 ($runtime)" + + set cmd "stap --runtime=$runtime '$srcdir/$subdir/${test}_5.stp'" + send_log "executing: $cmd\n" + set pipe [open "| sh -c {$cmd}" r] + set out [read $pipe] + set failed 0 + if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } + } + + set exp_out "enter f\nexit\n" + regsub -all -- {\n} $exp_out {\n} escaped_exp_out + if {$out eq $exp_out} { + pass "${test_name}: stdout matches \"$escaped_exp_out\"" + } else { + fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\"" + } + + set stderr_pat "\\AWARNING: statement will never be reached: identifier 'println' at \[^\\n\]*?\\.stp:5:9\\n source: println\\(\"leave f\"\\);\\n \\^\\n\\Z" + regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat + if {[regexp -linestop -- $stderr_pat $stderr]} { + pass "${test_name}: stderr matches \"$escaped_stderr_pat\"" + } else { + fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\"" + } + + if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" + } else { + pass "${test_name}: exit code is zero" + } +} + +# --- TEST 6 --- + +set subtest6 "TEST 6: 'return' right before 'for'" +foreach runtime [get_runtime_list] { + if {$runtime eq ""} { + set runtime "kernel" + } + set test_name "$test: $subtest6 ($runtime)" + + set cmd "stap --runtime=$runtime '$srcdir/$subdir/${test}_6.stp'" + send_log "executing: $cmd\n" + set pipe [open "| sh -c {$cmd}" r] + set out [read $pipe] + set failed 0 + if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } + } + + set exp_out "enter f\nexit\n" + regsub -all -- {\n} $exp_out {\n} escaped_exp_out + if {$out eq $exp_out} { + pass "${test_name}: stdout matches \"$escaped_exp_out\"" + } else { + fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\"" + } + + set stderr_pat "\\AWARNING: statement will never be reached: keyword at \[^\\n\]*?\\.stp:4:5\\n source: for \\(;;\\) \\\{\\n \\^\\n\\Z" + regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat + if {[regexp -linestop -- $stderr_pat $stderr]} { + pass "${test_name}: stderr matches \"$escaped_stderr_pat\"" + } else { + fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\"" + } + + if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" + } else { + pass "${test_name}: exit code is zero" + } +} + +# --- TEST 7 --- + +set subtest7 "TEST 7: 'return' right before 'while'" +foreach runtime [get_runtime_list] { + if {$runtime eq ""} { + set runtime "kernel" + } + set test_name "$test: $subtest7 ($runtime)" + + set cmd "stap --runtime=$runtime '$srcdir/$subdir/${test}_7.stp'" + send_log "executing: $cmd\n" + set pipe [open "| sh -c {$cmd}" r] + set out [read $pipe] + set failed 0 + if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } + } + + set exp_out "enter f\nexit\n" + regsub -all -- {\n} $exp_out {\n} escaped_exp_out + if {$out eq $exp_out} { + pass "${test_name}: stdout matches \"$escaped_exp_out\"" + } else { + fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\"" + } + + set stderr_pat "\\AWARNING: statement will never be reached: keyword at \[^\\n\]*?\\.stp:4:5\\n source: while \\(1\\) \\\{\\n \\^\\n\\Z" + regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat + if {[regexp -linestop -- $stderr_pat $stderr]} { + pass "${test_name}: stderr matches \"$escaped_stderr_pat\"" + } else { + fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\"" + } + + if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" + } else { + pass "${test_name}: exit code is zero" + } +} + +# --- TEST 8 --- + +set subtest8 "TEST 8: 'return' right before 'foreach'" +foreach runtime [get_runtime_list] { + if {$runtime eq ""} { + set runtime "kernel" + } + set test_name "$test: $subtest8 ($runtime)" + + set cmd "stap --runtime=$runtime '$srcdir/$subdir/${test}_8.stp'" + send_log "executing: $cmd\n" + set pipe [open "| sh -c {$cmd}" r] + set out [read $pipe] + set failed 0 + if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } + } + + set exp_out "enter f\na\[1\] = 3\n" + regsub -all -- {\n} $exp_out {\n} escaped_exp_out + if {$out eq $exp_out} { + pass "${test_name}: stdout matches \"$escaped_exp_out\"" + } else { + fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\"" + } + + set stderr_pat "\\AWARNING: statement will never be reached: keyword at \[^\\n\]*?\\.stp:6:5\\n source: foreach \\(k in a\\) \\\{\\n \\^\\n\\Z" + regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat + if {[regexp -linestop -- $stderr_pat $stderr]} { + pass "${test_name}: stderr matches \"$escaped_stderr_pat\"" + } else { + fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\"" + } + + if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" + } else { + pass "${test_name}: exit code is zero" + } +} + +# --- TEST 9 --- + +set subtest9 "TEST 9: 'return' right before 'return'" +foreach runtime [get_runtime_list] { + if {$runtime eq ""} { + set runtime "kernel" + } + set test_name "$test: $subtest9 ($runtime)" + + set cmd "stap --runtime=$runtime '$srcdir/$subdir/${test}_9.stp'" + send_log "executing: $cmd\n" + set pipe [open "| sh -c {$cmd}" r] + set out [read $pipe] + set failed 0 + if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } + } + + set exp_out "enter f\nexit\n" + regsub -all -- {\n} $exp_out {\n} escaped_exp_out + if {$out eq $exp_out} { + pass "${test_name}: stdout matches \"$escaped_exp_out\"" + } else { + fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\"" + } + + set stderr_pat "\\AWARNING: statement will never be reached: keyword at \[^\\n\]*?\\.stp:4:5\\n source: return\\n \\^\\n\\Z" + regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat + if {[regexp -linestop -- $stderr_pat $stderr]} { + pass "${test_name}: stderr matches \"$escaped_stderr_pat\"" + } else { + fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\"" + } + + if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" + } else { + pass "${test_name}: exit code is zero" + } +} + +# --- TEST 10 --- + +set subtest10 "TEST 10: 'return' right before 'next'" +foreach runtime [get_runtime_list] { + if {$runtime eq ""} { + set runtime "kernel" + } + set test_name "$test: $subtest10 ($runtime)" + + set cmd "stap --runtime=$runtime '$srcdir/$subdir/${test}_10.stp'" + send_log "executing: $cmd\n" + set pipe [open "| sh -c {$cmd}" r] + set out [read $pipe] + set failed 0 + if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } + } + + set exp_out "enter f\nexit\n" + regsub -all -- {\n} $exp_out {\n} escaped_exp_out + if {$out eq $exp_out} { + pass "${test_name}: stdout matches \"$escaped_exp_out\"" + } else { + fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\"" + } + + set stderr_pat "\\AWARNING: statement will never be reached: keyword at \[^\\n\]*?\\.stp:4:5\\n source: next\\n \\^\\n\\Z" + regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat + if {[regexp -linestop -- $stderr_pat $stderr]} { + pass "${test_name}: stderr matches \"$escaped_stderr_pat\"" + } else { + fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\"" + } + + if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" + } else { + pass "${test_name}: exit code is zero" + } +} + +# --- TEST 11 --- + +set subtest11 "TEST 11: 'return' right before 'delete'" +foreach runtime [get_runtime_list] { + if {$runtime eq ""} { + set runtime "kernel" + } + set test_name "$test: $subtest11 ($runtime)" + + set cmd "stap --runtime=$runtime '$srcdir/$subdir/${test}_11.stp'" + send_log "executing: $cmd\n" + set pipe [open "| sh -c {$cmd}" r] + set out [read $pipe] + set failed 0 + if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } + } + + set exp_out "enter f\na\[1\] = 3\n" + regsub -all -- {\n} $exp_out {\n} escaped_exp_out + if {$out eq $exp_out} { + pass "${test_name}: stdout matches \"$escaped_exp_out\"" + } else { + fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\"" + } + + set stderr_pat "\\AWARNING: statement will never be reached: keyword at \[^\\n\]*?\\.stp:6:5\\n source: delete a\\n \\^\\n\\Z" + regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat + if {[regexp -linestop -- $stderr_pat $stderr]} { + pass "${test_name}: stderr matches \"$escaped_stderr_pat\"" + } else { + fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\"" + } + + if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" + } else { + pass "${test_name}: exit code is zero" + } +} + +# --- TEST 12 --- + +set subtest12 "TEST 12: 'return' right before 'try'" +foreach runtime [get_runtime_list] { + if {$runtime eq ""} { + set runtime "kernel" + } + set test_name "$test: $subtest12 ($runtime)" + + set cmd "stap --runtime=$runtime '$srcdir/$subdir/${test}_12.stp'" + send_log "executing: $cmd\n" + set pipe [open "| sh -c {$cmd}" r] + set out [read $pipe] + set failed 0 + if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } + } + + set exp_out "enter f\na\[1\] = 3\n" + regsub -all -- {\n} $exp_out {\n} escaped_exp_out + if {$out eq $exp_out} { + pass "${test_name}: stdout matches \"$escaped_exp_out\"" + } else { + fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\"" + } + + set stderr_pat "\\AWARNING: statement will never be reached: keyword at \[^\\n\]*?\\.stp:6:5\\n source: try \\\{\\n \\^\\n\\Z" + regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat + if {[regexp -linestop -- $stderr_pat $stderr]} { + pass "${test_name}: stderr matches \"$escaped_stderr_pat\"" + } else { + fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\"" + } + + if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" + } else { + pass "${test_name}: exit code is zero" + } +} + +# --- TEST 13 --- + +set subtest13 "TEST 13: 'return' right before 'break'" +foreach runtime [get_runtime_list] { + if {$runtime eq ""} { + set runtime "kernel" + } + set test_name "$test: $subtest13 ($runtime)" + + set cmd "stap --runtime=$runtime '$srcdir/$subdir/${test}_13.stp'" + send_log "executing: $cmd\n" + set pipe [open "| sh -c {$cmd}" r] + set out [read $pipe] + set failed 0 + if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } + } + + set exp_out "enter f\nexit\n" + regsub -all -- {\n} $exp_out {\n} escaped_exp_out + if {$out eq $exp_out} { + pass "${test_name}: stdout matches \"$escaped_exp_out\"" + } else { + fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\"" + } + + set stderr_pat "\\AWARNING: statement will never be reached: keyword at \[^\\n\]*?\\.stp:5:9\\n source: break\\n \\^\\n\\Z" + regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat + if {[regexp -linestop -- $stderr_pat $stderr]} { + pass "${test_name}: stderr matches \"$escaped_stderr_pat\"" + } else { + fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\"" + } + + if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" + } else { + pass "${test_name}: exit code is zero" + } +} + +# --- TEST 14 --- + +set subtest14 "TEST 14: 'return' right before 'continue'" +foreach runtime [get_runtime_list] { + if {$runtime eq ""} { + set runtime "kernel" + } + set test_name "$test: $subtest14 ($runtime)" + + set cmd "stap --runtime=$runtime '$srcdir/$subdir/${test}_14.stp'" + send_log "executing: $cmd\n" + set pipe [open "| sh -c {$cmd}" r] + set out [read $pipe] + set failed 0 + if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } + } + + set exp_out "enter f\nexit\n" + regsub -all -- {\n} $exp_out {\n} escaped_exp_out + if {$out eq $exp_out} { + pass "${test_name}: stdout matches \"$escaped_exp_out\"" + } else { + fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\"" + } + + set stderr_pat "\\AWARNING: statement will never be reached: keyword at \[^\\n\]*?\\.stp:5:9\\n source: continue\\n \\^\\n\\Z" + regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat + if {[regexp -linestop -- $stderr_pat $stderr]} { + pass "${test_name}: stderr matches \"$escaped_stderr_pat\"" + } else { + fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\"" + } + + if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" + } else { + pass "${test_name}: exit code is zero" + } +} + +# --- TEST 15 --- + +set subtest15 "TEST 15: pretty-printer adds a semicolon (two return stmts in a row)" +set test_name "$test: $subtest15" + +set cmd "stap -p1 '$srcdir/$subdir/${test}_15.stp'" +send_log "executing: $cmd\n" +set pipe [open "| sh -c {$cmd}" r] +set out [read $pipe] +set failed 0 +if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } +} + +set out_pat "^return;\\nreturn;\\n" +regsub -all -- {\n} $out_pat {\n} escaped_out_pat +if {[regexp -linestop -lineanchor -- $out_pat $out]} { + pass "${test_name}: stdout matches \"$escaped_out_pat\"" +} else { + fail "${test_name}: stdout fails to match \"$escaped_out_pat\": got \"$out\"" +} + +if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" +} else { + pass "${test_name}: exit code is zero" +} +if {$stderr ne ""} { + send_log "stderr:\n$stderr" +} + +# --- TEST 16 --- + +set subtest16 "TEST 16: pretty-printer adds a semicolon (right before if)" +set test_name "$test: $subtest16" + +set cmd "stap -p1 '$srcdir/$subdir/${test}_16.stp'" +send_log "executing: $cmd\n" +set pipe [open "| sh -c {$cmd}" r] +set out [read $pipe] +set failed 0 +if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } +} + +set out_pat "^\\s*return;\\n" +regsub -all -- {\n} $out_pat {\n} escaped_out_pat +if {[regexp -linestop -lineanchor -- $out_pat $out]} { + pass "${test_name}: stdout matches \"$escaped_out_pat\"" +} else { + fail "${test_name}: stdout fails to match \"$escaped_out_pat\": got \"$out\"" +} + +if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" +} else { + pass "${test_name}: exit code is zero" +} +if {$stderr ne ""} { + send_log "stderr:\n$stderr" +} + +# --- TEST 17 --- + +set subtest17 "TEST 17: pretty-printer adds a semicolon (under if)" +set test_name "$test: $subtest17" + +set cmd "stap -p1 '$srcdir/$subdir/${test}_17.stp'" +send_log "executing: $cmd\n" +set pipe [open "| sh -c {$cmd}" r] +set out [read $pipe] +set failed 0 +if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } +} + +set out_pat "^if \\(1\\) return\n;\n" +regsub -all -- {\n} $out_pat {\n} escaped_out_pat +if {[regexp -linestop -lineanchor -- $out_pat $out]} { + pass "${test_name}: stdout matches \"$escaped_out_pat\"" +} else { + fail "${test_name}: stdout fails to match \"$escaped_out_pat\": got \"$out\"" +} + +if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" +} else { + pass "${test_name}: exit code is zero" +} +if {$stderr ne ""} { + send_log "stderr:\n$stderr" +} + +# --- TEST 18 --- + +set subtest18 "TEST 18: pretty-printer adds a semicolon (under for)" +set test_name "$test: $subtest18" + +set cmd "stap -p1 '$srcdir/$subdir/${test}_18.stp'" +send_log "executing: $cmd\n" +set pipe [open "| sh -c {$cmd}" r] +set out [read $pipe] +set failed 0 +if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } +} + +set out_pat "^for \\(; 1; \\) return;\n" +regsub -all -- {\n} $out_pat {\n} escaped_out_pat +if {[regexp -linestop -lineanchor -- $out_pat $out]} { + pass "${test_name}: stdout matches \"$escaped_out_pat\"" +} else { + fail "${test_name}: stdout fails to match \"$escaped_out_pat\": got \"$out\"" +} + +if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" +} else { + pass "${test_name}: exit code is zero" +} +if {$stderr ne ""} { + send_log "stderr:\n$stderr" +} + +# --- TEST 19 --- + +set subtest19 "TEST 19: pretty-printer adds a semicolon (under while)" +set test_name "$test: $subtest19" + +set cmd "stap -p1 '$srcdir/$subdir/${test}_19.stp'" +send_log "executing: $cmd\n" +set pipe [open "| sh -c {$cmd}" r] +set out [read $pipe] +set failed 0 +if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } +} + +set out_pat "^for \\(; 1; \\) return;\n" +regsub -all -- {\n} $out_pat {\n} escaped_out_pat +if {[regexp -linestop -lineanchor -- $out_pat $out]} { + pass "${test_name}: stdout matches \"$escaped_out_pat\"" +} else { + fail "${test_name}: stdout fails to match \"$escaped_out_pat\": got \"$out\"" +} + +if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" +} else { + pass "${test_name}: exit code is zero" +} +if {$stderr ne ""} { + send_log "stderr:\n$stderr" +} + +# --- TEST 20 --- + +set subtest20 "TEST 20: pretty-printer adds a semicolon (under foreach)" +set test_name "$test: $subtest20" + +set cmd "stap -p1 '$srcdir/$subdir/${test}_20.stp'" +send_log "executing: $cmd\n" +set pipe [open "| sh -c {$cmd}" r] +set out [read $pipe] +set failed 0 +if {[catch {close $pipe} stderr] != 0} { + if {$stderr ne "" && [string index $stderr end] ne "\n"} { + append stderr "\n" + } + global errorCode + if {"CHILDSTATUS" == [lindex $errorCode 0]} { + set failed [lindex $errorCode 2] + } +} + +set out_pat "^foreach \\(\\\[k\\\] in a\\) return;\n" +regsub -all -- {\n} $out_pat {\n} escaped_out_pat +if {[regexp -linestop -lineanchor -- $out_pat $out]} { + pass "${test_name}: stdout matches \"$escaped_out_pat\"" +} else { + fail "${test_name}: stdout fails to match \"$escaped_out_pat\": got \"$out\"" +} + +if {$failed} { + fail "${test_name}: exit code should be zero but is $failed" +} else { + pass "${test_name}: exit code is zero" +} +if {$stderr ne ""} { + send_log "stderr:\n$stderr" +} diff --git a/testsuite/systemtap.base/return_no_val_1.stp b/testsuite/systemtap.base/return_no_val_1.stp new file mode 100644 index 000000000..48c54fc73 --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_1.stp @@ -0,0 +1,10 @@ +function f() { + println("enter f"); + return; + println("leave f"); +} + +probe oneshot { + f(); + printf("exit\n"); +} diff --git a/testsuite/systemtap.base/return_no_val_10.stp b/testsuite/systemtap.base/return_no_val_10.stp new file mode 100644 index 000000000..b30ddc126 --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_10.stp @@ -0,0 +1,10 @@ +function f() { + println("enter f"); + return + next +} + +probe oneshot { + f(); + printf("exit\n"); +} diff --git a/testsuite/systemtap.base/return_no_val_11.stp b/testsuite/systemtap.base/return_no_val_11.stp new file mode 100644 index 000000000..0de8a2c81 --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_11.stp @@ -0,0 +1,12 @@ +global a +function f() { + println("enter f"); + a[1] = 3 + return + delete a +} + +probe oneshot { + f(); + printf("a[1] = %d\n", a[1]); +} diff --git a/testsuite/systemtap.base/return_no_val_12.stp b/testsuite/systemtap.base/return_no_val_12.stp new file mode 100644 index 000000000..2f28e5df4 --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_12.stp @@ -0,0 +1,14 @@ +global a +function f() { + println("enter f"); + a[1] = 3 + return + try { + delete a + } catch {} +} + +probe oneshot { + f(); + printf("a[1] = %d\n", a[1]); +} diff --git a/testsuite/systemtap.base/return_no_val_13.stp b/testsuite/systemtap.base/return_no_val_13.stp new file mode 100644 index 000000000..cd64295c0 --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_13.stp @@ -0,0 +1,12 @@ +function f() { + while (1) { + println("enter f"); + return + break + } +} + +probe oneshot { + f(); + printf("exit\n"); +} diff --git a/testsuite/systemtap.base/return_no_val_14.stp b/testsuite/systemtap.base/return_no_val_14.stp new file mode 100644 index 000000000..b4a5d942a --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_14.stp @@ -0,0 +1,12 @@ +function f() { + while (1) { + println("enter f"); + return + continue + } +} + +probe oneshot { + f(); + printf("exit\n"); +} diff --git a/testsuite/systemtap.base/return_no_val_15.stp b/testsuite/systemtap.base/return_no_val_15.stp new file mode 100644 index 000000000..60fb3b622 --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_15.stp @@ -0,0 +1,7 @@ +function f() { + return return +} + +probe oneshot { + f(); +} diff --git a/testsuite/systemtap.base/return_no_val_16.stp b/testsuite/systemtap.base/return_no_val_16.stp new file mode 100644 index 000000000..3bcfc2d94 --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_16.stp @@ -0,0 +1,10 @@ +function f() { + return + if (1) { + println("leave f"); + } +} + +probe oneshot { + f(); +} diff --git a/testsuite/systemtap.base/return_no_val_17.stp b/testsuite/systemtap.base/return_no_val_17.stp new file mode 100644 index 000000000..4c2197676 --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_17.stp @@ -0,0 +1,10 @@ +function f() { + if (1) + return + while (1) + next +} + +probe oneshot { + f(); +} diff --git a/testsuite/systemtap.base/return_no_val_18.stp b/testsuite/systemtap.base/return_no_val_18.stp new file mode 100644 index 000000000..cdd52826b --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_18.stp @@ -0,0 +1,10 @@ +function f() { + for (;;) + return + while (1) + next +} + +probe oneshot { + f(); +} diff --git a/testsuite/systemtap.base/return_no_val_19.stp b/testsuite/systemtap.base/return_no_val_19.stp new file mode 100644 index 000000000..318deeeae --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_19.stp @@ -0,0 +1,9 @@ +function f() { + while (1) + return + next +} + +probe oneshot { + f(); +} diff --git a/testsuite/systemtap.base/return_no_val_2.stp b/testsuite/systemtap.base/return_no_val_2.stp new file mode 100644 index 000000000..adda25b53 --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_2.stp @@ -0,0 +1,10 @@ +function f() { + println("enter f"); + println("leave f"); + return; +} + +probe oneshot { + f(); + printf("exit\n"); +} diff --git a/testsuite/systemtap.base/return_no_val_20.stp b/testsuite/systemtap.base/return_no_val_20.stp new file mode 100644 index 000000000..77f824a3b --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_20.stp @@ -0,0 +1,11 @@ +global a +function f() { + a[1] = 3 + foreach (k in a) + return + next +} + +probe oneshot { + f(); +} diff --git a/testsuite/systemtap.base/return_no_val_3.stp b/testsuite/systemtap.base/return_no_val_3.stp new file mode 100644 index 000000000..c3f4c910c --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_3.stp @@ -0,0 +1,10 @@ +function f(a) { + if (a > 0) { + return; + } + return 1; +} + +probe oneshot { + println(f(3)) +} diff --git a/testsuite/systemtap.base/return_no_val_4.stp b/testsuite/systemtap.base/return_no_val_4.stp new file mode 100644 index 000000000..3d93abef7 --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_4.stp @@ -0,0 +1,9 @@ +function f(a) { + if (a > 0) { + return; + } +} + +probe oneshot { + println(1 + f(3)) +} diff --git a/testsuite/systemtap.base/return_no_val_5.stp b/testsuite/systemtap.base/return_no_val_5.stp new file mode 100644 index 000000000..2f6d42bd0 --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_5.stp @@ -0,0 +1,12 @@ +function f() { + println("enter f"); + return + if (1) { + println("leave f"); + } +} + +probe oneshot { + f(); + printf("exit\n"); +} diff --git a/testsuite/systemtap.base/return_no_val_6.stp b/testsuite/systemtap.base/return_no_val_6.stp new file mode 100644 index 000000000..1f6529ea8 --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_6.stp @@ -0,0 +1,13 @@ +function f() { + println("enter f"); + return + for (;;) { + println("leave f"); + return + } +} + +probe oneshot { + f(); + printf("exit\n"); +} diff --git a/testsuite/systemtap.base/return_no_val_7.stp b/testsuite/systemtap.base/return_no_val_7.stp new file mode 100644 index 000000000..4d243bf56 --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_7.stp @@ -0,0 +1,13 @@ +function f() { + println("enter f"); + return + while (1) { + println("leave f"); + return + } +} + +probe oneshot { + f(); + printf("exit\n"); +} diff --git a/testsuite/systemtap.base/return_no_val_8.stp b/testsuite/systemtap.base/return_no_val_8.stp new file mode 100644 index 000000000..6291e0c63 --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_8.stp @@ -0,0 +1,15 @@ +global a +function f() { + println("enter f"); + a[1] = 3 + return + foreach (k in a) { + println("k: ", k); + return + } +} + +probe oneshot { + f(); + printf("a[1] = %d\n", a[1]); +} diff --git a/testsuite/systemtap.base/return_no_val_9.stp b/testsuite/systemtap.base/return_no_val_9.stp new file mode 100644 index 000000000..b1d33d5c6 --- /dev/null +++ b/testsuite/systemtap.base/return_no_val_9.stp @@ -0,0 +1,10 @@ +function f() { + println("enter f"); + return + return +} + +probe oneshot { + f(); + printf("exit\n"); +} diff --git a/translate.cxx b/translate.cxx index c7e7aa53f..8c78df8a1 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4405,11 +4405,18 @@ c_unparser::visit_return_statement (return_statement* s) if (current_function == 0) throw SEMANTIC_ERROR (_("cannot 'return' from probe"), s->tok); - if (s->value->type != current_function->type) + if (s->value) + { + if (s->value->type != current_function->type) + throw SEMANTIC_ERROR (_("return type mismatch"), current_function->tok, + s->tok); + + c_assign ("l->__retvalue", s->value, "return value"); + } + else if (current_function->type != pe_unknown) throw SEMANTIC_ERROR (_("return type mismatch"), current_function->tok, s->tok); - c_assign ("l->__retvalue", s->value, "return value"); record_actions(1, s->tok, true); o->newline() << "goto out;"; } -- 2.11.0.295.gd7dffce