/tests/libxul.rs

https://github.com/gimli-rs/cpp_demangle · Rust · 206 lines · 166 code · 22 blank · 18 comment · 18 complexity · 79989d828b32bcaa584a40655f946ea4 MD5 · raw file

  1. extern crate cpp_demangle;
  2. extern crate diff;
  3. use std::fs;
  4. use std::io::{BufRead, BufReader, BufWriter, Write};
  5. use std::process;
  6. const NUMBER_OF_LIBXUL_SYMBOLS: usize = 274_346;
  7. // These counts should only go up!
  8. const NUMBER_OF_LIBXUL_SYMBOLS_THAT_PARSE: usize = 274_346;
  9. const NUMBER_OF_LIBXUL_SYMBOLS_THAT_DEMANGLE: usize = 274_346;
  10. fn get_cppfilt() -> &'static str {
  11. if cfg!(not(target_os = "macos")) {
  12. return "c++filt";
  13. }
  14. // Prefer `gc++filt` (from the homebrew binutils package) since it is built
  15. // with a newer libiberty than the system `c++filt` (and maybe the system
  16. // `c++filt` will be backed by the LLVM demangler one day).
  17. match process::Command::new("gc++filt").spawn() {
  18. Ok(mut child) => {
  19. child.kill().expect("should kill child");
  20. child.wait().expect("should wait on child");
  21. "gc++filt"
  22. }
  23. Err(_) => "c++filt",
  24. }
  25. }
  26. #[test]
  27. fn libxul_symbols_demangle() {
  28. let mut total = 0;
  29. let mut num_parsed = 0;
  30. let mut num_demangled = 0;
  31. let mut num_match_libiberty = 0;
  32. let libxul_txt_file = fs::File::open(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/libxul.txt"))
  33. .expect("should open libxul.txt");
  34. let mut libxul_txt_file = BufReader::new(libxul_txt_file);
  35. let log_file = fs::File::create(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/libxul.log"))
  36. .expect("should create log file");
  37. let mut log_file = BufWriter::new(log_file);
  38. let mut line = Vec::new();
  39. let mut demangled = Vec::new();
  40. let mut libiberty_sym = Vec::new();
  41. let which_cppfilt = get_cppfilt();
  42. let mut cppfilt = process::Command::new(which_cppfilt)
  43. .stdin(process::Stdio::piped())
  44. .stdout(process::Stdio::piped())
  45. .spawn()
  46. .expect("should spawn c++filt");
  47. let mut cppfilt_stdin = cppfilt.stdin.take().unwrap();
  48. let mut cppfilt_stdout = BufReader::new(cppfilt.stdout.take().unwrap());
  49. while {
  50. line.clear();
  51. let bytes_read = libxul_txt_file
  52. .read_until(b'\n', &mut line)
  53. .expect("should read line");
  54. bytes_read > 0
  55. } {
  56. total += 1;
  57. // Grab the next symbol from libxul.txt.
  58. let line_len = line.len();
  59. assert!(line_len > 2);
  60. let mut line = if line[line_len - 1] == b'\n' {
  61. &line[..line_len - 1]
  62. } else {
  63. &line[..]
  64. };
  65. // libxul.txt was generated on macOS, and so it has the double
  66. // underscore ("__Z"). Remove the first underscore if needed.
  67. if line[0] == b'_' && (cfg!(not(target_os = "macos")) || which_cppfilt == "gc++filt") {
  68. line = &line[1..];
  69. }
  70. // Parse the symbol.
  71. if let Ok(sym) = cpp_demangle::BorrowedSymbol::new(line) {
  72. num_parsed += 1;
  73. // Demangle the symbol.
  74. demangled.clear();
  75. if write!(&mut demangled, "{}", sym).is_ok() {
  76. num_demangled += 1;
  77. // Finally, we are going to have `c++filt` demangle the
  78. // symbol. Write the line into `c++filt`.
  79. cppfilt_stdin
  80. .write_all(&line)
  81. .expect("should write line contents into c++filt");
  82. cppfilt_stdin
  83. .write_all(b"\n")
  84. .expect("should write newline into c++filt");
  85. cppfilt_stdin.flush().expect("should flush c++filt stdin");
  86. // Read its demangled version back out.
  87. libiberty_sym.clear();
  88. cppfilt_stdout
  89. .read_until(b'\n', &mut libiberty_sym)
  90. .expect("should read line from c++filt");
  91. // Drop the "\n".
  92. libiberty_sym.pop();
  93. // Compare our demangling to libiberty's.
  94. if libiberty_sym == demangled {
  95. num_match_libiberty += 1;
  96. } else {
  97. writeln!(
  98. &mut log_file,
  99. "failed to match libiberty's demangling: {}",
  100. String::from_utf8_lossy(line)
  101. )
  102. .unwrap();
  103. writeln!(
  104. &mut log_file,
  105. " ...we demangled to: {}",
  106. String::from_utf8_lossy(&demangled)
  107. )
  108. .unwrap();
  109. writeln!(
  110. &mut log_file,
  111. " ...libiberty demangled to: {}",
  112. String::from_utf8_lossy(&libiberty_sym)
  113. )
  114. .unwrap();
  115. }
  116. } else {
  117. writeln!(
  118. &mut log_file,
  119. "failed to demangle libxul symbol: {}",
  120. String::from_utf8_lossy(line)
  121. )
  122. .unwrap();
  123. }
  124. } else {
  125. writeln!(
  126. &mut log_file,
  127. "failed to parse libxul symbol: {}",
  128. String::from_utf8_lossy(line)
  129. )
  130. .unwrap();
  131. }
  132. }
  133. writeln!(
  134. &mut log_file,
  135. "================================================================"
  136. )
  137. .unwrap();
  138. writeln!(
  139. &mut log_file,
  140. "Total number of libxul symbols: {}",
  141. total
  142. )
  143. .unwrap();
  144. writeln!(
  145. &mut log_file,
  146. "Number of libxul symbols parsed: {} ({:.2}%)",
  147. num_parsed,
  148. num_parsed as f64 / total as f64 * 100.0
  149. )
  150. .unwrap();
  151. writeln!(
  152. &mut log_file,
  153. "Number of libxul symbols demangled: {} ({:.2}%)",
  154. num_demangled,
  155. num_demangled as f64 / total as f64 * 100.0
  156. )
  157. .unwrap();
  158. writeln!(
  159. &mut log_file,
  160. "Number of libxul symbols demangled same as libiberty: {} ({:.2}%)",
  161. num_match_libiberty,
  162. num_match_libiberty as f64 / num_demangled as f64 * 100.0
  163. )
  164. .unwrap();
  165. assert!(num_match_libiberty <= num_demangled);
  166. assert!(num_demangled <= num_parsed);
  167. assert!(num_parsed <= total);
  168. assert_eq!(
  169. NUMBER_OF_LIBXUL_SYMBOLS, total,
  170. "should have expected number of total symbols"
  171. );
  172. assert_eq!(
  173. NUMBER_OF_LIBXUL_SYMBOLS_THAT_PARSE, num_parsed,
  174. "should have expected number of symbols that we can parse"
  175. );
  176. assert_eq!(
  177. NUMBER_OF_LIBXUL_SYMBOLS_THAT_DEMANGLE, num_demangled,
  178. "should have expected number of symbols that we can demangle"
  179. );
  180. // Note: we don't assert any number of symbols that demangle the same as
  181. // libiberty since this depends on the libiberty version that the `c++filt`
  182. // on this system is using, which varies between CI and dev machines and
  183. // etc...
  184. }