Author: Akira Hatanaka Date: 2025-09-23T12:21:15-07:00 New Revision: 8a0d145d90df3eefd5e54a2b04d4f4f2515e99cc
URL: https://github.com/llvm/llvm-project/commit/8a0d145d90df3eefd5e54a2b04d4f4f2515e99cc DIFF: https://github.com/llvm/llvm-project/commit/8a0d145d90df3eefd5e54a2b04d4f4f2515e99cc.diff LOG: [os_log] Fix a CodeGen crash that occurs when arguments of struct, class, or complex types are passed to _builtin_os_log_format (#158744) This change fixes the crash in clang's CodeGen by erroring out in Sema if those arguments are passed. rdar://139824423 Added: clang/test/SemaObjC/os_log.m Modified: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Sema/SemaChecking.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index dd82c3b092eb5..432517701355a 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10456,6 +10456,9 @@ def warn_format_conversion_argument_type_mismatch : Warning< "format specifies type %0 but the argument has " "%select{type|underlying type}2 %1">, InGroup<Format>; +def err_format_conversion_argument_type_mismatch : Error< + "format specifies type %0 but the argument has " + "%select{type|underlying type}2 %1">; def warn_format_conversion_argument_type_mismatch_pedantic : Extension< warn_format_conversion_argument_type_mismatch.Summary>, InGroup<FormatPedantic>; @@ -10505,6 +10508,8 @@ def warn_printf_asterisk_missing_arg : Warning< def warn_printf_asterisk_wrong_type : Warning< "field %select{width|precision}0 should have type %1, but argument has type %2">, InGroup<Format>; +def err_printf_asterisk_wrong_type : Error< + "field %select{width|precision}0 should have type %1, but argument has type %2">; def warn_printf_nonsensical_optional_amount: Warning< "%select{field width|precision}0 used with '%1' conversion specifier, resulting in undefined behavior">, InGroup<Format>; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index b3b67230f7687..e73e81c440cc1 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -7673,6 +7673,14 @@ void CheckPrintfHandler::handleInvalidMaskType(StringRef MaskType) { S.Diag(getLocationOfByte(MaskType.data()), diag::err_invalid_mask_type_size); } +// Error out if struct or complex type argments are passed to os_log. +static bool isInvalidOSLogArgTypeForCodeGen(FormatStringType FSType, + QualType T) { + if (FSType != FormatStringType::OSLog) + return false; + return T->isRecordType() || T->isComplexType(); +} + bool CheckPrintfHandler::HandleAmount( const analyze_format_string::OptionalAmount &Amt, unsigned k, const char *startSpecifier, unsigned specifierLen) { @@ -7705,11 +7713,14 @@ bool CheckPrintfHandler::HandleAmount( assert(AT.isValid()); if (!AT.matchesType(S.Context, T)) { - EmitFormatDiagnostic(S.PDiag(diag::warn_printf_asterisk_wrong_type) - << k << AT.getRepresentativeTypeName(S.Context) - << T << Arg->getSourceRange(), + unsigned DiagID = isInvalidOSLogArgTypeForCodeGen(FSType, T) + ? diag::err_printf_asterisk_wrong_type + : diag::warn_printf_asterisk_wrong_type; + EmitFormatDiagnostic(S.PDiag(DiagID) + << k << AT.getRepresentativeTypeName(S.Context) + << T << Arg->getSourceRange(), getLocationOfByte(Amt.getStart()), - /*IsStringLocation*/true, + /*IsStringLocation*/ true, getSpecifierRange(startSpecifier, specifierLen)); // Don't do any more checking. We will just emit // spurious errors. @@ -8764,7 +8775,9 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, Diag = diag::warn_format_conversion_argument_type_mismatch_confusion; break; case ArgType::NoMatch: - Diag = diag::warn_format_conversion_argument_type_mismatch; + Diag = isInvalidOSLogArgTypeForCodeGen(FSType, ExprTy) + ? diag::err_format_conversion_argument_type_mismatch + : diag::warn_format_conversion_argument_type_mismatch; break; } diff --git a/clang/test/SemaObjC/os_log.m b/clang/test/SemaObjC/os_log.m new file mode 100644 index 0000000000000..3a8a550eb2009 --- /dev/null +++ b/clang/test/SemaObjC/os_log.m @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -verify %s + +struct S { + int a[4]; +}; + +struct S s; +_Complex float cf; + +void test_builtin_os_log_invalid_arg(void *buf) { + __builtin_os_log_format(buf, "%*.*f", s, 5, 1.3); // expected-error {{field width should have type 'int', but argument has type 'struct S'}} + __builtin_os_log_format(buf, "%*.*f", 1, s, 1.3); // expected-error {{field precision should have type 'int', but argument has type 'struct S'}} + __builtin_os_log_format(buf, "%*.*f", 1, 5, s); // expected-error {{format specifies type 'double' but the argument has type 'struct S'}} + + __builtin_os_log_format(buf, "%*.*f", cf, 5, 1.3); // expected-error {{field width should have type 'int', but argument has type '_Complex float'}} + __builtin_os_log_format(buf, "%*.*f", 1, cf, 1.3); // expected-error {{field precision should have type 'int', but argument has type '_Complex float'}} + __builtin_os_log_format(buf, "%*.*f", 1, 5, cf); // expected-error {{format specifies type 'double' but the argument has type '_Complex float'}} + + __builtin_os_log_format(buf, "%*.*f", (void *)0, 5, 1.3); // expected-warning {{field width should have type 'int', but argument has type 'void *'}} + __builtin_os_log_format(buf, "%*.*f", 1, (void *)0, 1.3); // expected-warning {{field precision should have type 'int', but argument has type 'void *'}} + __builtin_os_log_format(buf, "%*.*f", 1, 5, (void *)0); // expected-warning {{format specifies type 'double' but the argument has type 'void *'}} +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
