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