From 7365ea6ab39242c9428feae3afaa1ac88a608353 Mon Sep 17 00:00:00 2001 From: Mehdi Amini <mehdi.amini@apple.com> Date: Thu, 15 Dec 2016 04:02:31 +0000 Subject: [PATCH] Fix os_log formating with arbitrary precision and field width git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@289761 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/OSLog.cpp | 29 ++++++++++++++++++++++-- test/CodeGen/builtins.c | 49 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/lib/Analysis/OSLog.cpp b/lib/Analysis/OSLog.cpp index 04183883990..3e13a153c65 100644 --- a/lib/Analysis/OSLog.cpp +++ b/lib/Analysis/OSLog.cpp @@ -22,6 +22,9 @@ private: const Expr *E = nullptr; Optional<OSLogBufferItem::Kind> Kind; Optional<unsigned> Size; + Optional<const Expr *> Count; + Optional<const Expr *> Precision; + Optional<const Expr *> FieldWidth; unsigned char Flags = 0; }; SmallVector<ArgData, 4> ArgsData; @@ -84,7 +87,7 @@ public: ArgsData.back().Size = precision.getConstantAmount(); break; case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s" - ArgsData.back().Kind = OSLogBufferItem::CountKind; + ArgsData.back().Count = Args[precision.getArgIndex()]; break; case clang::analyze_format_string::OptionalAmount::Invalid: return false; @@ -100,7 +103,7 @@ public: ArgsData.back().Size = precision.getConstantAmount(); break; case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P" - ArgsData.back().Kind = OSLogBufferItem::CountKind; + ArgsData.back().Count = Args[precision.getArgIndex()]; break; case clang::analyze_format_string::OptionalAmount::Invalid: return false; @@ -108,8 +111,14 @@ public: break; } default: + if (FS.getPrecision().hasDataArgument()) { + ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()]; + } break; } + if (FS.getFieldWidth().hasDataArgument()) { + ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()]; + } if (FS.isPrivate()) { ArgsData.back().Flags |= OSLogBufferItem::IsPrivate; @@ -123,6 +132,22 @@ public: void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const { Layout.Items.clear(); for (auto &Data : ArgsData) { + if (Data.FieldWidth) { + CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType()); + Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth, + Size, 0); + } + if (Data.Precision) { + CharUnits Size = Ctx.getTypeSizeInChars((*Data.Precision)->getType()); + Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.Precision, + Size, 0); + } + if (Data.Count) { + // "%.*P" has an extra "count" that we insert before the argument. + CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType()); + Layout.Items.emplace_back(OSLogBufferItem::CountKind, *Data.Count, Size, + 0); + } if (Data.Size) Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size), Data.Flags); diff --git a/test/CodeGen/builtins.c b/test/CodeGen/builtins.c index c604ee54e29..a0f846b14f1 100644 --- a/test/CodeGen/builtins.c +++ b/test/CodeGen/builtins.c @@ -489,6 +489,55 @@ void test_builtin_os_log_wide(void *buf, const char *data, wchar_t *str) { __builtin_os_log_format(buf, "%S", str); } +// CHECK-LABEL: define void @test_builtin_os_log_precision_width +// CHECK: (i8* [[BUF:%.*]], i8* [[DATA:%.*]], i32 [[PRECISION:%.*]], i32 [[WIDTH:%.*]]) +void test_builtin_os_log_precision_width(void *buf, const char *data, + int precision, int width) { + volatile int len; + // CHECK: store i8* [[BUF]], i8** [[BUF_ADDR:%.*]], align 8 + // CHECK: store i8* [[DATA]], i8** [[DATA_ADDR:%.*]], align 8 + // CHECK: store i32 [[PRECISION]], i32* [[PRECISION_ADDR:%.*]], align 4 + // CHECK: store i32 [[WIDTH]], i32* [[WIDTH_ADDR:%.*]], align 4 + + // CHECK: store volatile i32 24, + len = __builtin_os_log_format_buffer_size("Hello %*.*s World", precision, width, data); + + // CHECK: [[BUF2:%.*]] = load i8*, i8** [[BUF_ADDR]] + // CHECK: [[SUMMARY:%.*]] = getelementptr i8, i8* [[BUF2]], i64 0 + // CHECK: store i8 2, i8* [[SUMMARY]] + // CHECK: [[NUM_ARGS:%.*]] = getelementptr i8, i8* [[BUF2]], i64 1 + // CHECK: store i8 3, i8* [[NUM_ARGS]] + + // CHECK: [[ARG1_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 2 + // CHECK: store i8 0, i8* [[ARG1_DESC]] + // CHECK: [[ARG1_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 3 + // CHECK: store i8 4, i8* [[ARG1_SIZE]] + // CHECK: [[ARG1:%.*]] = getelementptr i8, i8* [[BUF2]], i64 4 + // CHECK: [[ARG1_INT:%.*]] = bitcast i8* [[ARG1]] to i32* + // CHECK: [[ARG1_VAL:%.*]] = load i32, i32* [[PRECISION_ADDR]] + // CHECK: store i32 [[ARG1_VAL]], i32* [[ARG1_INT]] + + // CHECK: [[ARG2_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 8 + // CHECK: store i8 16, i8* [[ARG2_DESC]] + // CHECK: [[ARG2_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 9 + // CHECK: store i8 4, i8* [[ARG2_SIZE]] + // CHECK: [[ARG2:%.*]] = getelementptr i8, i8* [[BUF2]], i64 10 + // CHECK: [[ARG2_INT:%.*]] = bitcast i8* [[ARG2]] to i32* + // CHECK: [[ARG2_VAL:%.*]] = load i32, i32* [[WIDTH_ADDR]] + // CHECK: store i32 [[ARG2_VAL]], i32* [[ARG2_INT]] + + // CHECK: [[ARG3_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 14 + // CHECK: store i8 32, i8* [[ARG3_DESC]] + // CHECK: [[ARG3_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 15 + // CHECK: store i8 8, i8* [[ARG3_SIZE]] + // CHECK: [[ARG3:%.*]] = getelementptr i8, i8* [[BUF2]], i64 16 + // CHECK: [[ARG3_PTR:%.*]] = bitcast i8* [[ARG3]] to i8** + // CHECK: [[DATA2:%.*]] = load i8*, i8** [[DATA_ADDR]] + // CHECK: store i8* [[DATA2]], i8** [[ARG3_PTR]] + + __builtin_os_log_format(buf, "Hello %*.*s World", precision, width, data); +} + // CHECK-LABEL: define void @test_builtin_os_log_percent // CHECK: (i8* [[BUF:%.*]], i8* [[DATA1:%.*]], i8* [[DATA2:%.*]]) // Check that the %% which does not consume any argument is correctly handled -- GitLab