Bug Summary

File:tools/llvm-pdbdump/Diff.cpp
Warning:line 69, column 5
Called C++ object pointer is null

Annotated Source Code

1//===- Diff.cpp - PDB diff utility ------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "Diff.h"
11
12#include "StreamUtil.h"
13#include "llvm-pdbdump.h"
14
15#include "llvm/DebugInfo/PDB/Native/Formatters.h"
16#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
17#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
18#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
19#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
20
21#include "llvm/Support/FormatAdapters.h"
22#include "llvm/Support/FormatProviders.h"
23#include "llvm/Support/FormatVariadic.h"
24
25using namespace llvm;
26using namespace llvm::pdb;
27
28namespace llvm {
29template <> struct format_provider<PdbRaw_FeatureSig> {
30 static void format(const PdbRaw_FeatureSig &Sig, raw_ostream &Stream,
31 StringRef Style) {
32 switch (Sig) {
33 case PdbRaw_FeatureSig::MinimalDebugInfo:
34 Stream << "MinimalDebugInfo";
35 break;
36 case PdbRaw_FeatureSig::NoTypeMerge:
37 Stream << "NoTypeMerge";
38 break;
39 case PdbRaw_FeatureSig::VC110:
40 Stream << "VC110";
41 break;
42 case PdbRaw_FeatureSig::VC140:
43 Stream << "VC140";
44 break;
45 }
46 }
47};
48}
49
50template <typename R> using ValueOfRange = llvm::detail::ValueOfRange<R>;
51
52template <typename Range, typename Comp>
53static void set_differences(Range &&R1, Range &&R2,
54 SmallVectorImpl<ValueOfRange<Range>> *OnlyLeft,
55 SmallVectorImpl<ValueOfRange<Range>> *OnlyRight,
56 SmallVectorImpl<ValueOfRange<Range>> *Intersection,
57 Comp Comparator) {
58
59 std::sort(R1.begin(), R1.end(), Comparator);
60 std::sort(R2.begin(), R2.end(), Comparator);
61
62 if (OnlyLeft) {
3
Assuming 'OnlyLeft' is null
4
Taking false branch
63 OnlyLeft->reserve(R1.size());
64 auto End = std::set_difference(R1.begin(), R1.end(), R2.begin(), R2.end(),
65 OnlyLeft->begin(), Comparator);
66 OnlyLeft->set_size(std::distance(OnlyLeft->begin(), End));
67 }
68 if (OnlyRight) {
5
Assuming 'OnlyRight' is non-null
6
Taking true branch
69 OnlyLeft->reserve(R2.size());
7
Called C++ object pointer is null
70 auto End = std::set_difference(R2.begin(), R2.end(), R1.begin(), R1.end(),
71 OnlyRight->begin(), Comparator);
72 OnlyRight->set_size(std::distance(OnlyRight->begin(), End));
73 }
74 if (Intersection) {
75 Intersection->reserve(std::min(R1.size(), R2.size()));
76 auto End = std::set_intersection(R1.begin(), R1.end(), R2.begin(), R2.end(),
77 Intersection->begin(), Comparator);
78 Intersection->set_size(std::distance(Intersection->begin(), End));
79 }
80}
81
82template <typename Range>
83static void
84set_differences(Range &&R1, Range &&R2,
85 SmallVectorImpl<ValueOfRange<Range>> *OnlyLeft,
86 SmallVectorImpl<ValueOfRange<Range>> *OnlyRight,
87 SmallVectorImpl<ValueOfRange<Range>> *Intersection = nullptr) {
88 std::less<ValueOfRange<Range>> Comp;
89 set_differences(std::forward<Range>(R1), std::forward<Range>(R2), OnlyLeft,
1
Passing value via 3rd parameter 'OnlyLeft'
2
Calling 'set_differences'
90 OnlyRight, Intersection, Comp);
91}
92
93DiffStyle::DiffStyle(PDBFile &File1, PDBFile &File2)
94 : File1(File1), File2(File2) {}
95
96Error DiffStyle::dump() {
97 if (auto EC = diffSuperBlock())
98 return EC;
99
100 if (auto EC = diffFreePageMap())
101 return EC;
102
103 if (auto EC = diffStreamDirectory())
104 return EC;
105
106 if (auto EC = diffStringTable())
107 return EC;
108
109 if (auto EC = diffInfoStream())
110 return EC;
111
112 if (auto EC = diffDbiStream())
113 return EC;
114
115 if (auto EC = diffSectionContribs())
116 return EC;
117
118 if (auto EC = diffSectionMap())
119 return EC;
120
121 if (auto EC = diffFpoStream())
122 return EC;
123
124 if (auto EC = diffTpiStream(StreamTPI))
125 return EC;
126
127 if (auto EC = diffTpiStream(StreamIPI))
128 return EC;
129
130 if (auto EC = diffPublics())
131 return EC;
132
133 if (auto EC = diffGlobals())
134 return EC;
135
136 return Error::success();
137}
138
139template <typename T>
140static bool diffAndPrint(StringRef Label, PDBFile &File1, PDBFile &File2, T V1,
141 T V2) {
142 if (V1 == V2) {
143 outs() << formatv(" {0}: No differences detected!\n", Label);
144 return false;
145 }
146
147 outs().indent(2) << Label << "\n";
148 outs().indent(4) << formatv("{0}: {1}\n", File1.getFilePath(), V1);
149 outs().indent(4) << formatv("{0}: {1}\n", File2.getFilePath(), V2);
150 return true;
151}
152
153template <typename T>
154static bool diffAndPrint(StringRef Label, PDBFile &File1, PDBFile &File2,
155 ArrayRef<T> V1, ArrayRef<T> V2) {
156 if (V1 == V2) {
157 outs() << formatv(" {0}: No differences detected!\n", Label);
158 return false;
159 }
160
161 outs().indent(2) << Label << "\n";
162 outs().indent(4) << formatv("{0}: {1}\n", File1.getFilePath(),
163 make_range(V1.begin(), V1.end()));
164 outs().indent(4) << formatv("{0}: {1}\n", File2.getFilePath(),
165 make_range(V2.begin(), V2.end()));
166 return true;
167}
168
169template <typename T>
170static bool printSymmetricDifferences(PDBFile &File1, PDBFile &File2,
171 T &&OnlyRange1, T &&OnlyRange2,
172 StringRef Label) {
173 bool HasDiff = false;
174 if (!OnlyRange1.empty()) {
175 HasDiff = true;
176 outs() << formatv(" {0} {1}(s) only in ({2})\n", OnlyRange1.size(), Label,
177 File1.getFilePath());
178 for (const auto &Item : OnlyRange1)
179 outs() << formatv(" {0}\n", Label, Item);
180 }
181 if (!OnlyRange2.empty()) {
182 HasDiff = true;
183 outs() << formatv(" {0} {1}(s) only in ({2})\n", OnlyRange2.size(),
184 File2.getFilePath());
185 for (const auto &Item : OnlyRange2)
186 outs() << formatv(" {0}\n", Item);
187 }
188 return HasDiff;
189}
190
191Error DiffStyle::diffSuperBlock() {
192 outs() << "MSF Super Block: Searching for differences...\n";
193 bool Diffs = false;
194
195 Diffs |= diffAndPrint("Block Size", File1, File2, File1.getBlockSize(),
196 File2.getBlockSize());
197 Diffs |= diffAndPrint("Block Count", File1, File2, File1.getBlockCount(),
198 File2.getBlockCount());
199 Diffs |= diffAndPrint("Unknown 1", File1, File2, File1.getUnknown1(),
200 File2.getUnknown1());
201
202 if (opts::diff::Pedantic) {
203 Diffs |= diffAndPrint("Free Block Map", File1, File2,
204 File1.getFreeBlockMapBlock(),
205 File2.getFreeBlockMapBlock());
206 Diffs |= diffAndPrint("Directory Size", File1, File2,
207 File1.getNumDirectoryBytes(),
208 File2.getNumDirectoryBytes());
209 Diffs |= diffAndPrint("Block Map Addr", File1, File2,
210 File1.getBlockMapOffset(), File2.getBlockMapOffset());
211 }
212 if (!Diffs)
213 outs() << "MSF Super Block: No differences detected...\n";
214 return Error::success();
215}
216
217Error DiffStyle::diffStreamDirectory() {
218 SmallVector<std::string, 32> P;
219 SmallVector<std::string, 32> Q;
220 discoverStreamPurposes(File1, P);
221 discoverStreamPurposes(File2, Q);
222 outs() << "Stream Directory: Searching for differences...\n";
223
224 bool HasDifferences = false;
225 if (opts::diff::Pedantic) {
226 size_t Min = std::min(P.size(), Q.size());
227 for (size_t I = 0; I < Min; ++I) {
228 StringRef Names[] = {P[I], Q[I]};
229 uint32_t Sizes[] = {File1.getStreamByteSize(I),
230 File2.getStreamByteSize(I)};
231 bool NamesDiffer = Names[0] != Names[1];
232 bool SizesDiffer = Sizes[0] != Sizes[1];
233 if (NamesDiffer) {
234 HasDifferences = true;
235 outs().indent(2) << formatv("Stream {0} - {1}: {2}, {3}: {4}\n", I,
236 File1.getFilePath(), Names[0],
237 File2.getFilePath(), Names[1]);
238 continue;
239 }
240 if (SizesDiffer) {
241 HasDifferences = true;
242 outs().indent(2) << formatv(
243 "Stream {0} ({1}): {2}: {3} bytes, {4}: {5} bytes\n", I, Names[0],
244 File1.getFilePath(), Sizes[0], File2.getFilePath(), Sizes[1]);
245 continue;
246 }
247 }
248
249 ArrayRef<std::string> MaxNames = (P.size() > Q.size() ? P : Q);
250 size_t Max = std::max(P.size(), Q.size());
251 PDBFile &MaxFile = (P.size() > Q.size() ? File1 : File2);
252 StringRef MinFileName =
253 (P.size() < Q.size() ? File1.getFilePath() : File2.getFilePath());
254 for (size_t I = Min; I < Max; ++I) {
255 HasDifferences = true;
256 StringRef StreamName = MaxNames[I];
257
258 outs().indent(2) << formatv(
259 "Stream {0} - {1}: <not present>, {2}: Index {3}, {4} bytes\n",
260 StreamName, MinFileName, MaxFile.getFilePath(), I,
261 MaxFile.getStreamByteSize(I));
262 }
263 if (!HasDifferences)
264 outs() << "Stream Directory: No differences detected...\n";
265 } else {
266 auto PI = to_vector<32>(enumerate(P));
267 auto QI = to_vector<32>(enumerate(Q));
268
269 typedef decltype(PI) ContainerType;
270 typedef typename ContainerType::value_type value_type;
271
272 auto Comparator = [](const value_type &I1, const value_type &I2) {
273 return I1.value() < I2.value();
274 };
275
276 decltype(PI) OnlyP;
277 decltype(QI) OnlyQ;
278 decltype(PI) Common;
279
280 set_differences(PI, QI, &OnlyP, &OnlyQ, &Common, Comparator);
281
282 if (!OnlyP.empty()) {
283 HasDifferences = true;
284 outs().indent(2) << formatv("{0} Stream(s) only in ({1})\n", OnlyP.size(),
285 File1.getFilePath());
286 for (auto &Item : OnlyP) {
287 outs().indent(4) << formatv("Stream {0} - {1}\n", Item.index(),
288 Item.value());
289 }
290 }
291
292 if (!OnlyQ.empty()) {
293 HasDifferences = true;
294 outs().indent(2) << formatv("{0} Streams(s) only in ({1})\n",
295 OnlyQ.size(), File2.getFilePath());
296 for (auto &Item : OnlyQ) {
297 outs().indent(4) << formatv("Stream {0} - {1}\n", Item.index(),
298 Item.value());
299 }
300 }
301 if (!Common.empty()) {
302 outs().indent(2) << formatv("Found {0} common streams. Searching for "
303 "intra-stream differences.\n",
304 Common.size());
305 bool HasCommonDifferences = false;
306 for (const auto &Left : Common) {
307 // Left was copied from the first range so its index refers to a stream
308 // index in the first file. Find the corresponding stream index in the
309 // second file.
310 auto Range =
311 std::equal_range(QI.begin(), QI.end(), Left,
312 [](const value_type &L, const value_type &R) {
313 return L.value() < R.value();
314 });
315 const auto &Right = *Range.first;
316 assert(Left.value() == Right.value())((Left.value() == Right.value()) ? static_cast<void> (0
) : __assert_fail ("Left.value() == Right.value()", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/llvm-pdbdump/Diff.cpp"
, 316, __PRETTY_FUNCTION__))
;
317 uint32_t LeftSize = File1.getStreamByteSize(Left.index());
318 uint32_t RightSize = File2.getStreamByteSize(Right.index());
319 if (LeftSize != RightSize) {
320 HasDifferences = true;
321 HasCommonDifferences = true;
322 outs().indent(4) << formatv("{0} ({1}: {2} bytes, {3}: {4} bytes)\n",
323 Left.value(), File1.getFilePath(),
324 LeftSize, File2.getFilePath(), RightSize);
325 }
326 }
327 if (!HasCommonDifferences)
328 outs().indent(2) << "Common Streams: No differences detected!\n";
329 }
330 if (!HasDifferences)
331 outs() << "Stream Directory: No differences detected!\n";
332 }
333
334 return Error::success();
335}
336
337Error DiffStyle::diffStringTable() {
338 auto ExpectedST1 = File1.getStringTable();
339 auto ExpectedST2 = File2.getStringTable();
340 outs() << "String Table: Searching for differences...\n";
341 bool Has1 = !!ExpectedST1;
342 bool Has2 = !!ExpectedST2;
343 if (!(Has1 && Has2)) {
344 // If one has a string table and the other doesn't, we can print less
345 // output.
346 if (Has1 != Has2) {
347 if (Has1) {
348 outs() << formatv(" {0}: ({1} strings)\n", File1.getFilePath(),
349 ExpectedST1->getNameCount());
350 outs() << formatv(" {0}: (string table not present)\n",
351 File2.getFilePath());
352 } else {
353 outs() << formatv(" {0}: (string table not present)\n",
354 File1.getFilePath());
355 outs() << formatv(" {0}: ({1})\n", File2.getFilePath(),
356 ExpectedST2->getNameCount());
357 }
358 }
359 consumeError(ExpectedST1.takeError());
360 consumeError(ExpectedST2.takeError());
361 return Error::success();
362 }
363
364 bool HasDiff = false;
365 auto &ST1 = *ExpectedST1;
366 auto &ST2 = *ExpectedST2;
367
368 if (ST1.getByteSize() != ST2.getByteSize()) {
369 outs() << " Stream Size\n";
370 outs() << formatv(" {0} - {1} byte(s)\n", File1.getFilePath(),
371 ST1.getByteSize());
372 outs() << formatv(" {0} - {1} byte(s)\n", File2.getFilePath(),
373 ST2.getByteSize());
374 outs() << formatv(" Difference: {0} bytes\n",
375 AbsoluteDifference(ST1.getByteSize(), ST2.getByteSize()));
376 HasDiff = true;
377 }
378 HasDiff |= diffAndPrint("Hash Version", File1, File2, ST1.getHashVersion(),
379 ST1.getHashVersion());
380 HasDiff |= diffAndPrint("Signature", File1, File2, ST1.getSignature(),
381 ST1.getSignature());
382
383 // Both have a valid string table, dive in and compare individual strings.
384
385 auto IdList1 = ST1.name_ids();
386 auto IdList2 = ST2.name_ids();
387 if (opts::diff::Pedantic) {
388 // In pedantic mode, we compare index by index (i.e. the strings are in the
389 // same order
390 // in both tables.
391 uint32_t Max = std::max(IdList1.size(), IdList2.size());
392 for (uint32_t I = 0; I < Max; ++I) {
393 Optional<uint32_t> Id1, Id2;
394 StringRef S1, S2;
395 if (I < IdList1.size()) {
396 Id1 = IdList1[I];
397 if (auto Result = ST1.getStringForID(*Id1))
398 S1 = *Result;
399 else
400 return Result.takeError();
401 }
402 if (I < IdList2.size()) {
403 Id2 = IdList2[I];
404 if (auto Result = ST2.getStringForID(*Id2))
405 S2 = *Result;
406 else
407 return Result.takeError();
408 }
409 if (Id1 == Id2 && S1 == S2)
410 continue;
411
412 std::string OutId1 =
413 Id1 ? formatv("{0}", *Id1).str() : "(index not present)";
414 std::string OutId2 =
415 Id2 ? formatv("{0}", *Id2).str() : "(index not present)";
416 outs() << formatv(" String {0}\n", I);
417 outs() << formatv(" {0}: Hash - {1}, Value - {2}\n",
418 File1.getFilePath(), OutId1, S1);
419 outs() << formatv(" {0}: Hash - {1}, Value - {2}\n",
420 File2.getFilePath(), OutId2, S2);
421 HasDiff = true;
422 }
423 } else {
424 std::vector<StringRef> Strings1, Strings2;
425 Strings1.reserve(IdList1.size());
426 Strings2.reserve(IdList2.size());
427 for (auto ID : IdList1) {
428 auto S = ST1.getStringForID(ID);
429 if (!S)
430 return S.takeError();
431 Strings1.push_back(*S);
432 }
433 for (auto ID : IdList2) {
434 auto S = ST2.getStringForID(ID);
435 if (!S)
436 return S.takeError();
437 Strings2.push_back(*S);
438 }
439
440 SmallVector<StringRef, 64> OnlyP;
441 SmallVector<StringRef, 64> OnlyQ;
442 auto End1 = std::remove(Strings1.begin(), Strings1.end(), "");
443 auto End2 = std::remove(Strings2.begin(), Strings2.end(), "");
444 uint32_t Empty1 = std::distance(End1, Strings1.end());
445 uint32_t Empty2 = std::distance(End2, Strings2.end());
446 Strings1.erase(End1, Strings1.end());
447 Strings2.erase(End2, Strings2.end());
448 set_differences(Strings1, Strings2, &OnlyP, &OnlyQ);
449 printSymmetricDifferences(File1, File2, OnlyP, OnlyQ, "String");
450
451 if (Empty1 != Empty2) {
452 PDBFile &MoreF = (Empty1 > Empty2) ? File1 : File2;
453 PDBFile &LessF = (Empty1 < Empty2) ? File1 : File2;
454 uint32_t Difference = AbsoluteDifference(Empty1, Empty2);
455 outs() << formatv(" {0} had {1} more empty strings than {2}\n",
456 MoreF.getFilePath(), Difference, LessF.getFilePath());
457 }
458 }
459 if (!HasDiff)
460 outs() << "String Table: No differences detected!\n";
461 return Error::success();
462}
463
464Error DiffStyle::diffFreePageMap() { return Error::success(); }
465
466Error DiffStyle::diffInfoStream() {
467 auto ExpectedInfo1 = File1.getPDBInfoStream();
468 auto ExpectedInfo2 = File2.getPDBInfoStream();
469
470 outs() << "PDB Stream: Searching for differences...\n";
471 bool Has1 = !!ExpectedInfo1;
472 bool Has2 = !!ExpectedInfo2;
473 if (!(Has1 && Has2)) {
474 if (Has1 != Has2)
475 outs() << formatv("{0} does not have a PDB Stream!\n",
476 Has1 ? File1.getFilePath() : File2.getFilePath());
477 consumeError(ExpectedInfo2.takeError());
478 consumeError(ExpectedInfo2.takeError());
479 return Error::success();
480 }
481
482 bool HasDiff = false;
483 auto &IS1 = *ExpectedInfo1;
484 auto &IS2 = *ExpectedInfo2;
485 if (IS1.getStreamSize() != IS2.getStreamSize()) {
486 outs() << " Stream Size\n";
487 outs() << formatv(" {0} - {1} byte(s)\n", File1.getFilePath(),
488 IS1.getStreamSize());
489 outs() << formatv(" {0} - {1} byte(s)\n", File2.getFilePath(),
490 IS2.getStreamSize());
491 outs() << formatv(
492 " Difference: {0} bytes\n",
493 AbsoluteDifference(IS1.getStreamSize(), IS2.getStreamSize()));
494 HasDiff = true;
495 }
496 HasDiff |= diffAndPrint("Age", File1, File2, IS1.getAge(), IS2.getAge());
497 HasDiff |= diffAndPrint("Guid", File1, File2, IS1.getGuid(), IS2.getGuid());
498 HasDiff |= diffAndPrint("Signature", File1, File2, IS1.getSignature(),
499 IS2.getSignature());
500 HasDiff |=
501 diffAndPrint("Version", File1, File2, IS1.getVersion(), IS2.getVersion());
502 HasDiff |= diffAndPrint("Features", File1, File2, IS1.getFeatureSignatures(),
503 IS2.getFeatureSignatures());
504 HasDiff |= diffAndPrint("Named Stream Byte Size", File1, File2,
505 IS1.getNamedStreamMapByteSize(),
506 IS2.getNamedStreamMapByteSize());
507 SmallVector<StringRef, 4> NS1;
508 SmallVector<StringRef, 4> NS2;
509 for (const auto &X : IS1.getNamedStreams().entries())
510 NS1.push_back(X.getKey());
511 for (const auto &X : IS2.getNamedStreams().entries())
512 NS2.push_back(X.getKey());
513 SmallVector<StringRef, 4> OnlyP;
514 SmallVector<StringRef, 4> OnlyQ;
515 set_differences(NS1, NS2, &OnlyP, &OnlyQ);
516 printSymmetricDifferences(File1, File2, OnlyP, OnlyQ, "Named Streams");
517 if (!HasDiff)
518 outs() << "PDB Stream: No differences detected!\n";
519
520 return Error::success();
521}
522
523Error DiffStyle::diffDbiStream() { return Error::success(); }
524
525Error DiffStyle::diffSectionContribs() { return Error::success(); }
526
527Error DiffStyle::diffSectionMap() { return Error::success(); }
528
529Error DiffStyle::diffFpoStream() { return Error::success(); }
530
531Error DiffStyle::diffTpiStream(int Index) { return Error::success(); }
532
533Error DiffStyle::diffModuleInfoStream(int Index) { return Error::success(); }
534
535Error DiffStyle::diffPublics() { return Error::success(); }
536
537Error DiffStyle::diffGlobals() { return Error::success(); }