This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
[PATCH] Fix a bug in parser where use of parens right after unary '&' was rejected
- From: "Yichun Zhang (agentzh)" <agentzh at gmail dot com>
- To: systemtap at sourceware dot org
- Cc: "Yichun Zhang (agentzh)" <agentzh at gmail dot com>
- Date: Thu, 23 Aug 2018 20:33:54 -0700
- Subject: [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