Coverage Report

Created: 2021-09-21 08:58

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Frontend/SerializedDiagnosticReader.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- SerializedDiagnosticReader.cpp - Reads diagnostics -----------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "clang/Frontend/SerializedDiagnosticReader.h"
10
#include "clang/Basic/FileManager.h"
11
#include "clang/Basic/FileSystemOptions.h"
12
#include "clang/Frontend/SerializedDiagnostics.h"
13
#include "llvm/ADT/Optional.h"
14
#include "llvm/ADT/SmallVector.h"
15
#include "llvm/ADT/StringRef.h"
16
#include "llvm/Bitstream/BitCodes.h"
17
#include "llvm/Bitstream/BitstreamReader.h"
18
#include "llvm/Support/Compiler.h"
19
#include "llvm/Support/ErrorHandling.h"
20
#include "llvm/Support/ErrorOr.h"
21
#include "llvm/Support/ManagedStatic.h"
22
#include <cstdint>
23
#include <system_error>
24
25
using namespace clang;
26
using namespace serialized_diags;
27
28
17
std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
29
  // Open the diagnostics file.
30
17
  FileSystemOptions FO;
31
17
  FileManager FileMgr(FO);
32
33
17
  auto Buffer = FileMgr.getBufferForFile(File);
34
17
  if (!Buffer)
35
0
    return SDError::CouldNotLoad;
36
37
17
  llvm::BitstreamCursor Stream(**Buffer);
38
17
  Optional<llvm::BitstreamBlockInfo> BlockInfo;
39
40
17
  if (Stream.AtEndOfStream())
41
1
    return SDError::InvalidSignature;
42
43
  // Sniff for the signature.
44
64
  
for (unsigned char C : {'D', 'I', 'A', 'G'})16
{
45
64
    if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = Stream.Read(8)) {
46
64
      if (Res.get() == C)
47
64
        continue;
48
64
    } else {
49
      // FIXME this drops the error on the floor.
50
0
      consumeError(Res.takeError());
51
0
    }
52
0
    return SDError::InvalidSignature;
53
64
  }
54
55
  // Read the top level blocks.
56
88
  
while (16
!Stream.AtEndOfStream()) {
57
72
    if (Expected<unsigned> Res = Stream.ReadCode()) {
58
72
      if (Res.get() != llvm::bitc::ENTER_SUBBLOCK)
59
0
        return SDError::InvalidDiagnostics;
60
72
    } else {
61
      // FIXME this drops the error on the floor.
62
0
      consumeError(Res.takeError());
63
0
      return SDError::InvalidDiagnostics;
64
0
    }
65
66
72
    std::error_code EC;
67
72
    Expected<unsigned> MaybeSubBlockID = Stream.ReadSubBlockID();
68
72
    if (!MaybeSubBlockID) {
69
      // FIXME this drops the error on the floor.
70
0
      consumeError(MaybeSubBlockID.takeError());
71
0
      return SDError::InvalidDiagnostics;
72
0
    }
73
74
72
    switch (MaybeSubBlockID.get()) {
75
16
    case llvm::bitc::BLOCKINFO_BLOCK_ID: {
76
16
      Expected<Optional<llvm::BitstreamBlockInfo>> MaybeBlockInfo =
77
16
          Stream.ReadBlockInfoBlock();
78
16
      if (!MaybeBlockInfo) {
79
        // FIXME this drops the error on the floor.
80
0
        consumeError(MaybeBlockInfo.takeError());
81
0
        return SDError::InvalidDiagnostics;
82
0
      }
83
16
      BlockInfo = std::move(MaybeBlockInfo.get());
84
16
    }
85
16
      if (!BlockInfo)
86
0
        return SDError::MalformedBlockInfoBlock;
87
16
      Stream.setBlockInfo(&*BlockInfo);
88
16
      continue;
89
16
    case BLOCK_META:
90
16
      if ((EC = readMetaBlock(Stream)))
91
0
        return EC;
92
16
      continue;
93
40
    case BLOCK_DIAG:
94
40
      if ((EC = readDiagnosticBlock(Stream)))
95
0
        return EC;
96
40
      continue;
97
40
    default:
98
0
      if (llvm::Error Err = Stream.SkipBlock()) {
99
        // FIXME this drops the error on the floor.
100
0
        consumeError(std::move(Err));
101
0
        return SDError::MalformedTopLevelBlock;
102
0
      }
103
0
      continue;
104
72
    }
105
72
  }
106
16
  return {};
107
16
}
108
109
enum class SerializedDiagnosticReader::Cursor {
110
  Record = 1,
111
  BlockEnd,
112
  BlockBegin
113
};
114
115
llvm::ErrorOr<SerializedDiagnosticReader::Cursor>
116
SerializedDiagnosticReader::skipUntilRecordOrBlock(
117
348
    llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) {
118
348
  BlockOrRecordID = 0;
119
120
348
  while (!Stream.AtEndOfStream()) {
121
348
    unsigned Code;
122
348
    if (Expected<unsigned> Res = Stream.ReadCode())
123
348
      Code = Res.get();
124
0
    else
125
0
      return llvm::errorToErrorCode(Res.takeError());
126
127
348
    if (Code >= static_cast<unsigned>(llvm::bitc::FIRST_APPLICATION_ABBREV)) {
128
      // We found a record.
129
216
      BlockOrRecordID = Code;
130
216
      return Cursor::Record;
131
216
    }
132
132
    switch (static_cast<llvm::bitc::FixedAbbrevIDs>(Code)) {
133
38
    case llvm::bitc::ENTER_SUBBLOCK:
134
38
      if (Expected<unsigned> Res = Stream.ReadSubBlockID())
135
38
        BlockOrRecordID = Res.get();
136
0
      else
137
0
        return llvm::errorToErrorCode(Res.takeError());
138
38
      return Cursor::BlockBegin;
139
140
94
    case llvm::bitc::END_BLOCK:
141
94
      if (Stream.ReadBlockEnd())
142
0
        return SDError::InvalidDiagnostics;
143
94
      return Cursor::BlockEnd;
144
145
0
    case llvm::bitc::DEFINE_ABBREV:
146
0
      if (llvm::Error Err = Stream.ReadAbbrevRecord())
147
0
        return llvm::errorToErrorCode(std::move(Err));
148
0
      continue;
149
150
0
    case llvm::bitc::UNABBREV_RECORD:
151
0
      return SDError::UnsupportedConstruct;
152
153
0
    case llvm::bitc::FIRST_APPLICATION_ABBREV:
154
0
      llvm_unreachable("Unexpected abbrev id.");
155
132
    }
156
132
  }
157
158
0
  return SDError::InvalidDiagnostics;
159
348
}
160
161
std::error_code
162
16
SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
163
16
  if (llvm::Error Err =
164
16
          Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {
165
    // FIXME this drops the error on the floor.
166
0
    consumeError(std::move(Err));
167
0
    return SDError::MalformedMetadataBlock;
168
0
  }
169
170
16
  bool VersionChecked = false;
171
172
32
  while (true) {
173
32
    unsigned BlockOrCode = 0;
174
32
    llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
175
32
    if (!Res)
176
0
      Res.getError();
177
178
32
    switch (Res.get()) {
179
16
    case Cursor::Record:
180
16
      break;
181
0
    case Cursor::BlockBegin:
182
0
      if (llvm::Error Err = Stream.SkipBlock()) {
183
        // FIXME this drops the error on the floor.
184
0
        consumeError(std::move(Err));
185
0
        return SDError::MalformedMetadataBlock;
186
0
      }
187
0
      LLVM_FALLTHROUGH;
188
16
    case Cursor::BlockEnd:
189
16
      if (!VersionChecked)
190
0
        return SDError::MissingVersion;
191
16
      return {};
192
32
    }
193
194
16
    SmallVector<uint64_t, 1> Record;
195
16
    Expected<unsigned> MaybeRecordID = Stream.readRecord(BlockOrCode, Record);
196
16
    if (!MaybeRecordID)
197
0
      return errorToErrorCode(MaybeRecordID.takeError());
198
16
    unsigned RecordID = MaybeRecordID.get();
199
200
16
    if (RecordID == RECORD_VERSION) {
201
16
      if (Record.size() < 1)
202
0
        return SDError::MissingVersion;
203
16
      if (Record[0] > VersionNumber)
204
0
        return SDError::VersionMismatch;
205
16
      VersionChecked = true;
206
16
    }
207
16
  }
208
16
}
209
210
std::error_code
211
78
SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {
212
78
  if (llvm::Error Err =
213
78
          Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {
214
    // FIXME this drops the error on the floor.
215
0
    consumeError(std::move(Err));
216
0
    return SDError::MalformedDiagnosticBlock;
217
0
  }
218
219
78
  std::error_code EC;
220
78
  if ((EC = visitStartOfDiagnostic()))
221
0
    return EC;
222
223
78
  SmallVector<uint64_t, 16> Record;
224
316
  while (true) {
225
316
    unsigned BlockOrCode = 0;
226
316
    llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
227
316
    if (!Res)
228
0
      Res.getError();
229
230
316
    switch (Res.get()) {
231
38
    case Cursor::BlockBegin:
232
      // The only blocks we care about are subdiagnostics.
233
38
      if (BlockOrCode == serialized_diags::BLOCK_DIAG) {
234
38
        if ((EC = readDiagnosticBlock(Stream)))
235
0
          return EC;
236
38
      } else 
if (llvm::Error 0
Err0
= Stream.SkipBlock()) {
237
        // FIXME this drops the error on the floor.
238
0
        consumeError(std::move(Err));
239
0
        return SDError::MalformedSubBlock;
240
0
      }
241
38
      continue;
242
78
    case Cursor::BlockEnd:
243
78
      if ((EC = visitEndOfDiagnostic()))
244
0
        return EC;
245
78
      return {};
246
200
    case Cursor::Record:
247
200
      break;
248
316
    }
249
250
    // Read the record.
251
200
    Record.clear();
252
200
    StringRef Blob;
253
200
    Expected<unsigned> MaybeRecID =
254
200
        Stream.readRecord(BlockOrCode, Record, &Blob);
255
200
    if (!MaybeRecID)
256
0
      return errorToErrorCode(MaybeRecID.takeError());
257
200
    unsigned RecID = MaybeRecID.get();
258
259
200
    if (RecID < serialized_diags::RECORD_FIRST ||
260
200
        RecID > serialized_diags::RECORD_LAST)
261
0
      continue;
262
263
200
    switch ((RecordIDs)RecID) {
264
30
    case RECORD_CATEGORY:
265
      // A category has ID and name size.
266
30
      if (Record.size() != 2)
267
0
        return SDError::MalformedDiagnosticRecord;
268
30
      if ((EC = visitCategoryRecord(Record[0], Blob)))
269
0
        return EC;
270
30
      continue;
271
78
    case RECORD_DIAG:
272
      // A diagnostic has severity, location (4), category, flag, and message
273
      // size.
274
78
      if (Record.size() != 8)
275
0
        return SDError::MalformedDiagnosticRecord;
276
78
      if ((EC = visitDiagnosticRecord(
277
78
               Record[0], Location(Record[1], Record[2], Record[3], Record[4]),
278
78
               Record[5], Record[6], Blob)))
279
0
        return EC;
280
78
      continue;
281
78
    case RECORD_DIAG_FLAG:
282
      // A diagnostic flag has ID and name size.
283
16
      if (Record.size() != 2)
284
0
        return SDError::MalformedDiagnosticRecord;
285
16
      if ((EC = visitDiagFlagRecord(Record[0], Blob)))
286
0
        return EC;
287
16
      continue;
288
28
    case RECORD_FILENAME:
289
      // A filename has ID, size, timestamp, and name size. The size and
290
      // timestamp are legacy fields that are always zero these days.
291
28
      if (Record.size() != 4)
292
0
        return SDError::MalformedDiagnosticRecord;
293
28
      if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob)))
294
0
        return EC;
295
28
      continue;
296
28
    case RECORD_FIXIT:
297
      // A fixit has two locations (4 each) and message size.
298
12
      if (Record.size() != 9)
299
0
        return SDError::MalformedDiagnosticRecord;
300
12
      if ((EC = visitFixitRecord(
301
12
               Location(Record[0], Record[1], Record[2], Record[3]),
302
12
               Location(Record[4], Record[5], Record[6], Record[7]), Blob)))
303
0
        return EC;
304
12
      continue;
305
36
    case RECORD_SOURCE_RANGE:
306
      // A source range is two locations (4 each).
307
36
      if (Record.size() != 8)
308
0
        return SDError::MalformedDiagnosticRecord;
309
36
      if ((EC = visitSourceRangeRecord(
310
36
               Location(Record[0], Record[1], Record[2], Record[3]),
311
36
               Location(Record[4], Record[5], Record[6], Record[7]))))
312
0
        return EC;
313
36
      continue;
314
36
    case RECORD_VERSION:
315
      // A version is just a number.
316
0
      if (Record.size() != 1)
317
0
        return SDError::MalformedDiagnosticRecord;
318
0
      if ((EC = visitVersionRecord(Record[0])))
319
0
        return EC;
320
0
      continue;
321
200
    }
322
200
  }
323
78
}
324
325
namespace {
326
327
class SDErrorCategoryType final : public std::error_category {
328
0
  const char *name() const noexcept override {
329
0
    return "clang.serialized_diags";
330
0
  }
331
332
1
  std::string message(int IE) const override {
333
1
    auto E = static_cast<SDError>(IE);
334
1
    switch (E) {
335
0
    case SDError::CouldNotLoad:
336
0
      return "Failed to open diagnostics file";
337
1
    case SDError::InvalidSignature:
338
1
      return "Invalid diagnostics signature";
339
0
    case SDError::InvalidDiagnostics:
340
0
      return "Parse error reading diagnostics";
341
0
    case SDError::MalformedTopLevelBlock:
342
0
      return "Malformed block at top-level of diagnostics";
343
0
    case SDError::MalformedSubBlock:
344
0
      return "Malformed sub-block in a diagnostic";
345
0
    case SDError::MalformedBlockInfoBlock:
346
0
      return "Malformed BlockInfo block";
347
0
    case SDError::MalformedMetadataBlock:
348
0
      return "Malformed Metadata block";
349
0
    case SDError::MalformedDiagnosticBlock:
350
0
      return "Malformed Diagnostic block";
351
0
    case SDError::MalformedDiagnosticRecord:
352
0
      return "Malformed Diagnostic record";
353
0
    case SDError::MissingVersion:
354
0
      return "No version provided in diagnostics";
355
0
    case SDError::VersionMismatch:
356
0
      return "Unsupported diagnostics version";
357
0
    case SDError::UnsupportedConstruct:
358
0
      return "Bitcode constructs that are not supported in diagnostics appear";
359
0
    case SDError::HandlerFailed:
360
0
      return "Generic error occurred while handling a record";
361
1
    }
362
0
    llvm_unreachable("Unknown error type!");
363
0
  }
364
};
365
366
} // namespace
367
368
static llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory;
369
2
const std::error_category &clang::serialized_diags::SDErrorCategory() {
370
2
  return *ErrorCategory;
371
2
}