Coverage Report

Created: 2020-09-19 12:23

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/OSLog.cpp
Line
Count
Source (jump to first uncovered line)
1
// TODO: header template
2
3
#include "clang/AST/OSLog.h"
4
#include "clang/AST/Attr.h"
5
#include "clang/AST/Decl.h"
6
#include "clang/AST/DeclCXX.h"
7
#include "clang/AST/ExprObjC.h"
8
#include "clang/AST/FormatString.h"
9
#include "clang/Basic/Builtins.h"
10
#include "llvm/ADT/SmallBitVector.h"
11
12
using namespace clang;
13
14
using clang::analyze_os_log::OSLogBufferItem;
15
using clang::analyze_os_log::OSLogBufferLayout;
16
17
namespace {
18
class OSLogFormatStringHandler
19
    : public analyze_format_string::FormatStringHandler {
20
private:
21
  struct ArgData {
22
    const Expr *E = nullptr;
23
    Optional<OSLogBufferItem::Kind> Kind;
24
    Optional<unsigned> Size;
25
    Optional<const Expr *> Count;
26
    Optional<const Expr *> Precision;
27
    Optional<const Expr *> FieldWidth;
28
    unsigned char Flags = 0;
29
    StringRef MaskType;
30
  };
31
  SmallVector<ArgData, 4> ArgsData;
32
  ArrayRef<const Expr *> Args;
33
34
  OSLogBufferItem::Kind
35
3.00k
  getKind(analyze_format_string::ConversionSpecifier::Kind K) {
36
3.00k
    switch (K) {
37
829
    case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"
38
829
      return OSLogBufferItem::StringKind;
39
8
    case clang::analyze_format_string::ConversionSpecifier::SArg: // "%S"
40
8
      return OSLogBufferItem::WideStringKind;
41
8
    case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"
42
8
      return OSLogBufferItem::PointerKind;
43
21
    case clang::analyze_format_string::ConversionSpecifier::ObjCObjArg: // "%@"
44
21
      return OSLogBufferItem::ObjCObjKind;
45
6
    case clang::analyze_format_string::ConversionSpecifier::PrintErrno: // "%m"
46
6
      return OSLogBufferItem::ErrnoKind;
47
2.13k
    default:
48
2.13k
      return OSLogBufferItem::ScalarKind;
49
0
    }
50
3.00k
    }
51
3.00k
  }
52
53
public:
54
1.22k
  OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {
55
1.22k
    ArgsData.reserve(Args.size());
56
1.22k
  }
57
58
  bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
59
                             const char *StartSpecifier,
60
3.01k
                             unsigned SpecifierLen) override {
61
3.01k
    if (!FS.consumesDataArgument() &&
62
14
        FS.getConversionSpecifier().getKind() !=
63
14
            clang::analyze_format_string::ConversionSpecifier::PrintErrno)
64
8
      return true;
65
3.00k
66
3.00k
    ArgsData.emplace_back();
67
3.00k
    unsigned ArgIndex = FS.getArgIndex();
68
3.00k
    if (ArgIndex < Args.size())
69
3.00k
      ArgsData.back().E = Args[ArgIndex];
70
3.00k
71
    // First get the Kind
72
3.00k
    ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());
73
3.00k
    if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&
74
3.00k
        !ArgsData.back().E) {
75
      // missing argument
76
0
      ArgsData.pop_back();
77
0
      return false;
78
0
    }
79
3.00k
80
3.00k
    switch (FS.getConversionSpecifier().getKind()) {
81
837
    case clang::analyze_format_string::ConversionSpecifier::sArg:   // "%s"
82
837
    case clang::analyze_format_string::ConversionSpecifier::SArg: { // "%S"
83
837
      auto &precision = FS.getPrecision();
84
837
      switch (precision.getHowSpecified()) {
85
829
      case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%s"
86
829
        break;
87
0
      case clang::analyze_format_string::OptionalAmount::Constant: // "%.16s"
88
0
        ArgsData.back().Size = precision.getConstantAmount();
89
0
        break;
90
8
      case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s"
91
8
        ArgsData.back().Count = Args[precision.getArgIndex()];
92
8
        break;
93
0
      case clang::analyze_format_string::OptionalAmount::Invalid:
94
0
        return false;
95
837
      }
96
837
      break;
97
837
    }
98
8
    case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"
99
8
      auto &precision = FS.getPrecision();
100
8
      switch (precision.getHowSpecified()) {
101
0
      case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%P"
102
0
        return false; // length must be supplied with pointer format specifier
103
8
      case clang::analyze_format_string::OptionalAmount::Constant: // "%.16P"
104
8
        ArgsData.back().Size = precision.getConstantAmount();
105
8
        break;
106
0
      case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P"
107
0
        ArgsData.back().Count = Args[precision.getArgIndex()];
108
0
        break;
109
0
      case clang::analyze_format_string::OptionalAmount::Invalid:
110
0
        return false;
111
8
      }
112
8
      break;
113
8
    }
