PageRenderTime 79ms CodeModel.GetById 37ms RepoModel.GetById 0ms app.codeStats 0ms

/src/compiletest/runtest.rs

http://github.com/eholk/rust
Rust | 1792 lines | 1611 code | 128 blank | 53 comment | 88 complexity | 6fb3ad5f3ec9617106629b4917f6805e MD5 | raw file
Possible License(s): AGPL-1.0, BSD-2-Clause, 0BSD, Apache-2.0, MIT, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
  2. // file at the top-level directory of this distribution and at
  3. // http://rust-lang.org/COPYRIGHT.
  4. //
  5. // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
  6. // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
  7. // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
  8. // option. This file may not be copied, modified, or distributed
  9. // except according to those terms.
  10. use self::TargetLocation::*;
  11. use common::Config;
  12. use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
  13. use common::{Codegen, DebugInfoLldb, DebugInfoGdb};
  14. use errors;
  15. use header::TestProps;
  16. use header;
  17. use procsrv;
  18. use util::logv;
  19. use std::env;
  20. use std::fmt;
  21. use std::fs::{self, File};
  22. use std::io::BufReader;
  23. use std::io::prelude::*;
  24. use std::iter::repeat;
  25. use std::net::TcpStream;
  26. use std::path::{Path, PathBuf};
  27. use std::process::{Command, Output, ExitStatus};
  28. use std::str;
  29. use std::time::Duration;
  30. use test::MetricMap;
  31. pub fn run(config: Config, testfile: &Path) {
  32. match &*config.target {
  33. "arm-linux-androideabi" | "aarch64-linux-android" => {
  34. if !config.adb_device_status {
  35. panic!("android device not available");
  36. }
  37. }
  38. _=> { }
  39. }
  40. let mut _mm = MetricMap::new();
  41. run_metrics(config, testfile, &mut _mm);
  42. }
  43. pub fn run_metrics(config: Config, testfile: &Path, mm: &mut MetricMap) {
  44. if config.verbose {
  45. // We're going to be dumping a lot of info. Start on a new line.
  46. print!("\n\n");
  47. }
  48. debug!("running {:?}", testfile.display());
  49. let props = header::load_props(&testfile);
  50. debug!("loaded props");
  51. match config.mode {
  52. CompileFail => run_cfail_test(&config, &props, &testfile),
  53. ParseFail => run_cfail_test(&config, &props, &testfile),
  54. RunFail => run_rfail_test(&config, &props, &testfile),
  55. RunPass => run_rpass_test(&config, &props, &testfile),
  56. RunPassValgrind => run_valgrind_test(&config, &props, &testfile),
  57. Pretty => run_pretty_test(&config, &props, &testfile),
  58. DebugInfoGdb => run_debuginfo_gdb_test(&config, &props, &testfile),
  59. DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testfile),
  60. Codegen => run_codegen_test(&config, &props, &testfile, mm),
  61. }
  62. }
  63. fn get_output(props: &TestProps, proc_res: &ProcRes) -> String {
  64. if props.check_stdout {
  65. format!("{}{}", proc_res.stdout, proc_res.stderr)
  66. } else {
  67. proc_res.stderr.clone()
  68. }
  69. }
  70. fn run_cfail_test(config: &Config, props: &TestProps, testfile: &Path) {
  71. let proc_res = compile_test(config, props, testfile);
  72. if proc_res.status.success() {
  73. fatal_proc_rec(&format!("{} test compiled successfully!", config.mode)[..],
  74. &proc_res);
  75. }
  76. check_correct_failure_status(&proc_res);
  77. if proc_res.status.success() {
  78. fatal("process did not return an error status");
  79. }
  80. let output_to_check = get_output(props, &proc_res);
  81. let expected_errors = errors::load_errors(testfile);
  82. if !expected_errors.is_empty() {
  83. if !props.error_patterns.is_empty() {
  84. fatal("both error pattern and expected errors specified");
  85. }
  86. check_expected_errors(expected_errors, testfile, &proc_res);
  87. } else {
  88. check_error_patterns(props, testfile, &output_to_check, &proc_res);
  89. }
  90. check_no_compiler_crash(&proc_res);
  91. check_forbid_output(props, &output_to_check, &proc_res);
  92. }
  93. fn run_rfail_test(config: &Config, props: &TestProps, testfile: &Path) {
  94. let proc_res = if !config.jit {
  95. let proc_res = compile_test(config, props, testfile);
  96. if !proc_res.status.success() {
  97. fatal_proc_rec("compilation failed!", &proc_res);
  98. }
  99. exec_compiled_test(config, props, testfile)
  100. } else {
  101. jit_test(config, props, testfile)
  102. };
  103. // The value our Makefile configures valgrind to return on failure
  104. const VALGRIND_ERR: i32 = 100;
  105. if proc_res.status.code() == Some(VALGRIND_ERR) {
  106. fatal_proc_rec("run-fail test isn't valgrind-clean!", &proc_res);
  107. }
  108. let output_to_check = get_output(props, &proc_res);
  109. check_correct_failure_status(&proc_res);
  110. check_error_patterns(props, testfile, &output_to_check, &proc_res);
  111. }
  112. fn check_correct_failure_status(proc_res: &ProcRes) {
  113. // The value the rust runtime returns on failure
  114. const RUST_ERR: i32 = 101;
  115. if proc_res.status.code() != Some(RUST_ERR) {
  116. fatal_proc_rec(
  117. &format!("failure produced the wrong error: {}",
  118. proc_res.status),
  119. proc_res);
  120. }
  121. }
  122. fn run_rpass_test(config: &Config, props: &TestProps, testfile: &Path) {
  123. if !config.jit {
  124. let mut proc_res = compile_test(config, props, testfile);
  125. if !proc_res.status.success() {
  126. fatal_proc_rec("compilation failed!", &proc_res);
  127. }
  128. proc_res = exec_compiled_test(config, props, testfile);
  129. if !proc_res.status.success() {
  130. fatal_proc_rec("test run failed!", &proc_res);
  131. }
  132. } else {
  133. let proc_res = jit_test(config, props, testfile);
  134. if !proc_res.status.success() {
  135. fatal_proc_rec("jit failed!", &proc_res);
  136. }
  137. }
  138. }
  139. fn run_valgrind_test(config: &Config, props: &TestProps, testfile: &Path) {
  140. if config.valgrind_path.is_none() {
  141. assert!(!config.force_valgrind);
  142. return run_rpass_test(config, props, testfile);
  143. }
  144. let mut proc_res = compile_test(config, props, testfile);
  145. if !proc_res.status.success() {
  146. fatal_proc_rec("compilation failed!", &proc_res);
  147. }
  148. let mut new_config = config.clone();
  149. new_config.runtool = new_config.valgrind_path.clone();
  150. proc_res = exec_compiled_test(&new_config, props, testfile);
  151. if !proc_res.status.success() {
  152. fatal_proc_rec("test run failed!", &proc_res);
  153. }
  154. }
  155. fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
  156. if props.pp_exact.is_some() {
  157. logv(config, "testing for exact pretty-printing".to_string());
  158. } else {
  159. logv(config, "testing for converging pretty-printing".to_string());
  160. }
  161. let rounds =
  162. match props.pp_exact { Some(_) => 1, None => 2 };
  163. let mut src = String::new();
  164. File::open(testfile).unwrap().read_to_string(&mut src).unwrap();
  165. let mut srcs = vec!(src);
  166. let mut round = 0;
  167. while round < rounds {
  168. logv(config, format!("pretty-printing round {}", round));
  169. let proc_res = print_source(config,
  170. props,
  171. testfile,
  172. srcs[round].to_string(),
  173. &props.pretty_mode);
  174. if !proc_res.status.success() {
  175. fatal_proc_rec(&format!("pretty-printing failed in round {}", round),
  176. &proc_res);
  177. }
  178. let ProcRes{ stdout, .. } = proc_res;
  179. srcs.push(stdout);
  180. round += 1;
  181. }
  182. let mut expected = match props.pp_exact {
  183. Some(ref file) => {
  184. let filepath = testfile.parent().unwrap().join(file);
  185. let mut s = String::new();
  186. File::open(&filepath).unwrap().read_to_string(&mut s).unwrap();
  187. s
  188. }
  189. None => { srcs[srcs.len() - 2].clone() }
  190. };
  191. let mut actual = srcs[srcs.len() - 1].clone();
  192. if props.pp_exact.is_some() {
  193. // Now we have to care about line endings
  194. let cr = "\r".to_string();
  195. actual = actual.replace(&cr, "").to_string();
  196. expected = expected.replace(&cr, "").to_string();
  197. }
  198. compare_source(&expected, &actual);
  199. // If we're only making sure that the output matches then just stop here
  200. if props.pretty_compare_only { return; }
  201. // Finally, let's make sure it actually appears to remain valid code
  202. let proc_res = typecheck_source(config, props, testfile, actual);
  203. if !proc_res.status.success() {
  204. fatal_proc_rec("pretty-printed source does not typecheck", &proc_res);
  205. }
  206. if props.no_pretty_expanded { return }
  207. // additionally, run `--pretty expanded` and try to build it.
  208. let proc_res = print_source(config, props, testfile, srcs[round].clone(), "expanded");
  209. if !proc_res.status.success() {
  210. fatal_proc_rec("pretty-printing (expanded) failed", &proc_res);
  211. }
  212. let ProcRes{ stdout: expanded_src, .. } = proc_res;
  213. let proc_res = typecheck_source(config, props, testfile, expanded_src);
  214. if !proc_res.status.success() {
  215. fatal_proc_rec("pretty-printed source (expanded) does not typecheck",
  216. &proc_res);
  217. }
  218. return;
  219. fn print_source(config: &Config,
  220. props: &TestProps,
  221. testfile: &Path,
  222. src: String,
  223. pretty_type: &str) -> ProcRes {
  224. let aux_dir = aux_output_dir_name(config, testfile);
  225. compose_and_run(config,
  226. testfile,
  227. make_pp_args(config,
  228. props,
  229. testfile,
  230. pretty_type.to_string()),
  231. props.exec_env.clone(),
  232. &config.compile_lib_path,
  233. Some(aux_dir.to_str().unwrap()),
  234. Some(src))
  235. }
  236. fn make_pp_args(config: &Config,
  237. props: &TestProps,
  238. testfile: &Path,
  239. pretty_type: String) -> ProcArgs {
  240. let aux_dir = aux_output_dir_name(config, testfile);
  241. // FIXME (#9639): This needs to handle non-utf8 paths
  242. let mut args = vec!("-".to_string(),
  243. "-Zunstable-options".to_string(),
  244. "--pretty".to_string(),
  245. pretty_type,
  246. format!("--target={}", config.target),
  247. "-L".to_string(),
  248. aux_dir.to_str().unwrap().to_string());
  249. args.extend(split_maybe_args(&config.target_rustcflags).into_iter());
  250. args.extend(split_maybe_args(&props.compile_flags).into_iter());
  251. return ProcArgs {
  252. prog: config.rustc_path.to_str().unwrap().to_string(),
  253. args: args,
  254. };
  255. }
  256. fn compare_source(expected: &str, actual: &str) {
  257. if expected != actual {
  258. error("pretty-printed source does not match expected source");
  259. println!("\n\
  260. expected:\n\
  261. ------------------------------------------\n\
  262. {}\n\
  263. ------------------------------------------\n\
  264. actual:\n\
  265. ------------------------------------------\n\
  266. {}\n\
  267. ------------------------------------------\n\
  268. \n",
  269. expected, actual);
  270. panic!();
  271. }
  272. }
  273. fn typecheck_source(config: &Config, props: &TestProps,
  274. testfile: &Path, src: String) -> ProcRes {
  275. let args = make_typecheck_args(config, props, testfile);
  276. compose_and_run_compiler(config, props, testfile, args, Some(src))
  277. }
  278. fn make_typecheck_args(config: &Config, props: &TestProps, testfile: &Path) -> ProcArgs {
  279. let aux_dir = aux_output_dir_name(config, testfile);
  280. let target = if props.force_host {
  281. &*config.host
  282. } else {
  283. &*config.target
  284. };
  285. // FIXME (#9639): This needs to handle non-utf8 paths
  286. let mut args = vec!("-".to_string(),
  287. "-Zno-trans".to_string(),
  288. "--crate-type=lib".to_string(),
  289. format!("--target={}", target),
  290. "-L".to_string(),
  291. config.build_base.to_str().unwrap().to_string(),
  292. "-L".to_string(),
  293. aux_dir.to_str().unwrap().to_string());
  294. args.extend(split_maybe_args(&config.target_rustcflags).into_iter());
  295. args.extend(split_maybe_args(&props.compile_flags).into_iter());
  296. // FIXME (#9639): This needs to handle non-utf8 paths
  297. return ProcArgs {
  298. prog: config.rustc_path.to_str().unwrap().to_string(),
  299. args: args,
  300. };
  301. }
  302. }
  303. fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
  304. let mut config = Config {
  305. target_rustcflags: cleanup_debug_info_options(&config.target_rustcflags),
  306. host_rustcflags: cleanup_debug_info_options(&config.host_rustcflags),
  307. .. config.clone()
  308. };
  309. let config = &mut config;
  310. let DebuggerCommands {
  311. commands,
  312. check_lines,
  313. breakpoint_lines
  314. } = parse_debugger_commands(testfile, "gdb");
  315. let mut cmds = commands.connect("\n");
  316. // compile test file (it should have 'compile-flags:-g' in the header)
  317. let compiler_run_result = compile_test(config, props, testfile);
  318. if !compiler_run_result.status.success() {
  319. fatal_proc_rec("compilation failed!", &compiler_run_result);
  320. }
  321. let exe_file = make_exe_name(config, testfile);
  322. let debugger_run_result;
  323. match &*config.target {
  324. "arm-linux-androideabi" | "aarch64-linux-android" => {
  325. cmds = cmds.replace("run", "continue");
  326. // write debugger script
  327. let mut script_str = String::with_capacity(2048);
  328. script_str.push_str("set charset UTF-8\n");
  329. script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap()));
  330. script_str.push_str("target remote :5039\n");
  331. script_str.push_str(&format!("set solib-search-path \
  332. ./{}/stage2/lib/rustlib/{}/lib/\n",
  333. config.host, config.target));
  334. for line in breakpoint_lines.iter() {
  335. script_str.push_str(&format!("break {:?}:{}\n",
  336. testfile.file_name().unwrap()
  337. .to_string_lossy(),
  338. *line)[..]);
  339. }
  340. script_str.push_str(&cmds);
  341. script_str.push_str("\nquit\n");
  342. debug!("script_str = {}", script_str);
  343. dump_output_file(config,
  344. testfile,
  345. &script_str,
  346. "debugger.script");
  347. procsrv::run("",
  348. &config.adb_path,
  349. None,
  350. &[
  351. "push".to_string(),
  352. exe_file.to_str().unwrap().to_string(),
  353. config.adb_test_dir.clone()
  354. ],
  355. vec!(("".to_string(), "".to_string())),
  356. Some("".to_string()))
  357. .expect(&format!("failed to exec `{:?}`", config.adb_path));
  358. procsrv::run("",
  359. &config.adb_path,
  360. None,
  361. &[
  362. "forward".to_string(),
  363. "tcp:5039".to_string(),
  364. "tcp:5039".to_string()
  365. ],
  366. vec!(("".to_string(), "".to_string())),
  367. Some("".to_string()))
  368. .expect(&format!("failed to exec `{:?}`", config.adb_path));
  369. let adb_arg = format!("export LD_LIBRARY_PATH={}; \
  370. gdbserver{} :5039 {}/{}",
  371. config.adb_test_dir.clone(),
  372. if config.target.contains("aarch64")
  373. {"64"} else {""},
  374. config.adb_test_dir.clone(),
  375. exe_file.file_name().unwrap().to_str()
  376. .unwrap());
  377. let mut process = procsrv::run_background("",
  378. &config.adb_path
  379. ,
  380. None,
  381. &[
  382. "shell".to_string(),
  383. adb_arg.clone()
  384. ],
  385. vec!(("".to_string(),
  386. "".to_string())),
  387. Some("".to_string()))
  388. .expect(&format!("failed to exec `{:?}`", config.adb_path));
  389. loop {
  390. //waiting 1 second for gdbserver start
  391. #[allow(deprecated)]
  392. fn sleep() {
  393. ::std::old_io::timer::sleep(Duration::milliseconds(1000));
  394. }
  395. sleep();
  396. if TcpStream::connect("127.0.0.1:5039").is_ok() {
  397. break
  398. }
  399. }
  400. let tool_path = match config.android_cross_path.to_str() {
  401. Some(x) => x.to_string(),
  402. None => fatal("cannot find android cross path")
  403. };
  404. let debugger_script = make_out_name(config, testfile, "debugger.script");
  405. // FIXME (#9639): This needs to handle non-utf8 paths
  406. let debugger_opts =
  407. vec!("-quiet".to_string(),
  408. "-batch".to_string(),
  409. "-nx".to_string(),
  410. format!("-command={}", debugger_script.to_str().unwrap()));
  411. let mut gdb_path = tool_path;
  412. gdb_path.push_str(&format!("/bin/{}-gdb", config.target));
  413. let procsrv::Result {
  414. out,
  415. err,
  416. status
  417. } = procsrv::run("",
  418. &gdb_path,
  419. None,
  420. &debugger_opts,
  421. vec!(("".to_string(), "".to_string())),
  422. None)
  423. .expect(&format!("failed to exec `{:?}`", gdb_path));
  424. let cmdline = {
  425. let cmdline = make_cmdline("",
  426. &format!("{}-gdb", config.target),
  427. &debugger_opts);
  428. logv(config, format!("executing {}", cmdline));
  429. cmdline
  430. };
  431. debugger_run_result = ProcRes {
  432. status: Status::Normal(status),
  433. stdout: out,
  434. stderr: err,
  435. cmdline: cmdline
  436. };
  437. if process.kill().is_err() {
  438. println!("Adb process is already finished.");
  439. }
  440. }
  441. _=> {
  442. let rust_src_root = find_rust_src_root(config)
  443. .expect("Could not find Rust source root");
  444. let rust_pp_module_rel_path = Path::new("./src/etc");
  445. let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
  446. .to_str()
  447. .unwrap()
  448. .to_string();
  449. // write debugger script
  450. let mut script_str = String::with_capacity(2048);
  451. script_str.push_str("set charset UTF-8\n");
  452. script_str.push_str("show version\n");
  453. match config.gdb_version {
  454. Some(ref version) => {
  455. println!("NOTE: compiletest thinks it is using GDB version {}",
  456. version);
  457. if header::gdb_version_to_int(version) >
  458. header::gdb_version_to_int("7.4") {
  459. // Add the directory containing the pretty printers to
  460. // GDB's script auto loading safe path
  461. script_str.push_str(
  462. &format!("add-auto-load-safe-path {}\n",
  463. rust_pp_module_abs_path.replace(r"\", r"\\"))
  464. );
  465. }
  466. }
  467. _ => {
  468. println!("NOTE: compiletest does not know which version of \
  469. GDB it is using");
  470. }
  471. }
  472. // The following line actually doesn't have to do anything with
  473. // pretty printing, it just tells GDB to print values on one line:
  474. script_str.push_str("set print pretty off\n");
  475. // Add the pretty printer directory to GDB's source-file search path
  476. script_str.push_str(&format!("directory {}\n",
  477. rust_pp_module_abs_path));
  478. // Load the target executable
  479. script_str.push_str(&format!("file {}\n",
  480. exe_file.to_str().unwrap()
  481. .replace(r"\", r"\\")));
  482. // Add line breakpoints
  483. for line in &breakpoint_lines {
  484. script_str.push_str(&format!("break '{}':{}\n",
  485. testfile.file_name().unwrap()
  486. .to_string_lossy(),
  487. *line));
  488. }
  489. script_str.push_str(&cmds);
  490. script_str.push_str("\nquit\n");
  491. debug!("script_str = {}", script_str);
  492. dump_output_file(config,
  493. testfile,
  494. &script_str,
  495. "debugger.script");
  496. // run debugger script with gdb
  497. fn debugger() -> &'static str {
  498. if cfg!(windows) {"gdb.exe"} else {"gdb"}
  499. }
  500. let debugger_script = make_out_name(config, testfile, "debugger.script");
  501. // FIXME (#9639): This needs to handle non-utf8 paths
  502. let debugger_opts =
  503. vec!("-quiet".to_string(),
  504. "-batch".to_string(),
  505. "-nx".to_string(),
  506. format!("-command={}", debugger_script.to_str().unwrap()));
  507. let proc_args = ProcArgs {
  508. prog: debugger().to_string(),
  509. args: debugger_opts,
  510. };
  511. let environment = vec![("PYTHONPATH".to_string(), rust_pp_module_abs_path)];
  512. debugger_run_result = compose_and_run(config,
  513. testfile,
  514. proc_args,
  515. environment,
  516. &config.run_lib_path,
  517. None,
  518. None);
  519. }
  520. }
  521. if !debugger_run_result.status.success() {
  522. fatal("gdb failed to execute");
  523. }
  524. check_debugger_output(&debugger_run_result, &check_lines);
  525. }
  526. fn find_rust_src_root(config: &Config) -> Option<PathBuf> {
  527. let mut path = config.src_base.clone();
  528. let path_postfix = Path::new("src/etc/lldb_batchmode.py");
  529. while path.pop() {
  530. if path.join(&path_postfix).is_file() {
  531. return Some(path);
  532. }
  533. }
  534. return None;
  535. }
  536. fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) {
  537. if config.lldb_python_dir.is_none() {
  538. fatal("Can't run LLDB test because LLDB's python path is not set.");
  539. }
  540. let mut config = Config {
  541. target_rustcflags: cleanup_debug_info_options(&config.target_rustcflags),
  542. host_rustcflags: cleanup_debug_info_options(&config.host_rustcflags),
  543. .. config.clone()
  544. };
  545. let config = &mut config;
  546. // compile test file (it should have 'compile-flags:-g' in the header)
  547. let compile_result = compile_test(config, props, testfile);
  548. if !compile_result.status.success() {
  549. fatal_proc_rec("compilation failed!", &compile_result);
  550. }
  551. let exe_file = make_exe_name(config, testfile);
  552. match config.lldb_version {
  553. Some(ref version) => {
  554. println!("NOTE: compiletest thinks it is using LLDB version {}",
  555. version);
  556. }
  557. _ => {
  558. println!("NOTE: compiletest does not know which version of \
  559. LLDB it is using");
  560. }
  561. }
  562. // Parse debugger commands etc from test files
  563. let DebuggerCommands {
  564. commands,
  565. check_lines,
  566. breakpoint_lines,
  567. ..
  568. } = parse_debugger_commands(testfile, "lldb");
  569. // Write debugger script:
  570. // We don't want to hang when calling `quit` while the process is still running
  571. let mut script_str = String::from_str("settings set auto-confirm true\n");
  572. // Make LLDB emit its version, so we have it documented in the test output
  573. script_str.push_str("version\n");
  574. // Switch LLDB into "Rust mode"
  575. let rust_src_root = find_rust_src_root(config)
  576. .expect("Could not find Rust source root");
  577. let rust_pp_module_rel_path = Path::new("./src/etc/lldb_rust_formatters.py");
  578. let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
  579. .to_str()
  580. .unwrap()
  581. .to_string();
  582. script_str.push_str(&format!("command script import {}\n",
  583. &rust_pp_module_abs_path[..])[..]);
  584. script_str.push_str("type summary add --no-value ");
  585. script_str.push_str("--python-function lldb_rust_formatters.print_val ");
  586. script_str.push_str("-x \".*\" --category Rust\n");
  587. script_str.push_str("type category enable Rust\n");
  588. // Set breakpoints on every line that contains the string "#break"
  589. for line in &breakpoint_lines {
  590. script_str.push_str(&format!("breakpoint set --line {}\n", line));
  591. }
  592. // Append the other commands
  593. for line in &commands {
  594. script_str.push_str(line);
  595. script_str.push_str("\n");
  596. }
  597. // Finally, quit the debugger
  598. script_str.push_str("\nquit\n");
  599. // Write the script into a file
  600. debug!("script_str = {}", script_str);
  601. dump_output_file(config,
  602. testfile,
  603. &script_str,
  604. "debugger.script");
  605. let debugger_script = make_out_name(config, testfile, "debugger.script");
  606. // Let LLDB execute the script via lldb_batchmode.py
  607. let debugger_run_result = run_lldb(config,
  608. &exe_file,
  609. &debugger_script,
  610. &rust_src_root);
  611. if !debugger_run_result.status.success() {
  612. fatal_proc_rec("Error while running LLDB", &debugger_run_result);
  613. }
  614. check_debugger_output(&debugger_run_result, &check_lines);
  615. fn run_lldb(config: &Config,
  616. test_executable: &Path,
  617. debugger_script: &Path,
  618. rust_src_root: &Path)
  619. -> ProcRes {
  620. // Prepare the lldb_batchmode which executes the debugger script
  621. let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
  622. let mut cmd = Command::new("python");
  623. cmd.arg(&lldb_script_path)
  624. .arg(test_executable)
  625. .arg(debugger_script)
  626. .env("PYTHONPATH", config.lldb_python_dir.as_ref().unwrap());
  627. let (status, out, err) = match cmd.output() {
  628. Ok(Output { status, stdout, stderr }) => {
  629. (status,
  630. String::from_utf8(stdout).unwrap(),
  631. String::from_utf8(stderr).unwrap())
  632. },
  633. Err(e) => {
  634. fatal(&format!("Failed to setup Python process for \
  635. LLDB script: {}", e))
  636. }
  637. };
  638. dump_output(config, test_executable, &out, &err);
  639. return ProcRes {
  640. status: Status::Normal(status),
  641. stdout: out,
  642. stderr: err,
  643. cmdline: format!("{:?}", cmd)
  644. };
  645. }
  646. }
  647. struct DebuggerCommands {
  648. commands: Vec<String>,
  649. check_lines: Vec<String>,
  650. breakpoint_lines: Vec<uint>,
  651. }
  652. fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str)
  653. -> DebuggerCommands {
  654. let command_directive = format!("{}-command", debugger_prefix);
  655. let check_directive = format!("{}-check", debugger_prefix);
  656. let mut breakpoint_lines = vec!();
  657. let mut commands = vec!();
  658. let mut check_lines = vec!();
  659. let mut counter = 1;
  660. let reader = BufReader::new(File::open(file_path).unwrap());
  661. for line in reader.lines() {
  662. match line {
  663. Ok(line) => {
  664. if line.contains("#break") {
  665. breakpoint_lines.push(counter);
  666. }
  667. header::parse_name_value_directive(
  668. &line,
  669. &command_directive).map(|cmd| {
  670. commands.push(cmd)
  671. });
  672. header::parse_name_value_directive(
  673. &line,
  674. &check_directive).map(|cmd| {
  675. check_lines.push(cmd)
  676. });
  677. }
  678. Err(e) => {
  679. fatal(&format!("Error while parsing debugger commands: {}", e))
  680. }
  681. }
  682. counter += 1;
  683. }
  684. DebuggerCommands {
  685. commands: commands,
  686. check_lines: check_lines,
  687. breakpoint_lines: breakpoint_lines,
  688. }
  689. }
  690. fn cleanup_debug_info_options(options: &Option<String>) -> Option<String> {
  691. if options.is_none() {
  692. return None;
  693. }
  694. // Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS.
  695. let options_to_remove = [
  696. "-O".to_string(),
  697. "-g".to_string(),
  698. "--debuginfo".to_string()
  699. ];
  700. let new_options =
  701. split_maybe_args(options).into_iter()
  702. .filter(|x| !options_to_remove.contains(x))
  703. .collect::<Vec<String>>()
  704. .connect(" ");
  705. Some(new_options)
  706. }
  707. fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String]) {
  708. let num_check_lines = check_lines.len();
  709. if num_check_lines > 0 {
  710. // Allow check lines to leave parts unspecified (e.g., uninitialized
  711. // bits in the wrong case of an enum) with the notation "[...]".
  712. let check_fragments: Vec<Vec<String>> =
  713. check_lines.iter().map(|s| {
  714. s
  715. .trim()
  716. .split("[...]")
  717. .map(|x| x.to_string())
  718. .collect()
  719. }).collect();
  720. // check if each line in props.check_lines appears in the
  721. // output (in order)
  722. let mut i = 0;
  723. for line in debugger_run_result.stdout.lines() {
  724. let mut rest = line.trim();
  725. let mut first = true;
  726. let mut failed = false;
  727. for frag in &check_fragments[i] {
  728. let found = if first {
  729. if rest.starts_with(frag) {
  730. Some(0)
  731. } else {
  732. None
  733. }
  734. } else {
  735. rest.find(frag)
  736. };
  737. match found {
  738. None => {
  739. failed = true;
  740. break;
  741. }
  742. Some(i) => {
  743. rest = &rest[(i + frag.len())..];
  744. }
  745. }
  746. first = false;
  747. }
  748. if !failed && rest.len() == 0 {
  749. i += 1;
  750. }
  751. if i == num_check_lines {
  752. // all lines checked
  753. break;
  754. }
  755. }
  756. if i != num_check_lines {
  757. fatal_proc_rec(&format!("line not found in debugger output: {}",
  758. check_lines.get(i).unwrap()),
  759. debugger_run_result);
  760. }
  761. }
  762. }
  763. fn check_error_patterns(props: &TestProps,
  764. testfile: &Path,
  765. output_to_check: &str,
  766. proc_res: &ProcRes) {
  767. if props.error_patterns.is_empty() {
  768. fatal(&format!("no error pattern specified in {:?}", testfile.display()));
  769. }
  770. let mut next_err_idx = 0;
  771. let mut next_err_pat = &props.error_patterns[next_err_idx];
  772. let mut done = false;
  773. for line in output_to_check.lines() {
  774. if line.contains(next_err_pat) {
  775. debug!("found error pattern {}", next_err_pat);
  776. next_err_idx += 1;
  777. if next_err_idx == props.error_patterns.len() {
  778. debug!("found all error patterns");
  779. done = true;
  780. break;
  781. }
  782. next_err_pat = &props.error_patterns[next_err_idx];
  783. }
  784. }
  785. if done { return; }
  786. let missing_patterns = &props.error_patterns[next_err_idx..];
  787. if missing_patterns.len() == 1 {
  788. fatal_proc_rec(&format!("error pattern '{}' not found!", missing_patterns[0]),
  789. proc_res);
  790. } else {
  791. for pattern in missing_patterns {
  792. error(&format!("error pattern '{}' not found!", *pattern));
  793. }
  794. fatal_proc_rec("multiple error patterns not found", proc_res);
  795. }
  796. }
  797. fn check_no_compiler_crash(proc_res: &ProcRes) {
  798. for line in proc_res.stderr.lines() {
  799. if line.starts_with("error: internal compiler error:") {
  800. fatal_proc_rec("compiler encountered internal error",
  801. proc_res);
  802. }
  803. }
  804. }
  805. fn check_forbid_output(props: &TestProps,
  806. output_to_check: &str,
  807. proc_res: &ProcRes) {
  808. for pat in &props.forbid_output {
  809. if output_to_check.contains(pat) {
  810. fatal_proc_rec("forbidden pattern found in compiler output", proc_res);
  811. }
  812. }
  813. }
  814. fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
  815. testfile: &Path,
  816. proc_res: &ProcRes) {
  817. // true if we found the error in question
  818. let mut found_flags: Vec<_> = repeat(false).take(expected_errors.len()).collect();
  819. if proc_res.status.success() {
  820. fatal("process did not return an error status");
  821. }
  822. let prefixes = expected_errors.iter().map(|ee| {
  823. format!("{}:{}:", testfile.display(), ee.line)
  824. }).collect::<Vec<String>>();
  825. fn prefix_matches(line: &str, prefix: &str) -> bool {
  826. use std::ascii::AsciiExt;
  827. // On windows just translate all '\' path separators to '/'
  828. let line = line.replace(r"\", "/");
  829. if cfg!(windows) {
  830. line.to_ascii_lowercase().starts_with(&prefix.to_ascii_lowercase())
  831. } else {
  832. line.starts_with(prefix)
  833. }
  834. }
  835. // A multi-line error will have followup lines which will always
  836. // start with one of these strings.
  837. fn continuation( line: &str) -> bool {
  838. line.starts_with(" expected") ||
  839. line.starts_with(" found") ||
  840. // 1234
  841. // Should have 4 spaces: see issue 18946
  842. line.starts_with("(")
  843. }
  844. // Scan and extract our error/warning messages,
  845. // which look like:
  846. // filename:line1:col1: line2:col2: *error:* msg
  847. // filename:line1:col1: line2:col2: *warning:* msg
  848. // where line1:col1: is the starting point, line2:col2:
  849. // is the ending point, and * represents ANSI color codes.
  850. for line in proc_res.stderr.lines() {
  851. let mut was_expected = false;
  852. for (i, ee) in expected_errors.iter().enumerate() {
  853. if !found_flags[i] {
  854. debug!("prefix={} ee.kind={} ee.msg={} line={}",
  855. prefixes[i],
  856. ee.kind,
  857. ee.msg,
  858. line);
  859. if (prefix_matches(line, &prefixes[i]) || continuation(line)) &&
  860. line.contains(&ee.kind) &&
  861. line.contains(&ee.msg) {
  862. found_flags[i] = true;
  863. was_expected = true;
  864. break;
  865. }
  866. }
  867. }
  868. // ignore this msg which gets printed at the end
  869. if line.contains("aborting due to") {
  870. was_expected = true;
  871. }
  872. if !was_expected && is_compiler_error_or_warning(line) {
  873. fatal_proc_rec(&format!("unexpected compiler error or warning: '{}'",
  874. line),
  875. proc_res);
  876. }
  877. }
  878. for (i, &flag) in found_flags.iter().enumerate() {
  879. if !flag {
  880. let ee = &expected_errors[i];
  881. fatal_proc_rec(&format!("expected {} on line {} not found: {}",
  882. ee.kind, ee.line, ee.msg),
  883. proc_res);
  884. }
  885. }
  886. }
  887. fn is_compiler_error_or_warning(line: &str) -> bool {
  888. let mut i = 0;
  889. return
  890. scan_until_char(line, ':', &mut i) &&
  891. scan_char(line, ':', &mut i) &&
  892. scan_integer(line, &mut i) &&
  893. scan_char(line, ':', &mut i) &&
  894. scan_integer(line, &mut i) &&
  895. scan_char(line, ':', &mut i) &&
  896. scan_char(line, ' ', &mut i) &&
  897. scan_integer(line, &mut i) &&
  898. scan_char(line, ':', &mut i) &&
  899. scan_integer(line, &mut i) &&
  900. scan_char(line, ' ', &mut i) &&
  901. (scan_string(line, "error", &mut i) ||
  902. scan_string(line, "warning", &mut i));
  903. }
  904. fn scan_until_char(haystack: &str, needle: char, idx: &mut uint) -> bool {
  905. if *idx >= haystack.len() {
  906. return false;
  907. }
  908. let opt = haystack[(*idx)..].find(needle);
  909. if opt.is_none() {
  910. return false;
  911. }
  912. *idx = opt.unwrap();
  913. return true;
  914. }
  915. fn scan_char(haystack: &str, needle: char, idx: &mut uint) -> bool {
  916. if *idx >= haystack.len() {
  917. return false;
  918. }
  919. let range = haystack.char_range_at(*idx);
  920. if range.ch != needle {
  921. return false;
  922. }
  923. *idx = range.next;
  924. return true;
  925. }
  926. fn scan_integer(haystack: &str, idx: &mut uint) -> bool {
  927. let mut i = *idx;
  928. while i < haystack.len() {
  929. let range = haystack.char_range_at(i);
  930. if range.ch < '0' || '9' < range.ch {
  931. break;
  932. }
  933. i = range.next;
  934. }
  935. if i == *idx {
  936. return false;
  937. }
  938. *idx = i;
  939. return true;
  940. }
  941. fn scan_string(haystack: &str, needle: &str, idx: &mut uint) -> bool {
  942. let mut haystack_i = *idx;
  943. let mut needle_i = 0;
  944. while needle_i < needle.len() {
  945. if haystack_i >= haystack.len() {
  946. return false;
  947. }
  948. let range = haystack.char_range_at(haystack_i);
  949. haystack_i = range.next;
  950. if !scan_char(needle, range.ch, &mut needle_i) {
  951. return false;
  952. }
  953. }
  954. *idx = haystack_i;
  955. return true;
  956. }
  957. struct ProcArgs {
  958. prog: String,
  959. args: Vec<String>,
  960. }
  961. struct ProcRes {
  962. status: Status,
  963. stdout: String,
  964. stderr: String,
  965. cmdline: String,
  966. }
  967. enum Status {
  968. Parsed(i32),
  969. Normal(ExitStatus),
  970. }
  971. impl Status {
  972. fn code(&self) -> Option<i32> {
  973. match *self {
  974. Status::Parsed(i) => Some(i),
  975. Status::Normal(ref e) => e.code(),
  976. }
  977. }
  978. fn success(&self) -> bool {
  979. match *self {
  980. Status::Parsed(i) => i == 0,
  981. Status::Normal(ref e) => e.success(),
  982. }
  983. }
  984. }
  985. impl fmt::Display for Status {
  986. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  987. match *self {
  988. Status::Parsed(i) => write!(f, "exit code: {}", i),
  989. Status::Normal(ref e) => e.fmt(f),
  990. }
  991. }
  992. }
  993. fn compile_test(config: &Config, props: &TestProps,
  994. testfile: &Path) -> ProcRes {
  995. compile_test_(config, props, testfile, &[])
  996. }
  997. fn jit_test(config: &Config, props: &TestProps, testfile: &Path) -> ProcRes {
  998. compile_test_(config, props, testfile, &["--jit".to_string()])
  999. }
  1000. fn compile_test_(config: &Config, props: &TestProps,
  1001. testfile: &Path, extra_args: &[String]) -> ProcRes {
  1002. let aux_dir = aux_output_dir_name(config, testfile);
  1003. // FIXME (#9639): This needs to handle non-utf8 paths
  1004. let mut link_args = vec!("-L".to_string(),
  1005. aux_dir.to_str().unwrap().to_string());
  1006. link_args.extend(extra_args.iter().cloned());
  1007. let args = make_compile_args(config,
  1008. props,
  1009. link_args,
  1010. |a, b| TargetLocation::ThisFile(make_exe_name(a, b)), testfile);
  1011. compose_and_run_compiler(config, props, testfile, args, None)
  1012. }
  1013. fn exec_compiled_test(config: &Config, props: &TestProps,
  1014. testfile: &Path) -> ProcRes {
  1015. let env = props.exec_env.clone();
  1016. match &*config.target {
  1017. "arm-linux-androideabi" | "aarch64-linux-android" => {
  1018. _arm_exec_compiled_test(config, props, testfile, env)
  1019. }
  1020. _=> {
  1021. let aux_dir = aux_output_dir_name(config, testfile);
  1022. compose_and_run(config,
  1023. testfile,
  1024. make_run_args(config, props, testfile),
  1025. env,
  1026. &config.run_lib_path,
  1027. Some(aux_dir.to_str().unwrap()),
  1028. None)
  1029. }
  1030. }
  1031. }
  1032. fn compose_and_run_compiler(
  1033. config: &Config,
  1034. props: &TestProps,
  1035. testfile: &Path,
  1036. args: ProcArgs,
  1037. input: Option<String>) -> ProcRes {
  1038. if !props.aux_builds.is_empty() {
  1039. ensure_dir(&aux_output_dir_name(config, testfile));
  1040. }
  1041. let aux_dir = aux_output_dir_name(config, testfile);
  1042. // FIXME (#9639): This needs to handle non-utf8 paths
  1043. let extra_link_args = vec!("-L".to_string(), aux_dir.to_str().unwrap().to_string());
  1044. for rel_ab in &props.aux_builds {
  1045. let abs_ab = config.aux_base.join(rel_ab);
  1046. let aux_props = header::load_props(&abs_ab);
  1047. let mut crate_type = if aux_props.no_prefer_dynamic {
  1048. Vec::new()
  1049. } else {
  1050. vec!("--crate-type=dylib".to_string())
  1051. };
  1052. crate_type.extend(extra_link_args.clone().into_iter());
  1053. let aux_args =
  1054. make_compile_args(config,
  1055. &aux_props,
  1056. crate_type,
  1057. |a,b| {
  1058. let f = make_lib_name(a, b, testfile);
  1059. let parent = f.parent().unwrap();
  1060. TargetLocation::ThisDirectory(parent.to_path_buf())
  1061. },
  1062. &abs_ab);
  1063. let auxres = compose_and_run(config,
  1064. &abs_ab,
  1065. aux_args,
  1066. Vec::new(),
  1067. &config.compile_lib_path,
  1068. Some(aux_dir.to_str().unwrap()),
  1069. None);
  1070. if !auxres.status.success() {
  1071. fatal_proc_rec(
  1072. &format!("auxiliary build of {:?} failed to compile: ",
  1073. abs_ab.display()),
  1074. &auxres);
  1075. }
  1076. match &*config.target {
  1077. "arm-linux-androideabi" | "aarch64-linux-android" => {
  1078. _arm_push_aux_shared_library(config, testfile);
  1079. }
  1080. _ => {}
  1081. }
  1082. }
  1083. compose_and_run(config,
  1084. testfile,
  1085. args,
  1086. Vec::new(),
  1087. &config.compile_lib_path,
  1088. Some(aux_dir.to_str().unwrap()),
  1089. input)
  1090. }
  1091. fn ensure_dir(path: &Path) {
  1092. if path.is_dir() { return; }
  1093. fs::create_dir(path).unwrap();
  1094. }
  1095. fn compose_and_run(config: &Config, testfile: &Path,
  1096. ProcArgs{ args, prog }: ProcArgs,
  1097. procenv: Vec<(String, String)> ,
  1098. lib_path: &str,
  1099. aux_path: Option<&str>,
  1100. input: Option<String>) -> ProcRes {
  1101. return program_output(config, testfile, lib_path,
  1102. prog, aux_path, args, procenv, input);
  1103. }
  1104. enum TargetLocation {
  1105. ThisFile(PathBuf),
  1106. ThisDirectory(PathBuf),
  1107. }
  1108. fn make_compile_args<F>(config: &Config,
  1109. props: &TestProps,
  1110. extras: Vec<String> ,
  1111. xform: F,
  1112. testfile: &Path)
  1113. -> ProcArgs where
  1114. F: FnOnce(&Config, &Path) -> TargetLocation,
  1115. {
  1116. let xform_file = xform(config, testfile);
  1117. let target = if props.force_host {
  1118. &*config.host
  1119. } else {
  1120. &*config.target
  1121. };
  1122. // FIXME (#9639): This needs to handle non-utf8 paths
  1123. let mut args = vec!(testfile.to_str().unwrap().to_string(),
  1124. "-L".to_string(),
  1125. config.build_base.to_str().unwrap().to_string(),
  1126. format!("--target={}", target));
  1127. args.push_all(&extras);
  1128. if !props.no_prefer_dynamic {
  1129. args.push("-C".to_string());
  1130. args.push("prefer-dynamic".to_string());
  1131. }
  1132. let path = match xform_file {
  1133. TargetLocation::ThisFile(path) => {
  1134. args.push("-o".to_string());
  1135. path
  1136. }
  1137. TargetLocation::ThisDirectory(path) => {
  1138. args.push("--out-dir".to_string());
  1139. path
  1140. }
  1141. };
  1142. args.push(path.to_str().unwrap().to_string());
  1143. if props.force_host {
  1144. args.extend(split_maybe_args(&config.host_rustcflags).into_iter());
  1145. } else {
  1146. args.extend(split_maybe_args(&config.target_rustcflags).into_iter());
  1147. }
  1148. args.extend(split_maybe_args(&props.compile_flags).into_iter());
  1149. return ProcArgs {
  1150. prog: config.rustc_path.to_str().unwrap().to_string(),
  1151. args: args,
  1152. };
  1153. }
  1154. fn make_lib_name(config: &Config, auxfile: &Path, testfile: &Path) -> PathBuf {
  1155. // what we return here is not particularly important, as it
  1156. // happens; rustc ignores everything except for the directory.
  1157. let auxname = output_testname(auxfile);
  1158. aux_output_dir_name(config, testfile).join(&auxname)
  1159. }
  1160. fn make_exe_name(config: &Config, testfile: &Path) -> PathBuf {
  1161. let mut f = output_base_name(config, testfile);
  1162. if !env::consts::EXE_SUFFIX.is_empty() {
  1163. let mut fname = f.file_name().unwrap().to_os_string();
  1164. fname.push(env::consts::EXE_SUFFIX);
  1165. f.set_file_name(&fname);
  1166. }
  1167. f
  1168. }
  1169. fn make_run_args(config: &Config, props: &TestProps, testfile: &Path) ->
  1170. ProcArgs {
  1171. // If we've got another tool to run under (valgrind),
  1172. // then split apart its command
  1173. let mut args = split_maybe_args(&config.runtool);
  1174. let exe_file = make_exe_name(config, testfile);
  1175. // FIXME (#9639): This needs to handle non-utf8 paths
  1176. args.push(exe_file.to_str().unwrap().to_string());
  1177. // Add the arguments in the run_flags directive
  1178. args.extend(split_maybe_args(&props.run_flags).into_iter());
  1179. let prog = args.remove(0);
  1180. return ProcArgs {
  1181. prog: prog,
  1182. args: args,
  1183. };
  1184. }
  1185. fn split_maybe_args(argstr: &Option<String>) -> Vec<String> {
  1186. match *argstr {
  1187. Some(ref s) => {
  1188. s
  1189. .split(' ')
  1190. .filter_map(|s| {
  1191. if s.chars().all(|c| c.is_whitespace()) {
  1192. None
  1193. } else {
  1194. Some(s.to_string())
  1195. }
  1196. }).collect()
  1197. }
  1198. None => Vec::new()
  1199. }
  1200. }
  1201. fn program_output(config: &Config, testfile: &Path, lib_path: &str, prog: String,
  1202. aux_path: Option<&str>, args: Vec<String>,
  1203. env: Vec<(String, String)>,
  1204. input: Option<String>) -> ProcRes {
  1205. let cmdline =
  1206. {
  1207. let cmdline = make_cmdline(lib_path,
  1208. &prog,
  1209. &args);
  1210. logv(config, format!("executing {}", cmdline));
  1211. cmdline
  1212. };
  1213. let procsrv::Result {
  1214. out,
  1215. err,
  1216. status
  1217. } = procsrv::run(lib_path,
  1218. &prog,
  1219. aux_path,
  1220. &args,
  1221. env,
  1222. input).expect(&format!("failed to exec `{}`", prog));
  1223. dump_output(config, testfile, &out, &err);
  1224. return ProcRes {
  1225. status: Status::Normal(status),
  1226. stdout: out,
  1227. stderr: err,
  1228. cmdline: cmdline,
  1229. };
  1230. }
  1231. fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String {
  1232. use util;
  1233. // Linux and mac don't require adjusting the library search path
  1234. if cfg!(unix) {
  1235. format!("{} {}", prog, args.connect(" "))
  1236. } else {
  1237. // Build the LD_LIBRARY_PATH variable as it would be seen on the command line
  1238. // for diagnostic purposes
  1239. fn lib_path_cmd_prefix(path: &str) -> String {
  1240. format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path))
  1241. }
  1242. format!("{} {} {}", lib_path_cmd_prefix(libpath), prog, args.connect(" "))
  1243. }
  1244. }
  1245. fn dump_output(config: &Config, testfile: &Path, out: &str, err: &str) {
  1246. dump_output_file(config, testfile, out, "out");
  1247. dump_output_file(config, testfile, err, "err");
  1248. maybe_dump_to_stdout(config

Large files files are truncated, but you can click here to view the full file