Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reorder parsing of type qualifiers to match the spec. #280

Merged
merged 2 commits into from
Apr 13, 2023

Conversation

khuey
Copy link
Collaborator

@khuey khuey commented Apr 12, 2023

The spec says that the qualified-type production (within type) is parsed second only to the builtin-type production. The qualified-type production is ambiguous with later productions (in particular with the "Ul" inside class-enum-type) so the order does matter. This reorders things for "Ul" and brings along the other parts of the qualified-type production.

To preserve the existing behavior for function-type, rather than attempt to pass down a leading CV-qualifiers we simply skip them if the tail remaining indicates a function-type production is imminent.

This is the root cause of @Swatinem's issue, though perhaps some defense in depth that limits runaway growth of substitution tables is still wise.

The spec says that the `qualified-type` production (within `type`) is
parsed second only to the `builtin-type` production. The `qualified-type`
production is ambiguous with later productions (in particular with
the "Ul" inside `class-enum-type`) so the order does matter. This
reorders things for "Ul" and brings along the other parts of the
`qualified-type` production.

To preserve the existing behavior for `function-type`, rather than attempt
to pass down a leading `CV-qualifiers` we simply skip them if the
tail remaining indicates a `function-type` production is imminent.
@Swatinem
Copy link
Contributor

This indeed covers the pathological case. Here is a test that now runs instantly, whereas it would previously spin for ~15 seconds for production builds. Feel free to also add it to the testsuite.

// This symbol previously ran into some mutual recursion and unbounded growth of the substitution table.
// See <https://github.com/gimli-rs/cpp_demangle/issues/277> and <https://github.com/getsentry/symbolic/issues/477>
#[test]
fn test_pathological_recursion() {
    let s = "_ZUlzjjlZZL1zStUlSt7j_Z3kjIIjIjL1vfIIEEEjzjjfjzSt7j_Z3kjIIjfjzL4t3kjIIjfjtUlSt7j_Z3kjIIjIjL1vfIIEEEjzjjfjzSt7j_Z3kjIIjfjzL4t3kjIIjfjzL4t7IjIjjzjjzSt7j_Z3kjIIjfjzStfjzSt7j_ZA3kjIIjIjL1vfIIEEEjzjjfjzSt7j_Z3kjIIjIjL1vfIIEEEjzjjfjzSt7j_Z3kjIIjfjzL4t3kjIIjzL4t7IjIjjzjjzSt7j_Z3kjIIjfjzStfjzSt7j_ZA3kjIIjIjL1vfIIEEEjzjjfjzSt7j_Z3kjIIjIjL1vfIIEEEjzjjfjzSt7j_Z3kjIIjfjzL4t3kjIIjfjzL4t7IjIjL1vfIIEEEjzjjSI";
    let parse_options = cpp_demangle::ParseOptions::default().recursion_limit(160); // default is 96
    if let Ok(sym) = cpp_demangle::Symbol::new_with_options(s, &parse_options) {
        panic!("Unexpectedly parsed '{}' as '{}'", s, sym);
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants