Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/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
123
  getKind(analyze_format_string::ConversionSpecifier::Kind K) {
36
123
    switch (K) {
37
123
    case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"
38
64
      return OSLogBufferItem::StringKind;
39
123
    case clang::analyze_format_string::ConversionSpecifier::SArg: // "%S"
40
8
      return OSLogBufferItem::WideStringKind;
41
123
    case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"
42
10
      return OSLogBufferItem::PointerKind;
43
123
    case clang::analyze_format_string::ConversionSpecifier::ObjCObjArg: // "%@"
44
3
      return OSLogBufferItem::ObjCObjKind;
45
123
    case clang::analyze_format_string::ConversionSpecifier::PrintErrno: // "%m"
46
6
      return OSLogBufferItem::ErrnoKind;
47
123
    default:
48
32
      return OSLogBufferItem::ScalarKind;
49
123
    }
50
123
    }
51
123
  }
52
53
public:
54
329
  OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {
55
329
    ArgsData.reserve(Args.size());
56
329
  }
57
58
  virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
59
                                     const char *StartSpecifier,
60
131
                                     unsigned SpecifierLen) {
61
131
    if (!FS.consumesDataArgument() &&
62
131
        FS.getConversionSpecifier().getKind() !=
63
14
            clang::analyze_format_string::ConversionSpecifier::PrintErrno)
64
8
      return true;
65
123
66
123
    ArgsData.emplace_back();
67
123
    unsigned ArgIndex = FS.getArgIndex();
68
123
    if (ArgIndex < Args.size())
69
117
      ArgsData.back().E = Args[ArgIndex];
70
123
71
123
    // First get the Kind
72
123
    ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());
73
123
    if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&
74
123
        
!ArgsData.back().E117
) {
75
0
      // missing argument
76
0
      ArgsData.pop_back();
77
0
      return false;
78
0
    }
79
123
80
123
    switch (FS.getConversionSpecifier().getKind()) {
81
123
    case clang::analyze_format_string::ConversionSpecifier::sArg:   // "%s"
82
72
    case clang::analyze_format_string::ConversionSpecifier::SArg: { // "%S"
83
72
      auto &precision = FS.getPrecision();
84
72
      switch (precision.getHowSpecified()) {
85
72
      case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%s"
86
64
        break;
87
72
      case clang::analyze_format_string::OptionalAmount::Constant: // "%.16s"
88
0
        ArgsData.back().Size = precision.getConstantAmount();
89
0
        break;
90
72
      case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s"
91
8
        ArgsData.back().Count = Args[precision.getArgIndex()];
92
8
        break;
93
72
      case clang::analyze_format_string::OptionalAmount::Invalid:
94
0
        return false;
95
72
      }
96
72
      break;
97
72
    }
98
72
    case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"
99
10
      auto &precision = FS.getPrecision();
100
10
      switch (precision.getHowSpecified()) {
101
10
      case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%P"
102
0
        return false; // length must be supplied with pointer format specifier
103
10
      case clang::analyze_format_string::OptionalAmount::Constant: // "%.16P"
104
10
        ArgsData.back().Size = precision.getConstantAmount();
105
10
        break;
106
10
      case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P"
107
0
        ArgsData.back().Count = Args[precision.getArgIndex()];
108
0
        break;
109
10
      case clang::analyze_format_string::OptionalAmount::Invalid:
110
0
        return false;
111
10
      }
112
10
      break;
113
10
    }
114
41
    default:
115
41
      if (FS.getPrecision().hasDataArgument()) {
116
0
        ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];
117
0
      }
118
41
      break;
119
123
    }
120
123
    if (FS.getFieldWidth().hasDataArgument()) {
121
8
      ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];
122
8
    }
123
123
124
123
    if (FS.isSensitive())
125
4
      ArgsData.back().Flags |= OSLogBufferItem::IsSensitive;
126
119
    else if (FS.isPrivate())
127
16
      ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;
128
103
    else if (FS.isPublic())
129
16
      ArgsData.back().Flags |= OSLogBufferItem::IsPublic;
130
123
131
123
    ArgsData.back().MaskType = FS.getMaskType();
132
123
    return true;
133
123
  }
134
135
329
  void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {
136
329
    Layout.Items.clear();
137
329
    for (auto &Data : ArgsData) {
138
123
      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
123
144
123
      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
123
      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
123
      if (Data.Count) {
155
8
        // "%.*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
123
      if (Data.Size)
161
10
        Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size),
162
10
                                  Data.Flags);
163
123
      if (Data.Kind) {
164
123
        CharUnits Size;
165
123
        if (*Data.Kind == OSLogBufferItem::ErrnoKind)
166
6
          Size = CharUnits::Zero();
167
117
        else
168
117
          Size = Ctx.getTypeSizeInChars(Data.E->getType());
169
123
        Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);
170
123
      } 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
123
    }
176
329
  }
177
};
178
} // end anonymous namespace
179
180
bool clang::analyze_os_log::computeOSLogBufferLayout(
181
329
    ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {
182
329
  ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() + E->getNumArgs());
183
329
184
329
  const Expr *StringArg;
185
329
  ArrayRef<const Expr *> VarArgs;
186
329
  switch (E->getBuiltinCallee()) {
187
329
  case Builtin::BI__builtin_os_log_format_buffer_size:
188
160
    assert(E->getNumArgs() >= 1 &&
189
160
           "__builtin_os_log_format_buffer_size takes at least 1 argument");
190
160
    StringArg = E->getArg(0);
191
160
    VarArgs = Args.slice(1);
192
160
    break;
193
329
  case Builtin::BI__builtin_os_log_format:
194
169
    assert(E->getNumArgs() >= 2 &&
195
169
           "__builtin_os_log_format takes at least 2 arguments");
196
169
    StringArg = E->getArg(1);
197
169
    VarArgs = Args.slice(2);
198
169
    break;
199
329
  default:
200
0
    llvm_unreachable("non-os_log builtin passed to computeOSLogBufferLayout");
201
329
  }
202
329
203
329
  const StringLiteral *Lit = cast<StringLiteral>(StringArg->IgnoreParenCasts());
204
329
  assert(Lit && (Lit->isAscii() || Lit->isUTF8()));
205
329
  StringRef Data = Lit->getString();
206
329
  OSLogFormatStringHandler H(VarArgs);
207
329
  ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),
208
329
                    Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);
209
329
210
329
  H.computeLayout(Ctx, Layout);
211
329
  return true;
212
329
}