This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix a bug in parser where use of parens right after unary '&' was rejected


The parser did not allow stap expressions like `&(@var("foo"))` while
`&@var("foo")` is always allowed.

Added quite some tests to cover various use cases of the unary `&`
address-taking operator.
---
 parse.cxx                              |  13 +-
 testsuite/systemtap.base/addr_op.exp   | 210 +++++++++++++++++++++++++++++++++
 testsuite/systemtap.base/addr_op_1.c   |  10 ++
 testsuite/systemtap.base/addr_op_1.stp |   6 +
 testsuite/systemtap.base/addr_op_2.stp |   8 ++
 testsuite/systemtap.base/addr_op_3.stp |   6 +
 testsuite/systemtap.base/addr_op_4.c   |   5 +
 testsuite/systemtap.base/addr_op_4.stp |   7 ++
 testsuite/systemtap.base/addr_op_5.stp |   6 +
 9 files changed, 269 insertions(+), 2 deletions(-)
 create mode 100644 testsuite/systemtap.base/addr_op.exp
 create mode 100644 testsuite/systemtap.base/addr_op_1.c
 create mode 100644 testsuite/systemtap.base/addr_op_1.stp
 create mode 100644 testsuite/systemtap.base/addr_op_2.stp
 create mode 100644 testsuite/systemtap.base/addr_op_3.stp
 create mode 100644 testsuite/systemtap.base/addr_op_4.c
 create mode 100644 testsuite/systemtap.base/addr_op_4.stp
 create mode 100644 testsuite/systemtap.base/addr_op_5.stp

diff --git a/parse.cxx b/parse.cxx
index 751f56add..bf5fcba81 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -3694,8 +3694,17 @@ parser::parse_dwarf_value ()
     // '&' on old version only allowed specific target_symbol types
     throw PARSE_ERROR (_("expected @cast, @var or $var"));
   else
-    // Otherwise just get a plain value of any sort.
-    expr = parse_value ();
+    {
+      // Otherwise just get a plain value of any sort.
+      expr = parse_value ();
+      if (addressof)
+        {
+          tsym = dynamic_cast<target_symbol*> (expr);
+          if (tsym && tsym->addressof)
+            throw PARSE_ERROR (_("cannot take address more than once"),
+                               addrtok);
+        }
+    }
 
   // If we had '&' or see any target suffixes, that forces a target_symbol.
   // For compatibility, we only do this starting with 2.6.
