Skip to content

Commit 281d178

Browse files
authored
[clang] Diagnose functions with too many parameters (#104833)
This patch adds a parser check when a function declaration or function type declaration (in a function pointer declaration, for example) has too many parameters for `FunctionTypeBits::NumParams` to hold. At the moment of writing it's a 16-bit-wide bit-field, limiting the number of parameters at 65536. The check is added in the parser loop that goes over comma-separated list of function parameters. This is not the solution Aaron suggested in #35741 (comment), because it was found out that it's quite hard to recover from this particular error in `GetFullTypeForDeclarator()`. Multiple options were tried, but all of them led to crashes down the line. I used LLVM Compile Time Tracker to ensure this does not introduce a performance regression. I believe changes are in the noise: https://llvm-compile-time-tracker.com/compare.php?from=de5ea2d122c31e1551654ff506c33df299f351b8&to=424818620766cedb2770e076ee359afeb0cc14ec&stat=instructions:u Fixes #35741
1 parent 76c0798 commit 281d178

File tree

5 files changed

+52
-1
lines changed

5 files changed

+52
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ Miscellaneous Clang Crashes Fixed
310310
- Fixed a crash caused by long chains of ``sizeof`` and other similar operators
311311
that can be followed by a non-parenthesized expression. (#GH45061)
312312

313+
- Fixed a crash when function has more than 65536 parameters.
314+
Now a diagnostic is emitted. (#GH35741)
315+
313316
OpenACC Specific Changes
314317
------------------------
315318

clang/include/clang/AST/Type.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1929,6 +1929,11 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
19291929
unsigned Kind : NumOfBuiltinTypeBits;
19301930
};
19311931

1932+
public:
1933+
static constexpr int FunctionTypeNumParamsWidth = 16;
1934+
static constexpr int FunctionTypeNumParamsLimit = (1 << 16) - 1;
1935+
1936+
protected:
19321937
/// FunctionTypeBitfields store various bits belonging to FunctionProtoType.
19331938
/// Only common bits are stored here. Additional uncommon bits are stored
19341939
/// in a trailing object after FunctionProtoType.
@@ -1966,7 +1971,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
19661971
/// According to [implimits] 8 bits should be enough here but this is
19671972
/// somewhat easy to exceed with metaprogramming and so we would like to
19681973
/// keep NumParams as wide as reasonably possible.
1969-
unsigned NumParams : 16;
1974+
unsigned NumParams : FunctionTypeNumParamsWidth;
19701975

19711976
/// The type of exception specification this function has.
19721977
LLVM_PREFERRED_TYPE(ExceptionSpecificationType)

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,9 @@ def ext_decomp_decl_empty : ExtWarn<
481481
"ISO C++17 does not allow a decomposition group to be empty">,
482482
InGroup<DiagGroup<"empty-decomposition">>;
483483

484+
def err_function_parameter_limit_exceeded : Error<
485+
"too many function parameters; subsequent parameters will be ignored">;
486+
484487
// C++26 structured bindings
485488
def ext_decl_attrs_on_binding : ExtWarn<
486489
"an attribute specifier sequence attached to a structured binding declaration "

clang/lib/Parse/ParseDecl.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8025,6 +8025,17 @@ void Parser::ParseParameterDeclarationClause(
80258025
// Consume the keyword.
80268026
ConsumeToken();
80278027
}
8028+
8029+
// We can only store so many parameters
8030+
// Skip until the the end of the parameter list, ignoring
8031+
// parameters that would overflow.
8032+
if (ParamInfo.size() == Type::FunctionTypeNumParamsLimit) {
8033+
Diag(ParmDeclarator.getBeginLoc(),
8034+
diag::err_function_parameter_limit_exceeded);
8035+
SkipUntil(tok::r_paren, SkipUntilFlags::StopBeforeMatch);
8036+
break;
8037+
}
8038+
80288039
// Inform the actions module about the parameter declarator, so it gets
80298040
// added to the current scope.
80308041
Decl *Param =
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %clang_cc1 -verify %s
2+
3+
#define P_10(x) x##0, x##1, x##2, x##3, x##4, x##5, x##6, x##7, x##8, x##9,
4+
#define P_100(x) P_10(x##0) P_10(x##1) P_10(x##2) P_10(x##3) P_10(x##4) \
5+
P_10(x##5) P_10(x##6) P_10(x##7) P_10(x##8) P_10(x##9)
6+
#define P_1000(x) P_100(x##0) P_100(x##1) P_100(x##2) P_100(x##3) P_100(x##4) \
7+
P_100(x##5) P_100(x##6) P_100(x##7) P_100(x##8) P_100(x##9)
8+
#define P_10000(x) P_1000(x##0) P_1000(x##1) P_1000(x##2) P_1000(x##3) P_1000(x##4) \
9+
P_1000(x##5) P_1000(x##6) P_1000(x##7) P_1000(x##8) P_1000(x##9)
10+
11+
void func (
12+
P_10000(int p)
13+
P_10000(int q)
14+
P_10000(int r)
15+
P_10000(int s)
16+
P_10000(int t)
17+
P_10000(int u)
18+
P_10000(int v) // expected-error {{too many function parameters; subsequent parameters will be ignored}}
19+
int w);
20+
21+
extern double(*func2)(
22+
P_10000(int p)
23+
P_10000(int q)
24+
P_10000(int r)
25+
P_10000(int s)
26+
P_10000(int t)
27+
P_10000(int u)
28+
P_10000(int v) // expected-error {{too many function parameters; subsequent parameters will be ignored}}
29+
int w);

0 commit comments

Comments
 (0)