asan-dg.exp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. # Copyright (C) 2012-2015 Free Software Foundation, Inc.
  2. # This program is free software; you can redistribute it and/or modify
  3. # it under the terms of the GNU General Public License as published by
  4. # the Free Software Foundation; either version 3 of the License, or
  5. # (at your option) any later version.
  6. #
  7. # This program is distributed in the hope that it will be useful,
  8. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. # GNU General Public License for more details.
  11. #
  12. # You should have received a copy of the GNU General Public License
  13. # along with GCC; see the file COPYING3. If not see
  14. # <http://www.gnu.org/licenses/>.
  15. # Return 1 if compilation with -fsanitize=address is error-free for trivial
  16. # code, 0 otherwise.
  17. proc check_effective_target_fsanitize_address {} {
  18. return [check_no_compiler_messages fsanitize_address executable {
  19. int main (void) { return 0; }
  20. } "-fsanitize=address"]
  21. }
  22. proc asan_include_flags {} {
  23. global srcdir
  24. global TESTING_IN_BUILD_TREE
  25. set flags ""
  26. if { [is_remote host] || ! [info exists TESTING_IN_BUILD_TREE] } {
  27. return "${flags}"
  28. }
  29. set flags "-I$srcdir/../../libsanitizer/include"
  30. return "$flags"
  31. }
  32. #
  33. # asan_link_flags -- compute library path and flags to find libasan.
  34. # (originally from g++.exp)
  35. #
  36. proc asan_link_flags { paths } {
  37. global srcdir
  38. global ld_library_path
  39. global shlib_ext
  40. global asan_saved_library_path
  41. set gccpath ${paths}
  42. set flags ""
  43. set shlib_ext [get_shlib_extension]
  44. set asan_saved_library_path $ld_library_path
  45. if { $gccpath != "" } {
  46. if { [file exists "${gccpath}/libsanitizer/asan/.libs/libasan.a"]
  47. || [file exists "${gccpath}/libsanitizer/asan/.libs/libasan.${shlib_ext}"] } {
  48. append flags " -B${gccpath}/libsanitizer/ "
  49. append flags " -B${gccpath}/libsanitizer/asan/ "
  50. append flags " -L${gccpath}/libsanitizer/asan/.libs "
  51. append ld_library_path ":${gccpath}/libsanitizer/asan/.libs"
  52. }
  53. } else {
  54. global tool_root_dir
  55. set libasan [lookfor_file ${tool_root_dir} libasan]
  56. if { $libasan != "" } {
  57. append flags "-L${libasan} "
  58. append ld_library_path ":${libasan}"
  59. }
  60. }
  61. set_ld_library_path_env_vars
  62. return "$flags"
  63. }
  64. #
  65. # asan_init -- called at the start of each subdir of tests
  66. #
  67. proc asan_init { args } {
  68. global TEST_ALWAYS_FLAGS
  69. global ALWAYS_CXXFLAGS
  70. global TOOL_OPTIONS
  71. global asan_saved_TEST_ALWAYS_FLAGS
  72. global asan_saved_ALWAYS_CXXFLAGS
  73. set link_flags ""
  74. if ![is_remote host] {
  75. if [info exists TOOL_OPTIONS] {
  76. set link_flags "[asan_link_flags [get_multilibs ${TOOL_OPTIONS}]]"
  77. } else {
  78. set link_flags "[asan_link_flags [get_multilibs]]"
  79. }
  80. }
  81. set include_flags "[asan_include_flags]"
  82. if [info exists TEST_ALWAYS_FLAGS] {
  83. set asan_saved_TEST_ALWAYS_FLAGS $TEST_ALWAYS_FLAGS
  84. }
  85. if [info exists ALWAYS_CXXFLAGS] {
  86. set asan_saved_ALWAYS_CXXFLAGS $ALWAYS_CXXFLAGS
  87. set ALWAYS_CXXFLAGS [concat "{ldflags=$link_flags}" $ALWAYS_CXXFLAGS]
  88. set ALWAYS_CXXFLAGS [concat "{additional_flags=-fsanitize=address -g $include_flags}" $ALWAYS_CXXFLAGS]
  89. } else {
  90. if [info exists TEST_ALWAYS_FLAGS] {
  91. set TEST_ALWAYS_FLAGS "$link_flags -fsanitize=address -g $include_flags $TEST_ALWAYS_FLAGS"
  92. } else {
  93. set TEST_ALWAYS_FLAGS "$link_flags -fsanitize=address -g $include_flags"
  94. }
  95. }
  96. }
  97. #
  98. # asan_finish -- called at the start of each subdir of tests
  99. #
  100. proc asan_finish { args } {
  101. global TEST_ALWAYS_FLAGS
  102. global asan_saved_TEST_ALWAYS_FLAGS
  103. global asan_saved_ALWAYS_CXXFLAGS
  104. global asan_saved_library_path
  105. global ld_library_path
  106. if [info exists asan_saved_ALWAYS_CXXFLAGS ] {
  107. set ALWAYS_CXXFLAGS $asan_saved_ALWAYS_CXXFLAGS
  108. } else {
  109. if [info exists asan_saved_TEST_ALWAYS_FLAGS] {
  110. set TEST_ALWAYS_FLAGS $asan_saved_TEST_ALWAYS_FLAGS
  111. } else {
  112. unset TEST_ALWAYS_FLAGS
  113. }
  114. }
  115. set ld_library_path $asan_saved_library_path
  116. set_ld_library_path_env_vars
  117. }
  118. # Symbolize lines like
  119. # #2 0xdeadbeef (/some/path/libsanitizer.so.0.0.0+0xbeef)
  120. # in $output using addr2line to
  121. # #2 0xdeadbeef in foobar file:123
  122. proc asan_symbolize { output } {
  123. set addresses [regexp -inline -all -line "^ *#\[0-9\]+ 0x\[0-9a-f\]+ \[(\](\[^)\]+)\[+\](0x\[0-9a-f\]+)\[)\]$" "$output"]
  124. if { [llength $addresses] > 0 } {
  125. set addr2line_name [find_binutils_prog addr2line]
  126. set idx 1
  127. while { $idx < [llength $addresses] } {
  128. set key [regsub -all "\[\]\[\]" [lindex $addresses $idx] "\\\\&"]
  129. set val [lindex $addresses [expr $idx + 1]]
  130. lappend arr($key) $val
  131. set idx [expr $idx + 3]
  132. }
  133. foreach key [array names arr] {
  134. set args "-f -e $key $arr($key)"
  135. set status [remote_exec host "$addr2line_name" "$args"]
  136. if { [lindex $status 0] > 0 } continue
  137. regsub -all "\r\n" [lindex $status 1] "\n" addr2line_output
  138. regsub -all "\[\n\r\]BFD: \[^\n\r\]*" $addr2line_output "" addr2line_output
  139. regsub -all "^BFD: \[^\n\r\]*\[\n\r\]" $addr2line_output "" addr2line_output
  140. set addr2line_output [regexp -inline -all -line "^\[^\n\r]*" $addr2line_output]
  141. set idx 0
  142. foreach val $arr($key) {
  143. if { [expr $idx + 1] < [llength $addr2line_output] } {
  144. set fnname [lindex $addr2line_output $idx]
  145. set fileline [lindex $addr2line_output [expr $idx + 1]]
  146. if { "$fnname" != "??" } {
  147. set newkey "$key+$val"
  148. set repl($newkey) "$fnname $fileline"
  149. }
  150. set idx [expr $idx + 2]
  151. }
  152. }
  153. }
  154. set idx 0
  155. set new_output ""
  156. while {[regexp -start $idx -indices " #\[0-9\]+ 0x\[0-9a-f\]+ \[(\](\[^)\]+\[+\]0x\[0-9a-f\]+)\[)\]" "$output" -> addr] > 0} {
  157. set low [lindex $addr 0]
  158. set high [lindex $addr 1]
  159. set val [string range "$output" $low $high]
  160. append new_output [string range "$output" $idx [expr $low - 2]]
  161. if [info exists repl($val)] {
  162. append new_output "in $repl($val)"
  163. } else {
  164. append new_output "($val)"
  165. }
  166. set idx [expr $high + 2]
  167. }
  168. append new_output [string range "$output" $idx [string length "$output"]]
  169. return "$new_output"
  170. }
  171. return "$output"
  172. }
  173. # Return a list of gtest tests, printed in the form
  174. # DEJAGNU_GTEST_TEST AddressSanitizer_SimpleDeathTest
  175. # DEJAGNU_GTEST_TEST AddressSanitizer_VariousMallocsTest
  176. proc asan_get_gtest_test_list { output } {
  177. set idx 0
  178. set ret ""
  179. while {[regexp -start $idx -indices "DEJAGNU_GTEST_TEST (\[^\n\r\]*)(\r\n|\n|\r)" "$output" -> testname] > 0} {
  180. set low [lindex $testname 0]
  181. set high [lindex $testname 1]
  182. set val [string range "$output" $low $high]
  183. lappend ret $val
  184. set idx [expr $high + 1]
  185. }
  186. return $ret
  187. }
  188. # Return a list of gtest EXPECT_DEATH tests, printed in the form
  189. # DEJAGNU_GTEST_EXPECT_DEATH1 statement DEJAGNU_GTEST_EXPECT_DEATH1 regexp DEJAGNU_GTEST_EXPECT_DEATH1
  190. # DEJAGNU_GTEST_EXPECT_DEATH2 other statement DEJAGNU_GTEST_EXPECT_DEATH2 other regexp DEJAGNU_GTEST_EXPECT_DEATH2
  191. proc asan_get_gtest_expect_death_list { output } {
  192. set idx 0
  193. set ret ""
  194. while {[regexp -start $idx -indices "DEJAGNU_GTEST_EXPECT_DEATH(\[0-9\]*)" "$output" -> id ] > 0} {
  195. set low [lindex $id 0]
  196. set high [lindex $id 1]
  197. set val_id [string range "$output" $low $high]
  198. if {[regexp -start $low -indices "$val_id (.*) DEJAGNU_GTEST_EXPECT_DEATH$val_id (.*) DEJAGNU_GTEST_EXPECT_DEATH$val_id\[\n\r\]" "$output" whole statement regexpr ] == 0} { break }
  199. set low [lindex $statement 0]
  200. set high [lindex $statement 1]
  201. set val_statement [string range "$output" $low $high]
  202. set low [lindex $regexpr 0]
  203. set high [lindex $regexpr 1]
  204. set val_regexpr [string range "$output" $low $high]
  205. lappend ret [list "$val_id" "$val_statement" "$val_regexpr"]
  206. set idx [lindex $whole 1]
  207. }
  208. return $ret
  209. }
  210. # Replace ${tool}_load with a wrapper so that we can symbolize the output.
  211. if { [info procs ${tool}_load] != [list] \
  212. && [info procs saved_asan_${tool}_load] == [list] } {
  213. rename ${tool}_load saved_asan_${tool}_load
  214. proc ${tool}_load { program args } {
  215. global tool
  216. global asan_last_gtest_test_list
  217. global asan_last_gtest_expect_death_list
  218. set result [eval [list saved_asan_${tool}_load $program] $args]
  219. set output [lindex $result 1]
  220. set symbolized_output [asan_symbolize "$output"]
  221. set asan_last_gtest_test_list [asan_get_gtest_test_list "$output"]
  222. set asan_last_gtest_expect_death_list [asan_get_gtest_expect_death_list "$output"]
  223. set result [list [lindex $result 0] $symbolized_output]
  224. return $result
  225. }
  226. }
  227. # Utility for running gtest asan emulation under dejagnu, invoked via dg-final.
  228. # Call pass if variable has the desired value, otherwise fail.
  229. #
  230. # Argument 0 handles expected failures and the like
  231. proc asan-gtest { args } {
  232. global tool
  233. global asan_last_gtest_test_list
  234. global asan_last_gtest_expect_death_list
  235. if { ![info exists asan_last_gtest_test_list] } { return }
  236. if { [llength $asan_last_gtest_test_list] == 0 } { return }
  237. if { ![isnative] || [is_remote target] } { return }
  238. set gtest_test_list $asan_last_gtest_test_list
  239. unset asan_last_gtest_test_list
  240. if { [llength $args] >= 1 } {
  241. switch [dg-process-target [lindex $args 0]] {
  242. "S" { }
  243. "N" { return }
  244. "F" { setup_xfail "*-*-*" }
  245. "P" { }
  246. }
  247. }
  248. # This assumes that we are three frames down from dg-test, and that
  249. # it still stores the filename of the testcase in a local variable "name".
  250. # A cleaner solution would require a new DejaGnu release.
  251. upvar 2 name testcase
  252. upvar 2 prog prog
  253. set output_file "[file rootname [file tail $prog]].exe"
  254. foreach gtest $gtest_test_list {
  255. set testname "$testcase $gtest"
  256. set status -1
  257. setenv DEJAGNU_GTEST_ARG "$gtest"
  258. set result [${tool}_load ./$output_file $gtest]
  259. unsetenv DEJAGNU_GTEST_ARG
  260. set status [lindex $result 0]
  261. set output [lindex $result 1]
  262. if { "$status" == "pass" } {
  263. pass "$testname execution test"
  264. if { [info exists asan_last_gtest_expect_death_list] } {
  265. set gtest_expect_death_list $asan_last_gtest_expect_death_list
  266. foreach gtest_death $gtest_expect_death_list {
  267. set id [lindex $gtest_death 0]
  268. set testname "$testcase $gtest [lindex $gtest_death 1]"
  269. set regexpr [lindex $gtest_death 2]
  270. set status -1
  271. setenv DEJAGNU_GTEST_ARG "$gtest:$id"
  272. set result [${tool}_load ./$output_file "$gtest:$id"]
  273. unsetenv DEJAGNU_GTEST_ARG
  274. set status [lindex $result 0]
  275. set output [lindex $result 1]
  276. if { "$status" == "fail" } {
  277. pass "$testname execution test"
  278. if { ![regexp $regexpr ${output}] } {
  279. fail "$testname output pattern test"
  280. send_log "Output should match: $regexpr\n"
  281. } else {
  282. pass "$testname output pattern test"
  283. }
  284. } elseif { "$status" == "pass" } {
  285. fail "$testname execution test"
  286. } else {
  287. $status "$testname execution test"
  288. }
  289. }
  290. }
  291. } else {
  292. $status "$testname execution test"
  293. }
  294. unset asan_last_gtest_expect_death_list
  295. }
  296. return
  297. }