Bug Summary

File:tools/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
Warning:line 393, column 21
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name PlistDiagnostics.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -relaxed-aliasing -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-7/lib/clang/7.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-7~svn329677/build-llvm/tools/clang/lib/StaticAnalyzer/Core -I /build/llvm-toolchain-snapshot-7~svn329677/tools/clang/lib/StaticAnalyzer/Core -I /build/llvm-toolchain-snapshot-7~svn329677/tools/clang/include -I /build/llvm-toolchain-snapshot-7~svn329677/build-llvm/tools/clang/include -I /build/llvm-toolchain-snapshot-7~svn329677/build-llvm/include -I /build/llvm-toolchain-snapshot-7~svn329677/include -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/x86_64-linux-gnu/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/x86_64-linux-gnu/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/backward -internal-isystem /usr/include/clang/7.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-7/lib/clang/7.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-7~svn329677/build-llvm/tools/clang/lib/StaticAnalyzer/Core -ferror-limit 19 -fmessage-length 0 -fvisibility-inlines-hidden -fobjc-runtime=gcc -fno-common -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2018-04-11-031539-24776-1 -x c++ /build/llvm-toolchain-snapshot-7~svn329677/tools/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
1//===--- PlistDiagnostics.cpp - Plist Diagnostics for Paths -----*- 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// This file defines the PlistDiagnostics object.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Basic/FileManager.h"
15#include "clang/Basic/PlistSupport.h"
16#include "clang/Basic/SourceManager.h"
17#include "clang/Basic/Version.h"
18#include "clang/Lex/Preprocessor.h"
19#include "clang/Rewrite/Core/HTMLRewrite.h"
20#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
21#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
22#include "clang/StaticAnalyzer/Core/IssueHash.h"
23#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
24#include "llvm/ADT/Statistic.h"
25#include "llvm/ADT/SmallVector.h"
26#include "llvm/Support/Casting.h"
27using namespace clang;
28using namespace ento;
29using namespace markup;
30
31namespace {
32 class PlistDiagnostics : public PathDiagnosticConsumer {
33 const std::string OutputFile;
34 const LangOptions &LangOpts;
35 const bool SupportsCrossFileDiagnostics;
36 const bool SerializeStatistics;
37 public:
38 PlistDiagnostics(AnalyzerOptions &AnalyzerOpts,
39 const std::string& prefix,
40 const LangOptions &LangOpts,
41 bool supportsMultipleFiles);
42
43 ~PlistDiagnostics() override {}
44
45 void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
46 FilesMade *filesMade) override;
47
48 StringRef getName() const override {
49 return "PlistDiagnostics";
50 }
51
52 PathGenerationScheme getGenerationScheme() const override {
53 return Extensive;
54 }
55 bool supportsLogicalOpControlFlow() const override { return true; }
56 bool supportsCrossFileDiagnostics() const override {
57 return SupportsCrossFileDiagnostics;
58 }
59 };
60} // end anonymous namespace
61
62PlistDiagnostics::PlistDiagnostics(AnalyzerOptions &AnalyzerOpts,
63 const std::string& output,
64 const LangOptions &LO,
65 bool supportsMultipleFiles)
66 : OutputFile(output),
67 LangOpts(LO),
68 SupportsCrossFileDiagnostics(supportsMultipleFiles),
69 SerializeStatistics(AnalyzerOpts.shouldSerializeStats()) {}
70
71void ento::createPlistDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
72 PathDiagnosticConsumers &C,
73 const std::string& s,
74 const Preprocessor &PP) {
75 C.push_back(new PlistDiagnostics(AnalyzerOpts, s,
76 PP.getLangOpts(), false));
77}
78
79void ento::createPlistMultiFileDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
80 PathDiagnosticConsumers &C,
81 const std::string &s,
82 const Preprocessor &PP) {
83 C.push_back(new PlistDiagnostics(AnalyzerOpts, s,
84 PP.getLangOpts(), true));
85}
86
87static void ReportControlFlow(raw_ostream &o,
88 const PathDiagnosticControlFlowPiece& P,
89 const FIDMap& FM,
90 const SourceManager &SM,
91 const LangOptions &LangOpts,
92 unsigned indent) {
93
94 Indent(o, indent) << "<dict>\n";
95 ++indent;
96
97 Indent(o, indent) << "<key>kind</key><string>control</string>\n";
98
99 // Emit edges.
100 Indent(o, indent) << "<key>edges</key>\n";
101 ++indent;
102 Indent(o, indent) << "<array>\n";
103 ++indent;
104 for (PathDiagnosticControlFlowPiece::const_iterator I=P.begin(), E=P.end();
105 I!=E; ++I) {
106 Indent(o, indent) << "<dict>\n";
107 ++indent;
108
109 // Make the ranges of the start and end point self-consistent with adjacent edges
110 // by forcing to use only the beginning of the range. This simplifies the layout
111 // logic for clients.
112 Indent(o, indent) << "<key>start</key>\n";
113 SourceRange StartEdge(
114 SM.getExpansionLoc(I->getStart().asRange().getBegin()));
115 EmitRange(o, SM, Lexer::getAsCharRange(StartEdge, SM, LangOpts), FM,
116 indent + 1);
117
118 Indent(o, indent) << "<key>end</key>\n";
119 SourceRange EndEdge(SM.getExpansionLoc(I->getEnd().asRange().getBegin()));
120 EmitRange(o, SM, Lexer::getAsCharRange(EndEdge, SM, LangOpts), FM,
121 indent + 1);
122
123 --indent;
124 Indent(o, indent) << "</dict>\n";
125 }
126 --indent;
127 Indent(o, indent) << "</array>\n";
128 --indent;
129
130 // Output any helper text.
131 const auto &s = P.getString();
132 if (!s.empty()) {
133 Indent(o, indent) << "<key>alternate</key>";
134 EmitString(o, s) << '\n';
135 }
136
137 --indent;
138 Indent(o, indent) << "</dict>\n";
139}
140
141static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P,
142 const FIDMap& FM,
143 const SourceManager &SM,
144 const LangOptions &LangOpts,
145 unsigned indent,
146 unsigned depth,
147 bool isKeyEvent = false) {
148
149 Indent(o, indent) << "<dict>\n";
150 ++indent;
151
152 Indent(o, indent) << "<key>kind</key><string>event</string>\n";
153
154 if (isKeyEvent) {
155 Indent(o, indent) << "<key>key_event</key><true/>\n";
156 }
157
158 // Output the location.
159 FullSourceLoc L = P.getLocation().asLocation();
160
161 Indent(o, indent) << "<key>location</key>\n";
162 EmitLocation(o, SM, L, FM, indent);
163
164 // Output the ranges (if any).
165 ArrayRef<SourceRange> Ranges = P.getRanges();
166
167 if (!Ranges.empty()) {
168 Indent(o, indent) << "<key>ranges</key>\n";
169 Indent(o, indent) << "<array>\n";
170 ++indent;
171 for (auto &R : Ranges)
172 EmitRange(o, SM,
173 Lexer::getAsCharRange(SM.getExpansionRange(R), SM, LangOpts),
174 FM, indent + 1);
175 --indent;
176 Indent(o, indent) << "</array>\n";
177 }
178
179 // Output the call depth.
180 Indent(o, indent) << "<key>depth</key>";
181 EmitInteger(o, depth) << '\n';
182
183 // Output the text.
184 assert(!P.getString().empty())(static_cast <bool> (!P.getString().empty()) ? void (0)
: __assert_fail ("!P.getString().empty()", "/build/llvm-toolchain-snapshot-7~svn329677/tools/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp"
, 184, __extension__ __PRETTY_FUNCTION__))
;
185 Indent(o, indent) << "<key>extended_message</key>\n";
186 Indent(o, indent);
187 EmitString(o, P.getString()) << '\n';
188
189 // Output the short text.
190 // FIXME: Really use a short string.
191 Indent(o, indent) << "<key>message</key>\n";
192 Indent(o, indent);
193 EmitString(o, P.getString()) << '\n';
194
195 // Finish up.
196 --indent;
197 Indent(o, indent); o << "</dict>\n";
198}
199
200static void ReportPiece(raw_ostream &o,
201 const PathDiagnosticPiece &P,
202 const FIDMap& FM, const SourceManager &SM,
203 const LangOptions &LangOpts,
204 unsigned indent,
205 unsigned depth,
206 bool includeControlFlow,
207 bool isKeyEvent = false);
208
209static void ReportCall(raw_ostream &o,
210 const PathDiagnosticCallPiece &P,
211 const FIDMap& FM, const SourceManager &SM,
212 const LangOptions &LangOpts,
213 unsigned indent,
214 unsigned depth) {
215
216 if (auto callEnter = P.getCallEnterEvent())
217 ReportPiece(o, *callEnter, FM, SM, LangOpts, indent, depth, true,
218 P.isLastInMainSourceFile());
219
220
221 ++depth;
222
223 if (auto callEnterWithinCaller = P.getCallEnterWithinCallerEvent())
224 ReportPiece(o, *callEnterWithinCaller, FM, SM, LangOpts,
225 indent, depth, true);
226
227 for (PathPieces::const_iterator I = P.path.begin(), E = P.path.end();I!=E;++I)
228 ReportPiece(o, **I, FM, SM, LangOpts, indent, depth, true);
229
230 --depth;
231
232 if (auto callExit = P.getCallExitEvent())
233 ReportPiece(o, *callExit, FM, SM, LangOpts, indent, depth, true);
234}
235
236static void ReportMacro(raw_ostream &o,
237 const PathDiagnosticMacroPiece& P,
238 const FIDMap& FM, const SourceManager &SM,
239 const LangOptions &LangOpts,
240 unsigned indent,
241 unsigned depth) {
242
243 for (PathPieces::const_iterator I = P.subPieces.begin(), E=P.subPieces.end();
244 I!=E; ++I) {
245 ReportPiece(o, **I, FM, SM, LangOpts, indent, depth, false);
246 }
247}
248
249static void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P,
250 const FIDMap& FM, const SourceManager &SM,
251 const LangOptions &LangOpts) {
252 ReportPiece(o, P, FM, SM, LangOpts, 4, 0, true);
253}
254
255static void ReportPiece(raw_ostream &o,
256 const PathDiagnosticPiece &P,
257 const FIDMap& FM, const SourceManager &SM,
258 const LangOptions &LangOpts,
259 unsigned indent,
260 unsigned depth,
261 bool includeControlFlow,
262 bool isKeyEvent) {
263 switch (P.getKind()) {
264 case PathDiagnosticPiece::ControlFlow:
265 if (includeControlFlow)
266 ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, SM,
267 LangOpts, indent);
268 break;
269 case PathDiagnosticPiece::Call:
270 ReportCall(o, cast<PathDiagnosticCallPiece>(P), FM, SM, LangOpts,
271 indent, depth);
272 break;
273 case PathDiagnosticPiece::Event:
274 ReportEvent(o, cast<PathDiagnosticSpotPiece>(P), FM, SM, LangOpts,
275 indent, depth, isKeyEvent);
276 break;
277 case PathDiagnosticPiece::Macro:
278 ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts,
279 indent, depth);
280 break;
281 case PathDiagnosticPiece::Note:
282 // FIXME: Extend the plist format to support those.
283 break;
284 }
285}
286
287void PlistDiagnostics::FlushDiagnosticsImpl(
288 std::vector<const PathDiagnostic *> &Diags,
289 FilesMade *filesMade) {
290 // Build up a set of FIDs that we use by scanning the locations and
291 // ranges of the diagnostics.
292 FIDMap FM;
293 SmallVector<FileID, 10> Fids;
294 const SourceManager* SM = nullptr;
1
'SM' initialized to a null pointer value
295
296 if (!Diags.empty())
2
Assuming the condition is false
3
Taking false branch
297 SM = &Diags.front()->path.front()->getLocation().getManager();
298
299 auto AddPieceFID = [&FM, &Fids, SM](const PathDiagnosticPiece &Piece) {
300 AddFID(FM, Fids, *SM, Piece.getLocation().asLocation());
301 ArrayRef<SourceRange> Ranges = Piece.getRanges();
302 for (const SourceRange &Range : Ranges) {
303 AddFID(FM, Fids, *SM, Range.getBegin());
304 AddFID(FM, Fids, *SM, Range.getEnd());
305 }
306 };
307
308 for (const PathDiagnostic *D : Diags) {
309
310 SmallVector<const PathPieces *, 5> WorkList;
311 WorkList.push_back(&D->path);
312
313 while (!WorkList.empty()) {
314 const PathPieces &Path = *WorkList.pop_back_val();
315
316 for (const auto &Iter : Path) {
317 const PathDiagnosticPiece &Piece = *Iter;
318 AddPieceFID(Piece);
319
320 if (const PathDiagnosticCallPiece *Call =
321 dyn_cast<PathDiagnosticCallPiece>(&Piece)) {
322 if (auto CallEnterWithin = Call->getCallEnterWithinCallerEvent())
323 AddPieceFID(*CallEnterWithin);
324
325 if (auto CallEnterEvent = Call->getCallEnterEvent())
326 AddPieceFID(*CallEnterEvent);
327
328 WorkList.push_back(&Call->path);
329 } else if (const PathDiagnosticMacroPiece *Macro =
330 dyn_cast<PathDiagnosticMacroPiece>(&Piece)) {
331 WorkList.push_back(&Macro->subPieces);
332 }
333 }
334 }
335 }
336
337 // Open the file.
338 std::error_code EC;
339 llvm::raw_fd_ostream o(OutputFile, EC, llvm::sys::fs::F_Text);
340 if (EC) {
4
Taking false branch
341 llvm::errs() << "warning: could not create file: " << EC.message() << '\n';
342 return;
343 }
344
345 EmitPlistHeader(o);
346
347 // Write the root object: a <dict> containing...
348 // - "clang_version", the string representation of clang version
349 // - "files", an <array> mapping from FIDs to file names
350 // - "diagnostics", an <array> containing the path diagnostics
351 o << "<dict>\n" <<
352 " <key>clang_version</key>\n";
353 EmitString(o, getClangFullVersion()) << '\n';
354 o << " <key>files</key>\n"
355 " <array>\n";
356
357 for (FileID FID : Fids)
5
Assuming '__begin1' is equal to '__end1'
358 EmitString(o << " ", SM->getFileEntryForID(FID)->getName()) << '\n';
359
360 o << " </array>\n"
361 " <key>diagnostics</key>\n"
362 " <array>\n";
363
364 for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(),
6
Loop condition is true. Entering loop body
365 DE = Diags.end(); DI!=DE; ++DI) {
366
367 o << " <dict>\n"
368 " <key>path</key>\n";
369
370 const PathDiagnostic *D = *DI;
371
372 o << " <array>\n";
373
374 for (PathPieces::const_iterator I = D->path.begin(), E = D->path.end();
7
Loop condition is false. Execution continues on line 378
375 I != E; ++I)
376 ReportDiag(o, **I, FM, *SM, LangOpts);
377
378 o << " </array>\n";
379
380 // Output the bug type and bug category.
381 o << " <key>description</key>";
382 EmitString(o, D->getShortDescription()) << '\n';
383 o << " <key>category</key>";
384 EmitString(o, D->getCategory()) << '\n';
385 o << " <key>type</key>";
386 EmitString(o, D->getBugType()) << '\n';
387 o << " <key>check_name</key>";
388 EmitString(o, D->getCheckName()) << '\n';
389
390 o << " <!-- This hash is experimental and going to change! -->\n";
391 o << " <key>issue_hash_content_of_line_in_context</key>";
392 PathDiagnosticLocation UPDLoc = D->getUniqueingLoc();
393 FullSourceLoc L(SM->getExpansionLoc(UPDLoc.isValid()
8
'?' condition is true
9
Called C++ object pointer is null
394 ? UPDLoc.asLocation()
395 : D->getLocation().asLocation()),
396 *SM);
397 const Decl *DeclWithIssue = D->getDeclWithIssue();
398 EmitString(o, GetIssueHash(*SM, L, D->getCheckName(), D->getBugType(),
399 DeclWithIssue, LangOpts))
400 << '\n';
401
402 // Output information about the semantic context where
403 // the issue occurred.
404 if (const Decl *DeclWithIssue = D->getDeclWithIssue()) {
405 // FIXME: handle blocks, which have no name.
406 if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) {
407 StringRef declKind;
408 switch (ND->getKind()) {
409 case Decl::CXXRecord:
410 declKind = "C++ class";
411 break;
412 case Decl::CXXMethod:
413 declKind = "C++ method";
414 break;
415 case Decl::ObjCMethod:
416 declKind = "Objective-C method";
417 break;
418 case Decl::Function:
419 declKind = "function";
420 break;
421 default:
422 break;
423 }
424 if (!declKind.empty()) {
425 const std::string &declName = ND->getDeclName().getAsString();
426 o << " <key>issue_context_kind</key>";
427 EmitString(o, declKind) << '\n';
428 o << " <key>issue_context</key>";
429 EmitString(o, declName) << '\n';
430 }
431
432 // Output the bug hash for issue unique-ing. Currently, it's just an
433 // offset from the beginning of the function.
434 if (const Stmt *Body = DeclWithIssue->getBody()) {
435
436 // If the bug uniqueing location exists, use it for the hash.
437 // For example, this ensures that two leaks reported on the same line
438 // will have different issue_hashes and that the hash will identify
439 // the leak location even after code is added between the allocation
440 // site and the end of scope (leak report location).
441 if (UPDLoc.isValid()) {
442 FullSourceLoc UFunL(SM->getExpansionLoc(
443 D->getUniqueingDecl()->getBody()->getLocStart()), *SM);
444 o << " <key>issue_hash_function_offset</key><string>"
445 << L.getExpansionLineNumber() - UFunL.getExpansionLineNumber()
446 << "</string>\n";
447
448 // Otherwise, use the location on which the bug is reported.
449 } else {
450 FullSourceLoc FunL(SM->getExpansionLoc(Body->getLocStart()), *SM);
451 o << " <key>issue_hash_function_offset</key><string>"
452 << L.getExpansionLineNumber() - FunL.getExpansionLineNumber()
453 << "</string>\n";
454 }
455
456 }
457 }
458 }
459
460 // Output the location of the bug.
461 o << " <key>location</key>\n";
462 EmitLocation(o, *SM, D->getLocation().asLocation(), FM, 2);
463
464 // Output the diagnostic to the sub-diagnostic client, if any.
465 if (!filesMade->empty()) {
466 StringRef lastName;
467 PDFileEntry::ConsumerFiles *files = filesMade->getFiles(*D);
468 if (files) {
469 for (PDFileEntry::ConsumerFiles::const_iterator CI = files->begin(),
470 CE = files->end(); CI != CE; ++CI) {
471 StringRef newName = CI->first;
472 if (newName != lastName) {
473 if (!lastName.empty()) {
474 o << " </array>\n";
475 }
476 lastName = newName;
477 o << " <key>" << lastName << "_files</key>\n";
478 o << " <array>\n";
479 }
480 o << " <string>" << CI->second << "</string>\n";
481 }
482 o << " </array>\n";
483 }
484 }
485
486 // Close up the entry.
487 o << " </dict>\n";
488 }
489
490 o << " </array>\n";
491
492 if (llvm::AreStatisticsEnabled() && SerializeStatistics) {
493 o << " <key>statistics</key>\n";
494 std::string stats;
495 llvm::raw_string_ostream os(stats);
496 llvm::PrintStatisticsJSON(os);
497 os.flush();
498 EmitString(o, html::EscapeText(stats)) << '\n';
499 }
500
501 // Finish.
502 o << "</dict>\n</plist>";
503}