114
2.16k
    default:
115
2.16k
      if (FS.getPrecision().hasDataArgument()) {
116
0
        ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];
117
0
      }
118
2.16k
      break;
119
3.00k
    }
120
3.00k
    if (FS.getFieldWidth().hasDataArgument()) {
121
8
      ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];
122
8
    }
123
3.00k
124
3.00k
    if (FS.isSensitive())
125
4
      ArgsData.back().Flags |= OSLogBufferItem::IsSensitive;
126
3.00k
    else if (FS.isPrivate())
127
14
      ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;
128
2.99k
    else if (FS.isPublic())
129
13
      ArgsData.back().Flags |= OSLogBufferItem::IsPublic;
130
3.00k
131
3.00k
    ArgsData.back().MaskType = FS.getMaskType();
132
3.00k
    return true;
133
3.00k
  }
134
135
1.22k
  void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {
136
1.22k
    Layout.Items.clear();
137
3.00k
    for (auto &Data : ArgsData) {
138
3.00k
      if (!Data.MaskType.empty()) {
139
10
        CharUnits Size = CharUnits::fromQuantity(8);
140
10
        Layout.Items.emplace_back(OSLogBufferItem::MaskKind, nullptr,
141
10
                                  Size, 0, Data.MaskType);
142
10
      }
143
3.00k
144
3.00k
      if (Data.FieldWidth) {
145
8
        CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());
146
8
        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth,
147
8
                                  Size, 0);
148
8
      }
149
3.00k
      if (Data.Precision) {
150
0
        CharUnits Size = Ctx.getTypeSizeInChars((*Data.Precision)->getType());
151
0
        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.Precision,
152
0
                                  Size, 0);
153
0
      }
154
3.00k
      if (Data.Count) {
155
        // "%.*P" has an extra "count" that we insert before the argument.
156
8
        CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());
157
8
        Layout.Items.emplace_back(OSLogBufferItem::CountKind, *Data.Count, Size,
158
8
                                  0);
159
8
      }
160
3.00k
      if (Data.Size)
161
8
        Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size),
162
8
                                  Data.Flags);
163
3.00k
      if (Data.Kind) {
164
3.00k
        CharUnits Size;
165
3.00k
        if (*Data.Kind == OSLogBufferItem::ErrnoKind)
166
6
          Size = CharUnits::Zero();
167
3.00k
        else
168
3.00k
          Size = Ctx.getTypeSizeInChars(Data.E->getType());
169
3.00k
        Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);
170
0
      } else {
171
0
        auto Size = Ctx.getTypeSizeInChars(Data.E->getType());
172
0
        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E, Size,
173
0
                                  Data.Flags);
174
0
      }
175
3.00k
    }
176
1.22k
  }
177
};
178
} // end anonymous namespace
179
180
bool clang::analyze_os_log::computeOSLogBufferLayout(
181
1.22k
    ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {
182
1.22k
  ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() + E->getNumArgs());
183
1.22k
184
1.22k
  const Expr *StringArg;
185
1.22k
  ArrayRef<const Expr *> VarArgs;
186
1.22k
  switch (E->getBuiltinCallee()) {
187
1.16k
  case Builtin::BI__builtin_os_log_format_buffer_size:
188
1.16k
    assert(E->getNumArgs() >= 1 &&
189
1.16k
           "__builtin_os_log_format_buffer_size takes at least 1 argument");
190
1.16k
    StringArg = E->getArg(0);
191
1.16k
    VarArgs = Args.slice(1);
192
1.16k
    break;
193
59
  case Builtin::BI__builtin_os_log_format:
194
59
    assert(E->getNumArgs() >= 2 &&
195
59
           "__builtin_os_log_format takes at least 2 arguments");
196
59
    StringArg = E->getArg(1);
197
59
    VarArgs = Args.slice(2);
198
59
    break;
199
0
  default:
200
0
    llvm_unreachable("non-os_log builtin passed to computeOSLogBufferLayout");
201
1.22k
  }
202
1.22k
203
1.22k
  const StringLiteral *Lit = cast<StringLiteral>(StringArg->IgnoreParenCasts());
204
1.22k
  assert(Lit && (Lit->isAscii() || Lit->isUTF8()));
205
1.22k
  StringRef Data = Lit->getString();
206
1.22k
  OSLogFormatStringHandler H(VarArgs);
207
1.22k
  ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),
208
1.22k
                    Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);
209
1.22k
210
1.22k
  H.computeLayout(Ctx, Layout);
211
1.22k
  return true;
212
1.22k
}