diff options
author | 天音あめ <i@amane-a.me> | 2025-01-07 20:49:43 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-07 07:49:43 -0500 |
commit | ca5fd06366448c94e1da085984e9e69f8d6398c3 (patch) | |
tree | 6e03090a932ae91b90d509b4aaea0a99fe2f4523 | |
parent | a5e129ccdedf5c269a8e0fcad5e21381a7f0342c (diff) | |
download | llvm-ca5fd06366448c94e1da085984e9e69f8d6398c3.zip llvm-ca5fd06366448c94e1da085984e9e69f8d6398c3.tar.gz llvm-ca5fd06366448c94e1da085984e9e69f8d6398c3.tar.bz2 |
[clang] Fix crashes when passing VLA to va_arg (#119563)
Closes #119360.
This bug occurs when passing a VLA to `va_arg`. Since the return value
is inferred to be an array, it triggers
`ScalarExprEmitter::VisitCastExpr`, which converts it to a pointer and
subsequently calls `CodeGenFunction::EmitAggExpr`. At this point,
because the inferred type is an `AggExpr` instead of a `ScalarExpr`,
`ScalarExprEmitter::VisitVAArgExpr` is not invoked, and as a result,
`CodeGenFunction::EmitVariablyModifiedType` is also not called, leading
to the size of the VLA not being retrieved.
The solution is to move the call to
`CodeGenFunction::EmitVariablyModifiedType` into
`CodeGenFunction::EmitVAArg`, ensuring that the size of the VLA is
correctly obtained regardless of whether the expression is an `AggExpr`
or a `ScalarExpr`.
-rw-r--r-- | clang/docs/ReleaseNotes.rst | 11 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGCall.cpp | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprScalar.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 7 | ||||
-rw-r--r-- | clang/test/CodeGen/xcore-abi.c | 3 | ||||
-rw-r--r-- | clang/test/Sema/varargs.c | 5 |
7 files changed, 31 insertions, 6 deletions
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 8a48a9e..93915e5 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -704,6 +704,16 @@ Improvements to Clang's diagnostics return ptr + index < ptr; // warning } +- Clang now emits a ``-Wvarargs`` diagnostic when the second argument + to ``va_arg`` is of array type, which is an undefined behavior (#GH119360). + + .. code-block:: c++ + + void test() { + va_list va; + va_arg(va, int[10]); // warning + } + - Fix -Wdangling false positives on conditional operators (#120206). - Fixed a bug where Clang hung on an unsupported optional scope specifier ``::`` when parsing @@ -754,6 +764,7 @@ Bug Fixes in This Version the unsupported type instead of the ``register`` keyword (#GH109776). - Fixed a crash when emit ctor for global variant with flexible array init (#GH113187). - Fixed a crash when GNU statement expression contains invalid statement (#GH113468). +- Fixed a crash when passing the variable length array type to ``va_arg`` (#GH119360). - Fixed a failed assertion when using ``__attribute__((noderef))`` on an ``_Atomic``-qualified type (#GH116124). - No longer return ``false`` for ``noexcept`` expressions involving a diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 03fb7ca..1a55415 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10512,6 +10512,10 @@ def warn_second_parameter_to_va_arg_ownership_qualified : Warning< def warn_second_parameter_to_va_arg_never_compatible : Warning< "second argument to 'va_arg' is of promotable type %0; this va_arg has " "undefined behavior because arguments will be promoted to %1">, InGroup<Varargs>; +def warn_second_parameter_to_va_arg_array : Warning< + "second argument to 'va_arg' is of array type %0; " + "this va_arg has undefined behavior because arguments " + "will never be compatible with array type">, InGroup<Varargs>; def warn_return_missing_expr : Warning< "non-void %select{function|method}1 %0 should return a value">, DefaultError, diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 89e2eac..7b0ef4b 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -6090,6 +6090,8 @@ RValue CodeGenFunction::EmitVAArg(VAArgExpr *VE, Address &VAListAddr, VAListAddr = VE->isMicrosoftABI() ? EmitMSVAListRef(VE->getSubExpr()) : EmitVAListRef(VE->getSubExpr()); QualType Ty = VE->getType(); + if (Ty->isVariablyModifiedType()) + EmitVariablyModifiedType(Ty); if (VE->isMicrosoftABI()) return CGM.getABIInfo().EmitMSVAArg(*this, VAListAddr, Ty, Slot); return CGM.getABIInfo().EmitVAArg(*this, VAListAddr, Ty, Slot); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 4b71bd7..b282d4e 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -5448,11 +5448,6 @@ Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) { } Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { - QualType Ty = VE->getType(); - - if (Ty->isVariablyModifiedType()) - CGF.EmitVariablyModifiedType(Ty); - Address ArgValue = Address::invalid(); RValue ArgPtr = CGF.EmitVAArg(VE, ArgValue); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 562c98c..ae40895 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -16592,6 +16592,13 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, << TInfo->getTypeLoc().getSourceRange(); } + if (TInfo->getType()->isArrayType()) { + DiagRuntimeBehavior(TInfo->getTypeLoc().getBeginLoc(), E, + PDiag(diag::warn_second_parameter_to_va_arg_array) + << TInfo->getType() + << TInfo->getTypeLoc().getSourceRange()); + } + // Check for va_arg where arguments of the given type will be promoted // (i.e. this va_arg is guaranteed to have undefined behavior). QualType PromoteType; diff --git a/clang/test/CodeGen/xcore-abi.c b/clang/test/CodeGen/xcore-abi.c index bb8d2fe..40e2f41 100644 --- a/clang/test/CodeGen/xcore-abi.c +++ b/clang/test/CodeGen/xcore-abi.c @@ -76,7 +76,8 @@ void testva (int n, ...) { // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[V5]], ptr align 4 [[P]], i32 20, i1 false) // CHECK: call void @f(ptr noundef [[V5]]) - int* v6 = va_arg (ap, int[4]); // an unusual aggregate type + // an unusual aggregate type + int* v6 = va_arg (ap, int[4]); // expected-warning{{second argument to 'va_arg' is of array type 'int[4]'}} f(v6); // CHECK: [[I:%[a-z0-9]+]] = load ptr, ptr [[AP]] // CHECK: [[P:%[a-z0-9]+]] = load ptr, ptr [[I]] diff --git a/clang/test/Sema/varargs.c b/clang/test/Sema/varargs.c index 2cb7270..bec41dd 100644 --- a/clang/test/Sema/varargs.c +++ b/clang/test/Sema/varargs.c @@ -75,6 +75,11 @@ void f9(__builtin_va_list args) (void)__builtin_va_arg(args, enum E); // Don't warn here in C (void)__builtin_va_arg(args, short); // expected-warning {{second argument to 'va_arg' is of promotable type 'short'}} (void)__builtin_va_arg(args, char); // expected-warning {{second argument to 'va_arg' is of promotable type 'char'}} + // Don't crash on some undefined behaviors. + int n; + (void)__builtin_va_arg(args, int[10]); // expected-warning{{second argument to 'va_arg' is of array type 'int[10]'}} + (void)__builtin_va_arg(args, int[++n]); // expected-warning{{second argument to 'va_arg' is of array type 'int[++n]'}} + (void)__builtin_va_arg(args, int[n][n]); // expected-warning{{second argument to 'va_arg' is of array type 'int[n][n]'}} } void f10(int a, ...) { |