A libfuzzer run has discovered some inputs for which the demangler does not terminate.
When minimized, it looks like this: _Zcv1BIRT_EIS1_E
Deciphered:
_Z
cv - conversion operator
* result type
1B - "B"
I - template args begin
R - reference type <.
T_ - forward template reference | *
E - template args end | |
| |
* parameter type | |
I - template args begin | |
S1_ - substitution #1 * <'
E - template args endThe reason is: template-parameter refs in conversion operator result type create forward-references, while substitutions are instantly resolved via back-references. Together these can create a reference loop. It causes an infinite loop in ReferenceType::collapse().
I see three possible ways to avoid these loops:
- check if resolving a forward reference creates a loop and reject the invalid input (hard to traverse AST at this point)
- check if a substitution contains a malicious forward reference and reject the invalid input (hard to traverse AST at this point; substitutions are quite common: may affect performance; hard to clearly detect loops at this point)
- detect loops in ReferenceType::collapse() (cannot reject the input)
This patch implements (3) as seemingly the least-impact change. As a side effect, such invalid input strings are not rejected and produce garbage, however there are already similar guards in if (Printing) return; checks.
We need to add this at the top of this file:
// https://llvm.org/PR51407 was not fixed in some previously-released demanglers, which // causes them to run into the infinite loop. // UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14|15}} // UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx11.0Otherwise, we'll try to run the test on those configurations and we'll run into the infinite loop. Incidentally, this just stalled the CI for 24 hours (I'll put a timeout on our tests).