diff --git a/testsuite/systemtap.base/addr_op.exp b/testsuite/systemtap.base/addr_op.exp
new file mode 100644
index 000000000..64dd5a3a3
--- /dev/null
+++ b/testsuite/systemtap.base/addr_op.exp
@@ -0,0 +1,210 @@
+set test "addr_op"
+set testpath "$srcdir/$subdir"
+
+if {! [installtest_p]} { untested "$test"; return }
+if {! [uretprobes_p]} { untested "$test"; return }
+
+# --- TEST 1 ---
+
+set subtest1 "TEST 1: 2 excessive parens after unary '&' - with components"
+
+set res [target_compile ${testpath}/${test}_1.c ./a.out executable \
+    "additional_flags=-O additional_flags=-g"]
+if {$res ne ""} {
+    verbose "target_compile failed: $res" 2
+    fail "${test_name}: unable to compile ${test}_1.c"
+} else {
+    foreach runtime [get_runtime_list] {
+        if {$runtime eq ""} { set runtime "kernel" }
+        set test_name "$test: $subtest1 ($runtime)"
+
+        set cmd "stap --runtime=$runtime -c ./a.out '$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} { set failed 1 }
+
+        set exp_out "1\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\""
+        }
+
+        if {$failed} {
+            fail "${test_name}: exit code not zero"
+        } else {
+            pass "${test_name}: exit code is zero"
+        }
+        if {$stderr ne ""} {
+            send_log "stderr:\n$stderr"
+        }
+    }
+}
+
+# --- TEST 2 ---
+
+set subtest2 "TEST 2: one excessive paren after unary '&' - with components"
+
+set res [target_compile ${testpath}/${test}_1.c ./a.out executable \
+    "additional_flags=-O additional_flags=-g"]
+if {$res ne ""} {
+    verbose "target_compile failed: $res" 2
+    fail "${test_name}: unable to compile ${test}_1.c"
+} else {
+    foreach runtime [get_runtime_list] {
+        if {$runtime eq ""} { set runtime "kernel" }
+        set test_name "$test: $subtest2 ($runtime)"
+
+        set cmd "stap --runtime=$runtime -c ./a.out '$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} { set failed 1 }
+
+        set exp_out "1\n1\n0\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\""
+        }
+
+        if {$failed} {
+            fail "${test_name}: exit code not zero"
+        } else {
+            pass "${test_name}: exit code is zero"
+        }
+        if {$stderr ne ""} {
+            send_log "stderr:\n$stderr"
+        }
+    }
+}
+
+# --- TEST 3 ---
+
+set subtest3 "TEST 3: 2 excessive parens after unary '&' - without components"
+
+set res [target_compile ${testpath}/${test}_1.c ./a.out executable \
+    "additional_flags=-O additional_flags=-g"]
+if {$res ne ""} {
+    verbose "target_compile failed: $res" 2
+    fail "${test_name}: unable to compile ${test}_1.c"
+} else {
+    foreach runtime [get_runtime_list] {
+        if {$runtime eq ""} { set runtime "kernel" }
+        set test_name "$test: $subtest3 ($runtime)"
+
+        set cmd "stap --runtime=$runtime -c ./a.out '$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} { set failed 1 }
+
+        set exp_out "1\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\""
+        }
+
+        if {$failed} {
+            fail "${test_name}: exit code not zero"
+        } else {
+            pass "${test_name}: exit code is zero"
+        }
+        if {$stderr ne ""} {
+            send_log "stderr:\n$stderr"
+        }
+    }
+}
+
+# --- TEST 4 ---
+
+set subtest4 "TEST 4: taking address of int globals"
+
+set res [target_compile ${testpath}/${test}_4.c ./a.out executable \
+    "additional_flags=-O additional_flags=-g"]
+if {$res ne ""} {
+    verbose "target_compile failed: $res" 2
+    fail "${test_name}: unable to compile ${test}_4.c"
+} else {
+    foreach runtime [get_runtime_list] {
+        if {$runtime eq ""} { set runtime "kernel" }
+        set test_name "$test: $subtest4 ($runtime)"
+
+        set cmd "stap --runtime=$runtime -c ./a.out '$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} { set failed 1 }
+
+        set exp_out "1\n-32\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\""
+        }
+
+        if {$failed} {
+            fail "${test_name}: exit code not zero"
+        } else {
+            pass "${test_name}: exit code is zero"
+        }
+        if {$stderr ne ""} {
+            send_log "stderr:\n$stderr"
+        }
+    }
+}
+
+# --- TEST 5 ---
+
+set subtest5 "TEST 5: duplicate unary '&'"
+
+set res [target_compile ${testpath}/${test}_4.c ./a.out executable \
+    "additional_flags=-O additional_flags=-g"]
+if {$res ne ""} {
+    verbose "target_compile failed: $res" 2
+    fail "${test_name}: unable to compile ${test}_4.c"
+} else {
+    foreach runtime [get_runtime_list] {
+        if {$runtime eq ""} { set runtime "kernel" }
+        set test_name "$test: $subtest5 ($runtime)"
+
+        set cmd "stap --runtime=$runtime -c ./a.out '$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} { set failed 1 }
+
+        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 "\\Aparse error: cannot take address more than once\\n         at: operator '&' at .*?\\.stp:2:9\\n     source:     q = &\\(\\(&\\@var\\(\"a\"\\)\\)\\);\\n                     \\^\\n\\n1 parse error\\.\\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\""
+        }
+    }
+}
diff --git a/testsuite/systemtap.base/addr_op_1.c b/testsuite/systemtap.base/addr_op_1.c
new file mode 100644
index 000000000..c9ff20e1f
--- /dev/null
+++ b/testsuite/systemtap.base/addr_op_1.c
@@ -0,0 +1,10 @@
+struct foo {
+    int a;
+    int b[3];
+};
+
+struct foo v;
+
+int main(void) {
+    return 0;
+}
diff --git a/testsuite/systemtap.base/addr_op_1.stp b/testsuite/systemtap.base/addr_op_1.stp
new file mode 100644
index 000000000..2e8f88639
--- /dev/null
+++ b/testsuite/systemtap.base/addr_op_1.stp
@@ -0,0 +1,6 @@
+probe process.function("main") {
+    p = &@var("v")->b[0];
+    q = &((@var("v")->b[0]));
+    printf("%d\n", p == q);
+    exit();
+}
diff --git a/testsuite/systemtap.base/addr_op_2.stp b/testsuite/systemtap.base/addr_op_2.stp
new file mode 100644
index 000000000..0e7c14269
--- /dev/null
+++ b/testsuite/systemtap.base/addr_op_2.stp
@@ -0,0 +1,8 @@
+probe process.function("main") {
+    p = &@var("v")->b[0];
+    q = &(@var("v")->b[0]);
+    printf("%d\n", p == q);
+    printf("%d\n", q == @var("v")->b);
+    printf("%d\n", q == &((@var("v")->b[1])));
+    exit();
+}
diff --git a/testsuite/systemtap.base/addr_op_3.stp b/testsuite/systemtap.base/addr_op_3.stp
new file mode 100644
index 000000000..55ca2ff10
--- /dev/null
+++ b/testsuite/systemtap.base/addr_op_3.stp
@@ -0,0 +1,6 @@
+probe process.function("main") {
+    p = &@var("v");
+    q = &((@var("v")));
+    printf("%d\n", p == q);
+    exit();
+}
diff --git a/testsuite/systemtap.base/addr_op_4.c b/testsuite/systemtap.base/addr_op_4.c
new file mode 100644
index 000000000..62261ef53
--- /dev/null
+++ b/testsuite/systemtap.base/addr_op_4.c
@@ -0,0 +1,5 @@
+int a = -32;
+
+int main(void) {
+    return 0;
+}
diff --git a/testsuite/systemtap.base/addr_op_4.stp b/testsuite/systemtap.base/addr_op_4.stp
new file mode 100644
index 000000000..d4cb86d13
--- /dev/null
+++ b/testsuite/systemtap.base/addr_op_4.stp
@@ -0,0 +1,7 @@
+probe process.function("main") {
+    p = &@var("a");
+    q = &((@var("a")));
+    printf("%d\n", p == q);
+    printf("%d\n", user_int(q));
+    exit();
+}
diff --git a/testsuite/systemtap.base/addr_op_5.stp b/testsuite/systemtap.base/addr_op_5.stp
new file mode 100644
index 000000000..843b301df
--- /dev/null
+++ b/testsuite/systemtap.base/addr_op_5.stp
@@ -0,0 +1,6 @@
+probe process.function("main") {
+    q = &((&@var("a")));
+    printf("%d\n", p == q);
+    printf("%d\n", user_int(q));
+    exit();
+}
-- 
2.11.0.295.gd7dffce


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]