1use core::convert::TryFrom;
2use core::{char, fmt, iter, mem, str};
3
4#[allow(unused_macros)]
5macro_rules! write {
6 ($($ignored:tt)*) => {
7 compile_error!(
8 "use `self.print(value)` or `fmt::Trait::fmt(&value, self.out)`, \
9 instead of `write!(self.out, \"{...}\", value)`"
10 )
11 };
12}
13
14// Maximum recursion depth when parsing symbols before we just bail out saying
15// "this symbol is invalid"
16const MAX_DEPTH: u32 = 500;
17
18/// Representation of a demangled symbol name.
19pub struct Demangle<'a> {
20 inner: &'a str,
21}
22
23#[derive(PartialEq, Eq, Debug)]
24pub enum ParseError {
25 /// Symbol doesn't match the expected `v0` grammar.
26 Invalid,
27
28 /// Parsing the symbol crossed the recursion limit (see `MAX_DEPTH`).
29 RecursedTooDeep,
30}
31
32/// De-mangles a Rust symbol into a more readable version
33///
34/// This function will take a **mangled** symbol and return a value. When printed,
35/// the de-mangled version will be written. If the symbol does not look like
36/// a mangled symbol, the original value will be written instead.
37pub fn demangle(s: &str) -> Result<(Demangle, &str), ParseError> {
38 // First validate the symbol. If it doesn't look like anything we're
39 // expecting, we just print it literally. Note that we must handle non-Rust
40 // symbols because we could have any function in the backtrace.
41 let inner;
42 if s.len() > 2 && s.starts_with("_R") {
43 inner = &s[2..];
44 } else if s.len() > 1 && s.starts_with('R') {
45 // On Windows, dbghelp strips leading underscores, so we accept "R..."
46 // form too.
47 inner = &s[1..];
48 } else if s.len() > 3 && s.starts_with("__R") {
49 // On OSX, symbols are prefixed with an extra _
50 inner = &s[3..];
51 } else {
52 return Err(ParseError::Invalid);
53 }
54
55 // Paths always start with uppercase characters.
56 match inner.as_bytes()[0] {
57 b'A'..=b'Z' => {}
58 _ => return Err(ParseError::Invalid),
59 }
60
61 // only work with ascii text
62 if inner.bytes().any(|c| c & 0x80 != 0) {
63 return Err(ParseError::Invalid);
64 }
65
66 // Verify that the symbol is indeed a valid path.
67 let try_parse_path = |parser| {
68 let mut dummy_printer = Printer {
69 parser: Ok(parser),
70 out: None,
71 bound_lifetime_depth: 0,
72 };
73 dummy_printer
74 .print_path(false)
75 .expect("`fmt::Error`s should be impossible without a `fmt::Formatter`");
76 dummy_printer.parser
77 };
78 let mut parser = Parser {
79 sym: inner,
80 next: 0,
81 depth: 0,
82 };
83 parser = try_parse_path(parser)?;
84
85 // Instantiating crate (paths always start with uppercase characters).
86 if let Some(&(b'A'..=b'Z')) = parser.sym.as_bytes().get(parser.next) {
87 parser = try_parse_path(parser)?;
88 }
89
90 Ok((Demangle { inner }, &parser.sym[parser.next..]))
91}
92
93impl<'s> fmt::Display for Demangle<'s> {
94 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95 let mut printer: Printer<'_, '_, '_> = Printer {
96 parser: Ok(Parser {
97 sym: self.inner,
98 next: 0,
99 depth: 0,
100 }),
101 out: Some(f),
102 bound_lifetime_depth: 0,
103 };
104 printer.print_path(in_value:true)
105 }
106}
107
108struct Ident<'s> {
109 /// ASCII part of the identifier.
110 ascii: &'s str,
111 /// Punycode insertion codes for Unicode codepoints, if any.
112 punycode: &'s str,
113}
114
115const SMALL_PUNYCODE_LEN: usize = 128;
116
117impl<'s> Ident<'s> {
118 /// Attempt to decode punycode on the stack (allocation-free),
119 /// and pass the char slice to the closure, if successful.
120 /// This supports up to `SMALL_PUNYCODE_LEN` characters.
121 fn try_small_punycode_decode<F: FnOnce(&[char]) -> R, R>(&self, f: F) -> Option<R> {
122 let mut out = ['\0'; SMALL_PUNYCODE_LEN];
123 let mut out_len = 0;
124 let r = self.punycode_decode(|i, c| {
125 // Check there's space left for another character.
126 out.get(out_len).ok_or(())?;
127
128 // Move the characters after the insert position.
129 let mut j = out_len;
130 out_len += 1;
131
132 while j > i {
133 out[j] = out[j - 1];
134 j -= 1;
135 }
136
137 // Insert the new character.
138 out[i] = c;
139
140 Ok(())
141 });
142 if r.is_ok() {
143 Some(f(&out[..out_len]))
144 } else {
145 None
146 }
147 }
148
149 /// Decode punycode as insertion positions and characters
150 /// and pass them to the closure, which can return `Err(())`
151 /// to stop the decoding process.
152 fn punycode_decode<F: FnMut(usize, char) -> Result<(), ()>>(
153 &self,
154 mut insert: F,
155 ) -> Result<(), ()> {
156 let mut punycode_bytes = self.punycode.bytes().peekable();
157 if punycode_bytes.peek().is_none() {
158 return Err(());
159 }
160
161 let mut len = 0;
162
163 // Populate initial output from ASCII fragment.
164 for c in self.ascii.chars() {
165 insert(len, c)?;
166 len += 1;
167 }
168
169 // Punycode parameters and initial state.
170 let base = 36;
171 let t_min = 1;
172 let t_max = 26;
173 let skew = 38;
174 let mut damp = 700;
175 let mut bias = 72;
176 let mut i: usize = 0;
177 let mut n: usize = 0x80;
178
179 loop {
180 // Read one delta value.
181 let mut delta: usize = 0;
182 let mut w = 1;
183 let mut k: usize = 0;
184 loop {
185 use core::cmp::{max, min};
186
187 k += base;
188 let t = min(max(k.saturating_sub(bias), t_min), t_max);
189
190 let d = match punycode_bytes.next() {
191 Some(d @ b'a'..=b'z') => d - b'a',
192 Some(d @ b'0'..=b'9') => 26 + (d - b'0'),
193 _ => return Err(()),
194 };
195 let d = d as usize;
196 delta = delta.checked_add(d.checked_mul(w).ok_or(())?).ok_or(())?;
197 if d < t {
198 break;
199 }
200 w = w.checked_mul(base - t).ok_or(())?;
201 }
202
203 // Compute the new insert position and character.
204 len += 1;
205 i = i.checked_add(delta).ok_or(())?;
206 n = n.checked_add(i / len).ok_or(())?;
207 i %= len;
208
209 let n_u32 = n as u32;
210 let c = if n_u32 as usize == n {
211 char::from_u32(n_u32).ok_or(())?
212 } else {
213 return Err(());
214 };
215
216 // Insert the new character and increment the insert position.
217 insert(i, c)?;
218 i += 1;
219
220 // If there are no more deltas, decoding is complete.
221 if punycode_bytes.peek().is_none() {
222 return Ok(());
223 }
224
225 // Perform bias adaptation.
226 delta /= damp;
227 damp = 2;
228
229 delta += delta / len;
230 let mut k = 0;
231 while delta > ((base - t_min) * t_max) / 2 {
232 delta /= base - t_min;
233 k += base;
234 }
235 bias = k + ((base - t_min + 1) * delta) / (delta + skew);
236 }
237 }
238}
239
240impl<'s> fmt::Display for Ident<'s> {
241 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
242 self.try_small_punycode_decode(|chars| {
243 for &c in chars {
244 c.fmt(f)?;
245 }
246 Ok(())
247 })
248 .unwrap_or_else(|| {
249 if !self.punycode.is_empty() {
250 f.write_str("punycode{")?;
251
252 // Reconstruct a standard Punycode encoding,
253 // by using `-` as the separator.
254 if !self.ascii.is_empty() {
255 f.write_str(self.ascii)?;
256 f.write_str("-")?;
257 }
258 f.write_str(self.punycode)?;
259
260 f.write_str("}")
261 } else {
262 f.write_str(self.ascii)
263 }
264 })
265 }
266}
267
268/// Sequence of lowercase hexadecimal nibbles (`0-9a-f`), used by leaf consts.
269struct HexNibbles<'s> {
270 nibbles: &'s str,
271}
272
273impl<'s> HexNibbles<'s> {
274 /// Decode an integer value (with the "most significant nibble" first),
275 /// returning `None` if it can't fit in an `u64`.
276 // FIXME(eddyb) should this "just" use `u128` instead?
277 fn try_parse_uint(&self) -> Option<u64> {
278 let nibbles = self.nibbles.trim_start_matches("0");
279
280 if nibbles.len() > 16 {
281 return None;
282 }
283
284 let mut v = 0;
285 for nibble in nibbles.chars() {
286 v = (v << 4) | (nibble.to_digit(16).unwrap() as u64);
287 }
288 Some(v)
289 }
290
291 /// Decode a UTF-8 byte sequence (with each byte using a pair of nibbles)
292 /// into individual `char`s, returning `None` for invalid UTF-8.
293 fn try_parse_str_chars(&self) -> Option<impl Iterator<Item = char> + 's> {
294 if self.nibbles.len() % 2 != 0 {
295 return None;
296 }
297
298 // FIXME(eddyb) use `array_chunks` instead, when that becomes stable.
299 let mut bytes = self
300 .nibbles
301 .as_bytes()
302 .chunks_exact(2)
303 .map(|slice| match slice {
304 [a, b] => [a, b],
305 _ => unreachable!(),
306 })
307 .map(|[&hi, &lo]| {
308 let half = |nibble: u8| (nibble as char).to_digit(16).unwrap() as u8;
309 (half(hi) << 4) | half(lo)
310 });
311
312 let chars = iter::from_fn(move || {
313 // As long as there are any bytes left, there's at least one more
314 // UTF-8-encoded `char` to decode (or the possibility of error).
315 bytes.next().map(|first_byte| -> Result<char, ()> {
316 // FIXME(eddyb) this `enum` and `fn` should be somewhere in `core`.
317 enum Utf8FirstByteError {
318 ContinuationByte,
319 TooLong,
320 }
321 fn utf8_len_from_first_byte(byte: u8) -> Result<usize, Utf8FirstByteError> {
322 match byte {
323 0x00..=0x7f => Ok(1),
324 0x80..=0xbf => Err(Utf8FirstByteError::ContinuationByte),
325 0xc0..=0xdf => Ok(2),
326 0xe0..=0xef => Ok(3),
327 0xf0..=0xf7 => Ok(4),
328 0xf8..=0xff => Err(Utf8FirstByteError::TooLong),
329 }
330 }
331
332 // Collect the appropriate amount of bytes (up to 4), according
333 // to the UTF-8 length implied by the first byte.
334 let utf8_len = utf8_len_from_first_byte(first_byte).map_err(|_| ())?;
335 let utf8 = &mut [first_byte, 0, 0, 0][..utf8_len];
336 for i in 1..utf8_len {
337 utf8[i] = bytes.next().ok_or(())?;
338 }
339
340 // Fully validate the UTF-8 sequence.
341 let s = str::from_utf8(utf8).map_err(|_| ())?;
342
343 // Since we included exactly one UTF-8 sequence, and validation
344 // succeeded, `str::chars` should return exactly one `char`.
345 let mut chars = s.chars();
346 match (chars.next(), chars.next()) {
347 (Some(c), None) => Ok(c),
348 _ => unreachable!(
349 "str::from_utf8({:?}) = {:?} was expected to have 1 char, \
350 but {} chars were found",
351 utf8,
352 s,
353 s.chars().count()
354 ),
355 }
356 })
357 });
358
359 // HACK(eddyb) doing a separate validation iteration like this might be
360 // wasteful, but it's easier to avoid starting to print a string literal
361 // in the first place, than to abort it mid-string.
362 if chars.clone().any(|r| r.is_err()) {
363 None
364 } else {
365 Some(chars.map(Result::unwrap))
366 }
367 }
368}
369
370fn basic_type(tag: u8) -> Option<&'static str> {
371 Some(match tag {
372 b'b' => "bool",
373 b'c' => "char",
374 b'e' => "str",
375 b'u' => "()",
376 b'a' => "i8",
377 b's' => "i16",
378 b'l' => "i32",
379 b'x' => "i64",
380 b'n' => "i128",
381 b'i' => "isize",
382 b'h' => "u8",
383 b't' => "u16",
384 b'm' => "u32",
385 b'y' => "u64",
386 b'o' => "u128",
387 b'j' => "usize",
388 b'f' => "f32",
389 b'd' => "f64",
390 b'z' => "!",
391 b'p' => "_",
392 b'v' => "...",
393
394 _ => return None,
395 })
396}
397
398struct Parser<'s> {
399 sym: &'s str,
400 next: usize,
401 depth: u32,
402}
403
404impl<'s> Parser<'s> {
405 fn push_depth(&mut self) -> Result<(), ParseError> {
406 self.depth += 1;
407 if self.depth > MAX_DEPTH {
408 Err(ParseError::RecursedTooDeep)
409 } else {
410 Ok(())
411 }
412 }
413
414 fn pop_depth(&mut self) {
415 self.depth -= 1;
416 }
417
418 fn peek(&self) -> Option<u8> {
419 self.sym.as_bytes().get(self.next).cloned()
420 }
421
422 fn eat(&mut self, b: u8) -> bool {
423 if self.peek() == Some(b) {
424 self.next += 1;
425 true
426 } else {
427 false
428 }
429 }
430
431 fn next(&mut self) -> Result<u8, ParseError> {
432 let b = self.peek().ok_or(ParseError::Invalid)?;
433 self.next += 1;
434 Ok(b)
435 }
436
437 fn hex_nibbles(&mut self) -> Result<HexNibbles<'s>, ParseError> {
438 let start = self.next;
439 loop {
440 match self.next()? {
441 b'0'..=b'9' | b'a'..=b'f' => {}
442 b'_' => break,
443 _ => return Err(ParseError::Invalid),
444 }
445 }
446 Ok(HexNibbles {
447 nibbles: &self.sym[start..self.next - 1],
448 })
449 }
450
451 fn digit_10(&mut self) -> Result<u8, ParseError> {
452 let d = match self.peek() {
453 Some(d @ b'0'..=b'9') => d - b'0',
454 _ => return Err(ParseError::Invalid),
455 };
456 self.next += 1;
457 Ok(d)
458 }
459
460 fn digit_62(&mut self) -> Result<u8, ParseError> {
461 let d = match self.peek() {
462 Some(d @ b'0'..=b'9') => d - b'0',
463 Some(d @ b'a'..=b'z') => 10 + (d - b'a'),
464 Some(d @ b'A'..=b'Z') => 10 + 26 + (d - b'A'),
465 _ => return Err(ParseError::Invalid),
466 };
467 self.next += 1;
468 Ok(d)
469 }
470
471 fn integer_62(&mut self) -> Result<u64, ParseError> {
472 if self.eat(b'_') {
473 return Ok(0);
474 }
475
476 let mut x: u64 = 0;
477 while !self.eat(b'_') {
478 let d = self.digit_62()? as u64;
479 x = x.checked_mul(62).ok_or(ParseError::Invalid)?;
480 x = x.checked_add(d).ok_or(ParseError::Invalid)?;
481 }
482 x.checked_add(1).ok_or(ParseError::Invalid)
483 }
484
485 fn opt_integer_62(&mut self, tag: u8) -> Result<u64, ParseError> {
486 if !self.eat(tag) {
487 return Ok(0);
488 }
489 self.integer_62()?.checked_add(1).ok_or(ParseError::Invalid)
490 }
491
492 fn disambiguator(&mut self) -> Result<u64, ParseError> {
493 self.opt_integer_62(b's')
494 }
495
496 fn namespace(&mut self) -> Result<Option<char>, ParseError> {
497 match self.next()? {
498 // Special namespaces, like closures and shims.
499 ns @ b'A'..=b'Z' => Ok(Some(ns as char)),
500
501 // Implementation-specific/unspecified namespaces.
502 b'a'..=b'z' => Ok(None),
503
504 _ => Err(ParseError::Invalid),
505 }
506 }
507
508 fn backref(&mut self) -> Result<Parser<'s>, ParseError> {
509 let s_start = self.next - 1;
510 let i = self.integer_62()?;
511 if i >= s_start as u64 {
512 return Err(ParseError::Invalid);
513 }
514 let mut new_parser = Parser {
515 sym: self.sym,
516 next: i as usize,
517 depth: self.depth,
518 };
519 new_parser.push_depth()?;
520 Ok(new_parser)
521 }
522
523 fn ident(&mut self) -> Result<Ident<'s>, ParseError> {
524 let is_punycode = self.eat(b'u');
525 let mut len = self.digit_10()? as usize;
526 if len != 0 {
527 while let Ok(d) = self.digit_10() {
528 len = len.checked_mul(10).ok_or(ParseError::Invalid)?;
529 len = len.checked_add(d as usize).ok_or(ParseError::Invalid)?;
530 }
531 }
532
533 // Skip past the optional `_` separator.
534 self.eat(b'_');
535
536 let start = self.next;
537 self.next = self.next.checked_add(len).ok_or(ParseError::Invalid)?;
538 if self.next > self.sym.len() {
539 return Err(ParseError::Invalid);
540 }
541
542 let ident = &self.sym[start..self.next];
543
544 if is_punycode {
545 let ident = match ident.bytes().rposition(|b| b == b'_') {
546 Some(i) => Ident {
547 ascii: &ident[..i],
548 punycode: &ident[i + 1..],
549 },
550 None => Ident {
551 ascii: "",
552 punycode: ident,
553 },
554 };
555 if ident.punycode.is_empty() {
556 return Err(ParseError::Invalid);
557 }
558 Ok(ident)
559 } else {
560 Ok(Ident {
561 ascii: ident,
562 punycode: "",
563 })
564 }
565 }
566}
567
568struct Printer<'a, 'b: 'a, 's> {
569 /// The input parser to demangle from, or `Err` if any (parse) error was
570 /// encountered (in order to disallow further likely-incorrect demangling).
571 ///
572 /// See also the documentation on the `invalid!` and `parse!` macros below.
573 parser: Result<Parser<'s>, ParseError>,
574
575 /// The output formatter to demangle to, or `None` while skipping printing.
576 out: Option<&'a mut fmt::Formatter<'b>>,
577
578 /// Cumulative number of lifetimes bound by `for<...>` binders ('G'),
579 /// anywhere "around" the current entity (e.g. type) being demangled.
580 /// This value is not tracked while skipping printing, as it'd be unused.
581 ///
582 /// See also the documentation on the `Printer::in_binder` method.
583 bound_lifetime_depth: u32,
584}
585
586impl ParseError {
587 /// Snippet to print when the error is initially encountered.
588 fn message(&self) -> &str {
589 match self {
590 ParseError::Invalid => "{invalid syntax}",
591 ParseError::RecursedTooDeep => "{recursion limit reached}",
592 }
593 }
594}
595
596/// Mark the parser as errored (with `ParseError::Invalid`), print the
597/// appropriate message (see `ParseError::message`) and return early.
598macro_rules! invalid {
599 ($printer:ident) => {{
600 let err = ParseError::Invalid;
601 $printer.print(err.message())?;
602 $printer.parser = Err(err);
603 return Ok(());
604 }};
605}
606
607/// Call a parser method (if the parser hasn't errored yet),
608/// and mark the parser as errored if it returns `Err`.
609///
610/// If the parser errored, before or now, this returns early,
611/// from the current function, after printing either:
612/// * for a new error, the appropriate message (see `ParseError::message`)
613/// * for an earlier error, only `?` - this allows callers to keep printing
614/// the approximate syntax of the path/type/const, despite having errors,
615/// e.g. `Vec<[(A, ?); ?]>` instead of `Vec<[(A, ?`
616macro_rules! parse {
617 ($printer:ident, $method:ident $(($($arg:expr),*))*) => {
618 match $printer.parser {
619 Ok(ref mut parser) => match parser.$method($($($arg),*)*) {
620 Ok(x) => x,
621 Err(err) => {
622 $printer.print(err.message())?;
623 $printer.parser = Err(err);
624 return Ok(());
625 }
626 }
627 Err(_) => return $printer.print("?"),
628 }
629 };
630}
631
632impl<'a, 'b, 's> Printer<'a, 'b, 's> {
633 /// Eat the given character from the parser,
634 /// returning `false` if the parser errored.
635 fn eat(&mut self, b: u8) -> bool {
636 self.parser.as_mut().map(|p| p.eat(b)) == Ok(true)
637 }
638
639 /// Skip printing (i.e. `self.out` will be `None`) for the duration of the
640 /// given closure. This should not change parsing behavior, only disable the
641 /// output, but there may be optimizations (such as not traversing backrefs).
642 fn skipping_printing<F>(&mut self, f: F)
643 where
644 F: FnOnce(&mut Self) -> fmt::Result,
645 {
646 let orig_out = self.out.take();
647 f(self).expect("`fmt::Error`s should be impossible without a `fmt::Formatter`");
648 self.out = orig_out;
649 }
650
651 /// Print the target of a backref, using the given closure.
652 /// When printing is being skipped, the backref will only be parsed,
653 /// ignoring the backref's target completely.
654 fn print_backref<F>(&mut self, f: F) -> fmt::Result
655 where
656 F: FnOnce(&mut Self) -> fmt::Result,
657 {
658 let backref_parser = parse!(self, backref);
659
660 if self.out.is_none() {
661 return Ok(());
662 }
663
664 let orig_parser = mem::replace(&mut self.parser, Ok(backref_parser));
665 let r = f(self);
666 self.parser = orig_parser;
667 r
668 }
669
670 fn pop_depth(&mut self) {
671 if let Ok(ref mut parser) = self.parser {
672 parser.pop_depth();
673 }
674 }
675
676 /// Output the given value to `self.out` (using `fmt::Display` formatting),
677 /// if printing isn't being skipped.
678 fn print(&mut self, x: impl fmt::Display) -> fmt::Result {
679 if let Some(out) = &mut self.out {
680 fmt::Display::fmt(&x, out)?;
681 }
682 Ok(())
683 }
684
685 /// Output the given `char`s (escaped using `char::escape_debug`), with the
686 /// whole sequence wrapped in quotes, for either a `char` or `&str` literal,
687 /// if printing isn't being skipped.
688 fn print_quoted_escaped_chars(
689 &mut self,
690 quote: char,
691 chars: impl Iterator<Item = char>,
692 ) -> fmt::Result {
693 if let Some(out) = &mut self.out {
694 use core::fmt::Write;
695
696 out.write_char(quote)?;
697 for c in chars {
698 // Special-case not escaping a single/double quote, when
699 // inside the opposite kind of quote.
700 if matches!((quote, c), ('\'', '"') | ('"', '\'')) {
701 out.write_char(c)?;
702 continue;
703 }
704
705 for escaped in c.escape_debug() {
706 out.write_char(escaped)?;
707 }
708 }
709 out.write_char(quote)?;
710 }
711 Ok(())
712 }
713
714 /// Print the lifetime according to the previously decoded index.
715 /// An index of `0` always refers to `'_`, but starting with `1`,
716 /// indices refer to late-bound lifetimes introduced by a binder.
717 fn print_lifetime_from_index(&mut self, lt: u64) -> fmt::Result {
718 // Bound lifetimes aren't tracked when skipping printing.
719 if self.out.is_none() {
720 return Ok(());
721 }
722
723 self.print("'")?;
724 if lt == 0 {
725 return self.print("_");
726 }
727 match (self.bound_lifetime_depth as u64).checked_sub(lt) {
728 Some(depth) => {
729 // Try to print lifetimes alphabetically first.
730 if depth < 26 {
731 let c = (b'a' + depth as u8) as char;
732 self.print(c)
733 } else {
734 // Use `'_123` after running out of letters.
735 self.print("_")?;
736 self.print(depth)
737 }
738 }
739 None => invalid!(self),
740 }
741 }
742
743 /// Optionally enter a binder ('G') for late-bound lifetimes,
744 /// printing e.g. `for<'a, 'b> ` before calling the closure,
745 /// and make those lifetimes visible to it (via depth level).
746 fn in_binder<F>(&mut self, f: F) -> fmt::Result
747 where
748 F: FnOnce(&mut Self) -> fmt::Result,
749 {
750 let bound_lifetimes = parse!(self, opt_integer_62(b'G'));
751
752 // Don't track bound lifetimes when skipping printing.
753 if self.out.is_none() {
754 return f(self);
755 }
756
757 if bound_lifetimes > 0 {
758 self.print("for<")?;
759 for i in 0..bound_lifetimes {
760 if i > 0 {
761 self.print(", ")?;
762 }
763 self.bound_lifetime_depth += 1;
764 self.print_lifetime_from_index(1)?;
765 }
766 self.print("> ")?;
767 }
768
769 let r = f(self);
770
771 // Restore `bound_lifetime_depth` to the previous value.
772 self.bound_lifetime_depth -= bound_lifetimes as u32;
773
774 r
775 }
776
777 /// Print list elements using the given closure and separator,
778 /// until the end of the list ('E') is found, or the parser errors.
779 /// Returns the number of elements printed.
780 fn print_sep_list<F>(&mut self, f: F, sep: &str) -> Result<usize, fmt::Error>
781 where
782 F: Fn(&mut Self) -> fmt::Result,
783 {
784 let mut i = 0;
785 while self.parser.is_ok() && !self.eat(b'E') {
786 if i > 0 {
787 self.print(sep)?;
788 }
789 f(self)?;
790 i += 1;
791 }
792 Ok(i)
793 }
794
795 fn print_path(&mut self, in_value: bool) -> fmt::Result {
796 parse!(self, push_depth);
797
798 let tag = parse!(self, next);
799 match tag {
800 b'C' => {
801 let dis = parse!(self, disambiguator);
802 let name = parse!(self, ident);
803
804 self.print(name)?;
805 if let Some(out) = &mut self.out {
806 if !out.alternate() {
807 out.write_str("[")?;
808 fmt::LowerHex::fmt(&dis, out)?;
809 out.write_str("]")?;
810 }
811 }
812 }
813 b'N' => {
814 let ns = parse!(self, namespace);
815
816 self.print_path(in_value)?;
817
818 // HACK(eddyb) if the parser is already marked as having errored,
819 // `parse!` below will print a `?` without its preceding `::`
820 // (because printing the `::` is skipped in certain conditions,
821 // i.e. a lowercase namespace with an empty identifier),
822 // so in order to get `::?`, the `::` has to be printed here.
823 if self.parser.is_err() {
824 self.print("::")?;
825 }
826
827 let dis = parse!(self, disambiguator);
828 let name = parse!(self, ident);
829
830 match ns {
831 // Special namespaces, like closures and shims.
832 Some(ns) => {
833 self.print("::{")?;
834 match ns {
835 'C' => self.print("closure")?,
836 'S' => self.print("shim")?,
837 _ => self.print(ns)?,
838 }
839 if !name.ascii.is_empty() || !name.punycode.is_empty() {
840 self.print(":")?;
841 self.print(name)?;
842 }
843 self.print("#")?;
844 self.print(dis)?;
845 self.print("}")?;
846 }
847
848 // Implementation-specific/unspecified namespaces.
849 None => {
850 if !name.ascii.is_empty() || !name.punycode.is_empty() {
851 self.print("::")?;
852 self.print(name)?;
853 }
854 }
855 }
856 }
857 b'M' | b'X' | b'Y' => {
858 if tag != b'Y' {
859 // Ignore the `impl`'s own path.
860 parse!(self, disambiguator);
861 self.skipping_printing(|this| this.print_path(false));
862 }
863
864 self.print("<")?;
865 self.print_type()?;
866 if tag != b'M' {
867 self.print(" as ")?;
868 self.print_path(false)?;
869 }
870 self.print(">")?;
871 }
872 b'I' => {
873 self.print_path(in_value)?;
874 if in_value {
875 self.print("::")?;
876 }
877 self.print("<")?;
878 self.print_sep_list(Self::print_generic_arg, ", ")?;
879 self.print(">")?;
880 }
881 b'B' => {
882 self.print_backref(|this| this.print_path(in_value))?;
883 }
884 _ => invalid!(self),
885 }
886
887 self.pop_depth();
888 Ok(())
889 }
890
891 fn print_generic_arg(&mut self) -> fmt::Result {
892 if self.eat(b'L') {
893 let lt = parse!(self, integer_62);
894 self.print_lifetime_from_index(lt)
895 } else if self.eat(b'K') {
896 self.print_const(false)
897 } else {
898 self.print_type()
899 }
900 }
901
902 fn print_type(&mut self) -> fmt::Result {
903 let tag = parse!(self, next);
904
905 if let Some(ty) = basic_type(tag) {
906 return self.print(ty);
907 }
908
909 parse!(self, push_depth);
910
911 match tag {
912 b'R' | b'Q' => {
913 self.print("&")?;
914 if self.eat(b'L') {
915 let lt = parse!(self, integer_62);
916 if lt != 0 {
917 self.print_lifetime_from_index(lt)?;
918 self.print(" ")?;
919 }
920 }
921 if tag != b'R' {
922 self.print("mut ")?;
923 }
924 self.print_type()?;
925 }
926
927 b'P' | b'O' => {
928 self.print("*")?;
929 if tag != b'P' {
930 self.print("mut ")?;
931 } else {
932 self.print("const ")?;
933 }
934 self.print_type()?;
935 }
936
937 b'A' | b'S' => {
938 self.print("[")?;
939 self.print_type()?;
940 if tag == b'A' {
941 self.print("; ")?;
942 self.print_const(true)?;
943 }
944 self.print("]")?;
945 }
946 b'T' => {
947 self.print("(")?;
948 let count = self.print_sep_list(Self::print_type, ", ")?;
949 if count == 1 {
950 self.print(",")?;
951 }
952 self.print(")")?;
953 }
954 b'F' => self.in_binder(|this| {
955 let is_unsafe = this.eat(b'U');
956 let abi = if this.eat(b'K') {
957 if this.eat(b'C') {
958 Some("C")
959 } else {
960 let abi = parse!(this, ident);
961 if abi.ascii.is_empty() || !abi.punycode.is_empty() {
962 invalid!(this);
963 }
964 Some(abi.ascii)
965 }
966 } else {
967 None
968 };
969
970 if is_unsafe {
971 this.print("unsafe ")?;
972 }
973
974 if let Some(abi) = abi {
975 this.print("extern \"")?;
976
977 // If the ABI had any `-`, they were replaced with `_`,
978 // so the parts between `_` have to be re-joined with `-`.
979 let mut parts = abi.split('_');
980 this.print(parts.next().unwrap())?;
981 for part in parts {
982 this.print("-")?;
983 this.print(part)?;
984 }
985
986 this.print("\" ")?;
987 }
988
989 this.print("fn(")?;
990 this.print_sep_list(Self::print_type, ", ")?;
991 this.print(")")?;
992
993 if this.eat(b'u') {
994 // Skip printing the return type if it's 'u', i.e. `()`.
995 } else {
996 this.print(" -> ")?;
997 this.print_type()?;
998 }
999
1000 Ok(())
1001 })?,
1002 b'D' => {
1003 self.print("dyn ")?;
1004 self.in_binder(|this| {
1005 this.print_sep_list(Self::print_dyn_trait, " + ")?;
1006 Ok(())
1007 })?;
1008
1009 if !self.eat(b'L') {
1010 invalid!(self);
1011 }
1012 let lt = parse!(self, integer_62);
1013 if lt != 0 {
1014 self.print(" + ")?;
1015 self.print_lifetime_from_index(lt)?;
1016 }
1017 }
1018 b'B' => {
1019 self.print_backref(Self::print_type)?;
1020 }
1021 _ => {
1022 // Go back to the tag, so `print_path` also sees it.
1023 let _ = self.parser.as_mut().map(|p| p.next -= 1);
1024 self.print_path(false)?;
1025 }
1026 }
1027
1028 self.pop_depth();
1029 Ok(())
1030 }
1031
1032 /// A trait in a trait object may have some "existential projections"
1033 /// (i.e. associated type bindings) after it, which should be printed
1034 /// in the `<...>` of the trait, e.g. `dyn Trait<T, U, Assoc=X>`.
1035 /// To this end, this method will keep the `<...>` of an 'I' path
1036 /// open, by omitting the `>`, and return `Ok(true)` in that case.
1037 fn print_path_maybe_open_generics(&mut self) -> Result<bool, fmt::Error> {
1038 if self.eat(b'B') {
1039 // NOTE(eddyb) the closure may not run if printing is being skipped,
1040 // but in that case the returned boolean doesn't matter.
1041 let mut open = false;
1042 self.print_backref(|this| {
1043 open = this.print_path_maybe_open_generics()?;
1044 Ok(())
1045 })?;
1046 Ok(open)
1047 } else if self.eat(b'I') {
1048 self.print_path(false)?;
1049 self.print("<")?;
1050 self.print_sep_list(Self::print_generic_arg, ", ")?;
1051 Ok(true)
1052 } else {
1053 self.print_path(false)?;
1054 Ok(false)
1055 }
1056 }
1057
1058 fn print_dyn_trait(&mut self) -> fmt::Result {
1059 let mut open = self.print_path_maybe_open_generics()?;
1060
1061 while self.eat(b'p') {
1062 if !open {
1063 self.print("<")?;
1064 open = true;
1065 } else {
1066 self.print(", ")?;
1067 }
1068
1069 let name = parse!(self, ident);
1070 self.print(name)?;
1071 self.print(" = ")?;
1072 self.print_type()?;
1073 }
1074
1075 if open {
1076 self.print(">")?;
1077 }
1078
1079 Ok(())
1080 }
1081
1082 fn print_const(&mut self, in_value: bool) -> fmt::Result {
1083 let tag = parse!(self, next);
1084
1085 parse!(self, push_depth);
1086
1087 // Only literals (and the names of `const` generic parameters, but they
1088 // don't get mangled at all), can appear in generic argument position
1089 // without any disambiguation, all other expressions require braces.
1090 // To avoid duplicating the mapping between `tag` and what syntax gets
1091 // used (especially any special-casing), every case that needs braces
1092 // has to call `open_brace(self)?` (and the closing brace is automatic).
1093 let mut opened_brace = false;
1094 let mut open_brace_if_outside_expr = |this: &mut Self| {
1095 // If this expression is nested in another, braces aren't required.
1096 if in_value {
1097 return Ok(());
1098 }
1099
1100 opened_brace = true;
1101 this.print("{")
1102 };
1103
1104 match tag {
1105 b'p' => self.print("_")?,
1106
1107 // Primitive leaves with hex-encoded values (see `basic_type`).
1108 b'h' | b't' | b'm' | b'y' | b'o' | b'j' => self.print_const_uint(tag)?,
1109 b'a' | b's' | b'l' | b'x' | b'n' | b'i' => {
1110 if self.eat(b'n') {
1111 self.print("-")?;
1112 }
1113
1114 self.print_const_uint(tag)?;
1115 }
1116 b'b' => match parse!(self, hex_nibbles).try_parse_uint() {
1117 Some(0) => self.print("false")?,
1118 Some(1) => self.print("true")?,
1119 _ => invalid!(self),
1120 },
1121 b'c' => {
1122 let valid_char = parse!(self, hex_nibbles)
1123 .try_parse_uint()
1124 .and_then(|v| u32::try_from(v).ok())
1125 .and_then(char::from_u32);
1126 match valid_char {
1127 Some(c) => self.print_quoted_escaped_chars('\'', iter::once(c))?,
1128 None => invalid!(self),
1129 }
1130 }
1131 b'e' => {
1132 // NOTE(eddyb) a string literal `"..."` has type `&str`, so
1133 // to get back the type `str`, `*"..."` syntax is needed
1134 // (even if that may not be valid in Rust itself).
1135 open_brace_if_outside_expr(self)?;
1136 self.print("*")?;
1137
1138 self.print_const_str_literal()?;
1139 }
1140
1141 b'R' | b'Q' => {
1142 // NOTE(eddyb) this prints `"..."` instead of `&*"..."`, which
1143 // is what `Re..._` would imply (see comment for `str` above).
1144 if tag == b'R' && self.eat(b'e') {
1145 self.print_const_str_literal()?;
1146 } else {
1147 open_brace_if_outside_expr(self)?;
1148 self.print("&")?;
1149 if tag != b'R' {
1150 self.print("mut ")?;
1151 }
1152 self.print_const(true)?;
1153 }
1154 }
1155 b'A' => {
1156 open_brace_if_outside_expr(self)?;
1157 self.print("[")?;
1158 self.print_sep_list(|this| this.print_const(true), ", ")?;
1159 self.print("]")?;
1160 }
1161 b'T' => {
1162 open_brace_if_outside_expr(self)?;
1163 self.print("(")?;
1164 let count = self.print_sep_list(|this| this.print_const(true), ", ")?;
1165 if count == 1 {
1166 self.print(",")?;
1167 }
1168 self.print(")")?;
1169 }
1170 b'V' => {
1171 open_brace_if_outside_expr(self)?;
1172 self.print_path(true)?;
1173 match parse!(self, next) {
1174 b'U' => {}
1175 b'T' => {
1176 self.print("(")?;
1177 self.print_sep_list(|this| this.print_const(true), ", ")?;
1178 self.print(")")?;
1179 }
1180 b'S' => {
1181 self.print(" { ")?;
1182 self.print_sep_list(
1183 |this| {
1184 parse!(this, disambiguator);
1185 let name = parse!(this, ident);
1186 this.print(name)?;
1187 this.print(": ")?;
1188 this.print_const(true)
1189 },
1190 ", ",
1191 )?;
1192 self.print(" }")?;
1193 }
1194 _ => invalid!(self),
1195 }
1196 }
1197 b'B' => {
1198 self.print_backref(|this| this.print_const(in_value))?;
1199 }
1200 _ => invalid!(self),
1201 }
1202
1203 if opened_brace {
1204 self.print("}")?;
1205 }
1206
1207 self.pop_depth();
1208 Ok(())
1209 }
1210
1211 fn print_const_uint(&mut self, ty_tag: u8) -> fmt::Result {
1212 let hex = parse!(self, hex_nibbles);
1213
1214 match hex.try_parse_uint() {
1215 Some(v) => self.print(v)?,
1216
1217 // Print anything that doesn't fit in `u64` verbatim.
1218 None => {
1219 self.print("0x")?;
1220 self.print(hex.nibbles)?;
1221 }
1222 }
1223
1224 if let Some(out) = &mut self.out {
1225 if !out.alternate() {
1226 let ty = basic_type(ty_tag).unwrap();
1227 self.print(ty)?;
1228 }
1229 }
1230
1231 Ok(())
1232 }
1233
1234 fn print_const_str_literal(&mut self) -> fmt::Result {
1235 match parse!(self, hex_nibbles).try_parse_str_chars() {
1236 Some(chars) => self.print_quoted_escaped_chars('"', chars),
1237 None => invalid!(self),
1238 }
1239 }
1240}
1241
1242#[cfg(test)]
1243mod tests {
1244 use std::prelude::v1::*;
1245
1246 macro_rules! t {
1247 ($a:expr, $b:expr) => {{
1248 assert_eq!(format!("{}", ::demangle($a)), $b);
1249 }};
1250 }
1251 macro_rules! t_nohash {
1252 ($a:expr, $b:expr) => {{
1253 assert_eq!(format!("{:#}", ::demangle($a)), $b);
1254 }};
1255 }
1256 macro_rules! t_nohash_type {
1257 ($a:expr, $b:expr) => {
1258 t_nohash!(concat!("_RMC0", $a), concat!("<", $b, ">"))
1259 };
1260 }
1261 macro_rules! t_const {
1262 ($mangled:expr, $value:expr) => {
1263 t_nohash!(
1264 concat!("_RIC0K", $mangled, "E"),
1265 concat!("::<", $value, ">")
1266 )
1267 };
1268 }
1269 macro_rules! t_const_suffixed {
1270 ($mangled:expr, $value:expr, $value_ty_suffix:expr) => {{
1271 t_const!($mangled, $value);
1272 t!(
1273 concat!("_RIC0K", $mangled, "E"),
1274 concat!("[0]::<", $value, $value_ty_suffix, ">")
1275 );
1276 }};
1277 }
1278
1279 #[test]
1280 fn demangle_crate_with_leading_digit() {
1281 t_nohash!("_RNvC6_123foo3bar", "123foo::bar");
1282 }
1283
1284 #[test]
1285 fn demangle_utf8_idents() {
1286 t_nohash!(
1287 "_RNqCs4fqI2P2rA04_11utf8_identsu30____7hkackfecea1cbdathfdh9hlq6y",
1288 "utf8_idents::საჭმელად_გემრიელი_სადილი"
1289 );
1290 }
1291
1292 #[test]
1293 fn demangle_closure() {
1294 t_nohash!(
1295 "_RNCNCNgCs6DXkGYLi8lr_2cc5spawn00B5_",
1296 "cc::spawn::{closure#0}::{closure#0}"
1297 );
1298 t_nohash!(
1299 "_RNCINkXs25_NgCsbmNqQUJIY6D_4core5sliceINyB9_4IterhENuNgNoBb_4iter8iterator8Iterator9rpositionNCNgNpB9_6memchr7memrchrs_0E0Bb_",
1300 "<core::slice::Iter<u8> as core::iter::iterator::Iterator>::rposition::<core::slice::memchr::memrchr::{closure#1}>::{closure#0}"
1301 );
1302 }
1303
1304 #[test]
1305 fn demangle_dyn_trait() {
1306 t_nohash!(
1307 "_RINbNbCskIICzLVDPPb_5alloc5alloc8box_freeDINbNiB4_5boxed5FnBoxuEp6OutputuEL_ECs1iopQbuBiw2_3std",
1308 "alloc::alloc::box_free::<dyn alloc::boxed::FnBox<(), Output = ()>>"
1309 );
1310 }
1311
1312 #[test]
1313 fn demangle_const_generics_preview() {
1314 // NOTE(eddyb) this was hand-written, before rustc had working
1315 // const generics support (but the mangling format did include them).
1316 t_nohash_type!(
1317 "INtC8arrayvec8ArrayVechKj7b_E",
1318 "arrayvec::ArrayVec<u8, 123>"
1319 );
1320 t_const_suffixed!("j7b_", "123", "usize");
1321 }
1322
1323 #[test]
1324 fn demangle_min_const_generics() {
1325 t_const!("p", "_");
1326 t_const_suffixed!("hb_", "11", "u8");
1327 t_const_suffixed!("off00ff00ff00ff00ff_", "0xff00ff00ff00ff00ff", "u128");
1328 t_const_suffixed!("s98_", "152", "i16");
1329 t_const_suffixed!("anb_", "-11", "i8");
1330 t_const!("b0_", "false");
1331 t_const!("b1_", "true");
1332 t_const!("c76_", "'v'");
1333 t_const!("c22_", r#"'"'"#);
1334 t_const!("ca_", "'\\n'");
1335 t_const!("c2202_", "'∂'");
1336 }
1337
1338 #[test]
1339 fn demangle_const_str() {
1340 t_const!("e616263_", "{*\"abc\"}");
1341 t_const!("e27_", r#"{*"'"}"#);
1342 t_const!("e090a_", "{*\"\\t\\n\"}");
1343 t_const!("ee28882c3bc_", "{*\"∂ü\"}");
1344 t_const!(
1345 "ee183a1e18390e183ade1839be18394e1839ae18390e183935fe18392e18394e1839b\
1346 e183a0e18398e18394e1839ae183985fe183a1e18390e18393e18398e1839ae18398_",
1347 "{*\"საჭმელად_გემრიელი_სადილი\"}"
1348 );
1349 t_const!(
1350 "ef09f908af09fa688f09fa686f09f90ae20c2a720f09f90b6f09f9192e298\
1351 95f09f94a520c2a720f09fa7a1f09f929bf09f929af09f9299f09f929c_",
1352 "{*\"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜\"}"
1353 );
1354 }
1355
1356 // NOTE(eddyb) this uses the same strings as `demangle_const_str` and should
1357 // be kept in sync with it - while a macro could be used to generate both
1358 // `str` and `&str` tests, from a single list of strings, this seems clearer.
1359 #[test]
1360 fn demangle_const_ref_str() {
1361 t_const!("Re616263_", "\"abc\"");
1362 t_const!("Re27_", r#""'""#);
1363 t_const!("Re090a_", "\"\\t\\n\"");
1364 t_const!("Ree28882c3bc_", "\"∂ü\"");
1365 t_const!(
1366 "Ree183a1e18390e183ade1839be18394e1839ae18390e183935fe18392e18394e1839b\
1367 e183a0e18398e18394e1839ae183985fe183a1e18390e18393e18398e1839ae18398_",
1368 "\"საჭმელად_გემრიელი_სადილი\""
1369 );
1370 t_const!(
1371 "Ref09f908af09fa688f09fa686f09f90ae20c2a720f09f90b6f09f9192e298\
1372 95f09f94a520c2a720f09fa7a1f09f929bf09f929af09f9299f09f929c_",
1373 "\"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜\""
1374 );
1375 }
1376
1377 #[test]
1378 fn demangle_const_ref() {
1379 t_const!("Rp", "{&_}");
1380 t_const!("Rh7b_", "{&123}");
1381 t_const!("Rb0_", "{&false}");
1382 t_const!("Rc58_", "{&'X'}");
1383 t_const!("RRRh0_", "{&&&0}");
1384 t_const!("RRRe_", "{&&\"\"}");
1385 t_const!("QAE", "{&mut []}");
1386 }
1387
1388 #[test]
1389 fn demangle_const_array() {
1390 t_const!("AE", "{[]}");
1391 t_const!("Aj0_E", "{[0]}");
1392 t_const!("Ah1_h2_h3_E", "{[1, 2, 3]}");
1393 t_const!("ARe61_Re62_Re63_E", "{[\"a\", \"b\", \"c\"]}");
1394 t_const!("AAh1_h2_EAh3_h4_EE", "{[[1, 2], [3, 4]]}");
1395 }
1396
1397 #[test]
1398 fn demangle_const_tuple() {
1399 t_const!("TE", "{()}");
1400 t_const!("Tj0_E", "{(0,)}");
1401 t_const!("Th1_b0_E", "{(1, false)}");
1402 t_const!(
1403 "TRe616263_c78_RAh1_h2_h3_EE",
1404 "{(\"abc\", 'x', &[1, 2, 3])}"
1405 );
1406 }
1407
1408 #[test]
1409 fn demangle_const_adt() {
1410 t_const!(
1411 "VNvINtNtC4core6option6OptionjE4NoneU",
1412 "{core::option::Option::<usize>::None}"
1413 );
1414 t_const!(
1415 "VNvINtNtC4core6option6OptionjE4SomeTj0_E",
1416 "{core::option::Option::<usize>::Some(0)}"
1417 );
1418 t_const!(
1419 "VNtC3foo3BarS1sRe616263_2chc78_5sliceRAh1_h2_h3_EE",
1420 "{foo::Bar { s: \"abc\", ch: 'x', slice: &[1, 2, 3] }}"
1421 );
1422 }
1423
1424 #[test]
1425 fn demangle_exponential_explosion() {
1426 // NOTE(eddyb) because of the prefix added by `t_nohash_type!` is
1427 // 3 bytes long, `B2_` refers to the start of the type, not `B_`.
1428 // 6 backrefs (`B8_E` through `B3_E`) result in 2^6 = 64 copies of `_`.
1429 // Also, because the `p` (`_`) type is after all of the starts of the
1430 // backrefs, it can be replaced with any other type, independently.
1431 t_nohash_type!(
1432 concat!("TTTTTT", "p", "B8_E", "B7_E", "B6_E", "B5_E", "B4_E", "B3_E"),
1433 "((((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _)))), \
1434 ((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _))))), \
1435 (((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _)))), \
1436 ((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _))))))"
1437 );
1438 }
1439
1440 #[test]
1441 fn demangle_thinlto() {
1442 t_nohash!("_RC3foo.llvm.9D1C9369", "foo");
1443 t_nohash!("_RC3foo.llvm.9D1C9369@@16", "foo");
1444 t_nohash!("_RNvC9backtrace3foo.llvm.A5310EB9", "backtrace::foo");
1445 }
1446
1447 #[test]
1448 fn demangle_extra_suffix() {
1449 // From alexcrichton/rustc-demangle#27:
1450 t_nohash!(
1451 "_RNvNtNtNtNtCs92dm3009vxr_4rand4rngs7adapter9reseeding4fork23FORK_HANDLER_REGISTERED.0.0",
1452 "rand::rngs::adapter::reseeding::fork::FORK_HANDLER_REGISTERED.0.0"
1453 );
1454 }
1455
1456 #[test]
1457 fn demangling_limits() {
1458 // Stress tests found via fuzzing.
1459
1460 for sym in include_str!("v0-large-test-symbols/early-recursion-limit")
1461 .lines()
1462 .filter(|line| !line.is_empty() && !line.starts_with('#'))
1463 {
1464 assert_eq!(
1465 super::demangle(sym).map(|_| ()),
1466 Err(super::ParseError::RecursedTooDeep)
1467 );
1468 }
1469
1470 assert_contains!(
1471 ::demangle(
1472 "RIC20tRYIMYNRYFG05_EB5_B_B6_RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR\
1473 RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB_E",
1474 )
1475 .to_string(),
1476 "{recursion limit reached}"
1477 );
1478 }
1479
1480 #[test]
1481 fn recursion_limit_leaks() {
1482 // NOTE(eddyb) this test checks that both paths and types support the
1483 // recursion limit correctly, i.e. matching `push_depth` and `pop_depth`,
1484 // and don't leak "recursion levels" and trip the limit.
1485 // The test inputs are generated on the fly, using a repeated pattern,
1486 // as hardcoding the actual strings would be too verbose.
1487 // Also, `MAX_DEPTH` can be directly used, instead of assuming its value.
1488 for &(sym_leaf, expected_leaf) in &[("p", "_"), ("Rp", "&_"), ("C1x", "x")] {
1489 let mut sym = format!("_RIC0p");
1490 let mut expected = format!("::<_");
1491 for _ in 0..(super::MAX_DEPTH * 2) {
1492 sym.push_str(sym_leaf);
1493 expected.push_str(", ");
1494 expected.push_str(expected_leaf);
1495 }
1496 sym.push('E');
1497 expected.push('>');
1498
1499 t_nohash!(&sym, expected);
1500 }
1501 }
1502
1503 #[test]
1504 fn recursion_limit_backref_free_bypass() {
1505 // NOTE(eddyb) this test checks that long symbols cannot bypass the
1506 // recursion limit by not using backrefs, and cause a stack overflow.
1507
1508 // This value was chosen to be high enough that stack overflows were
1509 // observed even with `cargo test --release`.
1510 let depth = 100_000;
1511
1512 // In order to hide the long mangling from the initial "shallow" parse,
1513 // it's nested in an identifier (crate name), preceding its use.
1514 let mut sym = format!("_RIC{}", depth);
1515 let backref_start = sym.len() - 2;
1516 for _ in 0..depth {
1517 sym.push('R');
1518 }
1519
1520 // Write a backref to just after the length of the identifier.
1521 sym.push('B');
1522 sym.push(char::from_digit((backref_start - 1) as u32, 36).unwrap());
1523 sym.push('_');
1524
1525 // Close the `I` at the start.
1526 sym.push('E');
1527
1528 assert_contains!(::demangle(&sym).to_string(), "{recursion limit reached}");
1529 }
1530}
1531