This is an archive of the discontinued LLVM Phabricator instance.

[clang] Limit the maximum level of fold-expr expansion.
ClosedPublic

Authored by hokein on Sep 1 2020, 6:35 AM.

Details

Summary

Introduce a new diagnostic, and respect the bracket-depth (256) by default.

Diff Detail

Event Timeline

hokein created this revision.Sep 1 2020, 6:35 AM
Herald added a project: Restricted Project. · View Herald TranscriptSep 1 2020, 6:35 AM
hokein requested review of this revision.Sep 1 2020, 6:35 AM
sammccall added inline comments.Sep 1 2020, 1:10 PM
clang/include/clang/Basic/DiagnosticSemaKinds.td
5095

I think this should be NoSFINAE, similar to err_template_recursion_depth_exceeded.

Maybe DefaultFatal too?

5096

The diagnostic test could be clearer: what's a "fold expression expansion level"?

what about "instantiating fold expression with %0 arguments exceeds expression nesting limit of %1"?

clang/lib/Sema/TreeTransform.h
13196

The brackets here are not obvious. Also we're not actually tracking bracket *depth*! So this definitely needs a comment.

Something like:

// Formally a fold expression expands to nested parenthesized expressions.
// Enforce this limit to avoid creating trees so deep we can't safely traverse them
13197

you might also want to emit note_bracket_depth (I don't think you need to clone it if we get the wording right)

clang/test/SemaCXX/fold_expr_expansion_limit.cpp
9

this diagnostic is bogus :-(
default-fatal would fix this, I guess.

hokein updated this revision to Diff 289372.Sep 2 2020, 2:11 AM
hokein marked 4 inline comments as done.

address review comments.

clang/lib/Sema/TreeTransform.h
13197

note_bracket_depth is from parse diagnostic, introducing it in Sema feels like a slight layer violation, but the compile should be fine, because all diagnostic headers in the support library.

clang/test/SemaCXX/fold_expr_expansion_limit.cpp
9

oh, yeah, if a fatal error is emitted, all subsequent diagnostics will be silenced.

sammccall accepted this revision.Sep 2 2020, 6:41 AM
sammccall added inline comments.
clang/include/clang/Basic/DiagnosticSemaKinds.td
5096

arguements -> arguments

This revision is now accepted and ready to land.Sep 2 2020, 6:41 AM
hokein updated this revision to Diff 290445.Sep 8 2020, 3:46 AM

fix a typo.

This revision was landed with ongoing or failed builds.Sep 8 2020, 6:40 AM
This revision was automatically updated to reflect the committed changes.

Why did we select the 'bracket-depth' for this? The documentation on that doesn't seem to be anything close to what this should be based on:

Sets the limit for nested parentheses, brackets, and braces to N in blocks, declarators, expressions, and struct or union declarations.

The 256 default limit is REALLY small for a fold expression, particularly since the instantiation depth limit is 1024 by default. I think this patch needs to be changed to use the InstantiationDepth instead. @rjmccall, thoughts?

Why did we select the 'bracket-depth' for this? The documentation on that doesn't seem to be anything close to what this should be based on:

Sets the limit for nested parentheses, brackets, and braces to N in blocks, declarators, expressions, and struct or union declarations.

The 256 default limit is REALLY small for a fold expression, particularly since the instantiation depth limit is 1024 by default. I think this patch needs to be changed to use the InstantiationDepth instead. @rjmccall, thoughts?

Even that limit (1024) seems like it is perhaps a little conservative. Apparently, this comes up in Boost Numerics, where they use a pack of size 1089 at one point that they use a '+' fold expression that this causes us to no longer be able to build.

Why did we select the 'bracket-depth' for this? The documentation on that doesn't seem to be anything close to what this should be based on:

Based on a discussion with @rsmith - the formal definition of pack expansion is that it expands to nested parenthesized expressions expressions.

Sets the limit for nested parentheses, brackets, and braces to N in blocks, declarators, expressions, and struct or union declarations.

The 256 default limit is REALLY small for a fold expression, particularly since the instantiation depth limit is 1024 by default. I think this patch needs to be changed to use the InstantiationDepth instead. @rjmccall, thoughts?

One motivation here is to limit exposure of tools to stack overflows. A modest increase in the stack size of DynTypedNode triggered stack overflows in various traversals on real code.
While it's possible in principle to write traversals that use only data recursion (and I've also fixed the ones in clang itself that I can find), in practice a lot of code and tools rely on recursive traversals, so trivially creating arbitrarily deep ASTs without any limit is certain to break things with unclear responsibility. (Whereas this change places responsibility with boost numerics).

FWIW, somewhere between 1024 and 2048 was the critical depth on the systems we looked at, so 1024 seems... plausible, but large.