https://github.com/ahatanak created https://github.com/llvm/llvm-project/pull/158744
This change fixes a crash in clang's CodeGen by ensuring that those arguments are ignored. rdar://139824423 >From 2100dca9ad30277bbdb53384358245fd1566a9cb Mon Sep 17 00:00:00 2001 From: Akira Hatanaka <ahata...@gmail.com> Date: Fri, 5 Sep 2025 07:01:00 -0700 Subject: [PATCH] [os_log] Fix a CodeGen crash that occurs when arguments of struct, class, or complex types are passed to _builtin_os_log_format This change fixes a crash in clang's CodeGen by ensuring that those arguments are ignored. rdar://139824423 --- clang/lib/AST/OSLog.cpp | 48 ++++++++++++++++++++++----------- clang/test/CodeGenObjC/os_log.m | 23 ++++++++++++++++ 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/clang/lib/AST/OSLog.cpp b/clang/lib/AST/OSLog.cpp index 91f8410e89e86..d228d297dd2ca 100644 --- a/clang/lib/AST/OSLog.cpp +++ b/clang/lib/AST/OSLog.cpp @@ -70,22 +70,31 @@ class OSLogFormatStringHandler bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *StartSpecifier, unsigned SpecifierLen, const TargetInfo &) override { + // Set the argument expression. Arguments of struct/class/complex types are + // ignored. + auto CheckAndSetArgExpr = [&](unsigned Idx, auto &ArgE) { + const Expr *E = Args[Idx]; + if (E && (E->getType()->isRecordType() || E->getType()->isComplexType())) + return false; + ArgE = E; + return true; + }; + if (!FS.consumesDataArgument() && FS.getConversionSpecifier().getKind() != clang::analyze_format_string::ConversionSpecifier::PrintErrno) return true; - ArgsData.emplace_back(); + ArgData ArgD; unsigned ArgIndex = FS.getArgIndex(); if (ArgIndex < Args.size()) - ArgsData.back().E = Args[ArgIndex]; + if (!CheckAndSetArgExpr(ArgIndex, ArgD.E)) + return true; // First get the Kind - ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind()); - if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind && - !ArgsData.back().E) { + ArgD.Kind = getKind(FS.getConversionSpecifier().getKind()); + if (ArgD.Kind != OSLogBufferItem::ErrnoKind && !ArgD.E) { // missing argument - ArgsData.pop_back(); return false; } @@ -97,10 +106,11 @@ class OSLogFormatStringHandler case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%s" break; case clang::analyze_format_string::OptionalAmount::Constant: // "%.16s" - ArgsData.back().Size = precision.getConstantAmount(); + ArgD.Size = precision.getConstantAmount(); break; case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s" - ArgsData.back().Count = Args[precision.getArgIndex()]; + if (!CheckAndSetArgExpr(precision.getArgIndex(), ArgD.Count)) + return true; break; case clang::analyze_format_string::OptionalAmount::Invalid: return false; @@ -113,10 +123,11 @@ class OSLogFormatStringHandler case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%P" return false; // length must be supplied with pointer format specifier case clang::analyze_format_string::OptionalAmount::Constant: // "%.16P" - ArgsData.back().Size = precision.getConstantAmount(); + ArgD.Size = precision.getConstantAmount(); break; case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P" - ArgsData.back().Count = Args[precision.getArgIndex()]; + if (!CheckAndSetArgExpr(precision.getArgIndex(), ArgD.Count)) + return true; break; case clang::analyze_format_string::OptionalAmount::Invalid: return false; @@ -125,22 +136,27 @@ class OSLogFormatStringHandler } default: if (FS.getPrecision().hasDataArgument()) { - ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()]; + if (!CheckAndSetArgExpr(FS.getPrecision().getArgIndex(), + ArgD.Precision)) + return true; } break; } if (FS.getFieldWidth().hasDataArgument()) { - ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()]; + if (!CheckAndSetArgExpr(FS.getFieldWidth().getArgIndex(), + ArgD.FieldWidth)) + return true; } if (FS.isSensitive()) - ArgsData.back().Flags |= OSLogBufferItem::IsSensitive; + ArgD.Flags |= OSLogBufferItem::IsSensitive; else if (FS.isPrivate()) - ArgsData.back().Flags |= OSLogBufferItem::IsPrivate; + ArgD.Flags |= OSLogBufferItem::IsPrivate; else if (FS.isPublic()) - ArgsData.back().Flags |= OSLogBufferItem::IsPublic; + ArgD.Flags |= OSLogBufferItem::IsPublic; - ArgsData.back().MaskType = FS.getMaskType(); + ArgD.MaskType = FS.getMaskType(); + ArgsData.push_back(ArgD); return true; } diff --git a/clang/test/CodeGenObjC/os_log.m b/clang/test/CodeGenObjC/os_log.m index 837883ec4bb75..00229a746304c 100644 --- a/clang/test/CodeGenObjC/os_log.m +++ b/clang/test/CodeGenObjC/os_log.m @@ -13,6 +13,13 @@ + (id)m1; C *c; +struct S { + int a[4]; +}; + +struct S s; +_Complex float cf; + @class NSString; extern __attribute__((visibility("default"))) NSString *GenString(void); void os_log_pack_send(void *); @@ -123,3 +130,19 @@ void test_builtin_os_log5(void *buf) { __builtin_os_log_format(buf, "capabilities: %@", (0, GenString())); os_log_pack_send(buf); } + +// CHECK-LABEL: define void @test_builtin_os_log6( +// CHECK: call void @__os_log_helper_1_0_0( + +void test_builtin_os_log6(void *buf) { + __builtin_os_log_format(buf, "%.*s %.*P %*.*f", s, s, s, s, s, s, s); +} + +// CHECK-LABEL: define linkonce_odr hidden void @__os_log_helper_1_0_0( + +// CHECK-LABEL: define void @test_builtin_os_log7( +// CHECK: call void @__os_log_helper_1_0_0( + +void test_builtin_os_log7(void *buf) { + __builtin_os_log_format(buf, "%.*s %.*P %*.*f", cf, cf, cf, cf, cf, cf, cf); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits