Bug Summary

File:tools/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp
Warning:line 49, column 23
Dereference of undefined pointer value

Annotated Source Code

[?] Use j/k keys for keyboard navigation

1//===-- MinidumpTypes.cpp ---------------------------------------*- 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// Project includes
11#include "MinidumpTypes.h"
12
13// Other libraries and framework includes
14// C includes
15// C++ includes
16
17using namespace lldb_private;
18using namespace minidump;
19
20const MinidumpHeader *MinidumpHeader::Parse(llvm::ArrayRef<uint8_t> &data) {
21 const MinidumpHeader *header = nullptr;
22 Status error = consumeObject(data, header);
23
24 const MinidumpHeaderConstants signature =
25 static_cast<const MinidumpHeaderConstants>(
26 static_cast<const uint32_t>(header->signature));
27 const MinidumpHeaderConstants version =
28 static_cast<const MinidumpHeaderConstants>(
29 static_cast<const uint32_t>(header->version) & 0x0000ffff);
30 // the high 16 bits of the version field are implementation specific
31
32 if (error.Fail() || signature != MinidumpHeaderConstants::Signature ||
33 version != MinidumpHeaderConstants::Version)
34 return nullptr;
35
36 // TODO check for max number of streams ?
37 // TODO more sanity checks ?
38
39 return header;
40}
41
42// Minidump string
43llvm::Optional<std::string>
44lldb_private::minidump::parseMinidumpString(llvm::ArrayRef<uint8_t> &data) {
45 std::string result;
46
47 const uint32_t *source_length;
48 Status error = consumeObject(data, source_length);
49 if (error.Fail() || *source_length > data.size() || *source_length % 2 != 0)
1
Assuming the condition is false
2
Dereference of undefined pointer value
50 return llvm::None;
51
52 auto source_start = reinterpret_cast<const llvm::UTF16 *>(data.data());
53 // source_length is the length of the string in bytes
54 // we need the length of the string in UTF-16 characters/code points (16 bits
55 // per char)
56 // that's why it's divided by 2
57 const auto source_end = source_start + (*source_length) / 2;
58 // resize to worst case length
59 result.resize(UNI_MAX_UTF8_BYTES_PER_CODE_POINT4 * (*source_length) / 2);
60 auto result_start = reinterpret_cast<llvm::UTF8 *>(&result[0]);
61 const auto result_end = result_start + result.size();
62 llvm::ConvertUTF16toUTF8(&source_start, source_end, &result_start, result_end,
63 llvm::strictConversion);
64 const auto result_size =
65 std::distance(reinterpret_cast<llvm::UTF8 *>(&result[0]), result_start);
66 result.resize(result_size); // shrink to actual length
67
68 return result;
69}
70
71// MinidumpThread
72const MinidumpThread *MinidumpThread::Parse(llvm::ArrayRef<uint8_t> &data) {
73 const MinidumpThread *thread = nullptr;
74 Status error = consumeObject(data, thread);
75 if (error.Fail())
76 return nullptr;
77
78 return thread;
79}
80
81llvm::ArrayRef<MinidumpThread>
82MinidumpThread::ParseThreadList(llvm::ArrayRef<uint8_t> &data) {
83 const llvm::support::ulittle32_t *thread_count;
84 Status error = consumeObject(data, thread_count);
85 if (error.Fail() || *thread_count * sizeof(MinidumpThread) > data.size())
86 return {};
87
88 return llvm::ArrayRef<MinidumpThread>(
89 reinterpret_cast<const MinidumpThread *>(data.data()), *thread_count);
90}
91
92// MinidumpSystemInfo
93const MinidumpSystemInfo *
94MinidumpSystemInfo::Parse(llvm::ArrayRef<uint8_t> &data) {
95 const MinidumpSystemInfo *system_info;
96 Status error = consumeObject(data, system_info);
97 if (error.Fail())
98 return nullptr;
99
100 return system_info;
101}
102
103// MinidumpMiscInfo
104const MinidumpMiscInfo *MinidumpMiscInfo::Parse(llvm::ArrayRef<uint8_t> &data) {
105 const MinidumpMiscInfo *misc_info;
106 Status error = consumeObject(data, misc_info);
107 if (error.Fail())
108 return nullptr;
109
110 return misc_info;
111}
112
113llvm::Optional<lldb::pid_t> MinidumpMiscInfo::GetPid() const {
114 uint32_t pid_flag =
115 static_cast<const uint32_t>(MinidumpMiscInfoFlags::ProcessID);
116 if (flags1 & pid_flag)
117 return llvm::Optional<lldb::pid_t>(process_id);
118
119 return llvm::None;
120}
121
122// Linux Proc Status
123// it's stored as an ascii string in the file
124llvm::Optional<LinuxProcStatus>
125LinuxProcStatus::Parse(llvm::ArrayRef<uint8_t> &data) {
126 LinuxProcStatus result;
127 result.proc_status =
128 llvm::StringRef(reinterpret_cast<const char *>(data.data()), data.size());
129 data = data.drop_front(data.size());
130
131 llvm::SmallVector<llvm::StringRef, 0> lines;
132 result.proc_status.split(lines, '\n', 42);
133 // /proc/$pid/status has 41 lines, but why not use 42?
134 for (auto line : lines) {
135 if (line.consume_front("Pid:")) {
136 line = line.trim();
137 if (!line.getAsInteger(10, result.pid))
138 return result;
139 }
140 }
141
142 return llvm::None;
143}
144
145lldb::pid_t LinuxProcStatus::GetPid() const { return pid; }
146
147// Module stuff
148const MinidumpModule *MinidumpModule::Parse(llvm::ArrayRef<uint8_t> &data) {
149 const MinidumpModule *module = nullptr;
150 Status error = consumeObject(data, module);
151 if (error.Fail())
152 return nullptr;
153
154 return module;
155}
156
157llvm::ArrayRef<MinidumpModule>
158MinidumpModule::ParseModuleList(llvm::ArrayRef<uint8_t> &data) {
159
160 const llvm::support::ulittle32_t *modules_count;
161 Status error = consumeObject(data, modules_count);
162 if (error.Fail() || *modules_count * sizeof(MinidumpModule) > data.size())
163 return {};
164
165 return llvm::ArrayRef<MinidumpModule>(
166 reinterpret_cast<const MinidumpModule *>(data.data()), *modules_count);
167}
168
169// Exception stuff
170const MinidumpExceptionStream *
171MinidumpExceptionStream::Parse(llvm::ArrayRef<uint8_t> &data) {
172 const MinidumpExceptionStream *exception_stream = nullptr;
173 Status error = consumeObject(data, exception_stream);
174 if (error.Fail())
175 return nullptr;
176
177 return exception_stream;
178}
179
180llvm::ArrayRef<MinidumpMemoryDescriptor>
181MinidumpMemoryDescriptor::ParseMemoryList(llvm::ArrayRef<uint8_t> &data) {
182 const llvm::support::ulittle32_t *mem_ranges_count;
183 Status error = consumeObject(data, mem_ranges_count);
184 if (error.Fail() ||
185 *mem_ranges_count * sizeof(MinidumpMemoryDescriptor) > data.size())
186 return {};
187
188 return llvm::makeArrayRef(
189 reinterpret_cast<const MinidumpMemoryDescriptor *>(data.data()),
190 *mem_ranges_count);
191}
192
193std::pair<llvm::ArrayRef<MinidumpMemoryDescriptor64>, uint64_t>
194MinidumpMemoryDescriptor64::ParseMemory64List(llvm::ArrayRef<uint8_t> &data) {
195 const llvm::support::ulittle64_t *mem_ranges_count;
196 Status error = consumeObject(data, mem_ranges_count);
197 if (error.Fail() ||
198 *mem_ranges_count * sizeof(MinidumpMemoryDescriptor64) > data.size())
199 return {};
200
201 const llvm::support::ulittle64_t *base_rva;
202 error = consumeObject(data, base_rva);
203 if (error.Fail())
204 return {};
205
206 return std::make_pair(
207 llvm::makeArrayRef(
208 reinterpret_cast<const MinidumpMemoryDescriptor64 *>(data.data()),
209 *mem_ranges_count),
210 *base_rva);
211}
212
213std::vector<const MinidumpMemoryInfo *>
214MinidumpMemoryInfo::ParseMemoryInfoList(llvm::ArrayRef<uint8_t> &data) {
215 const MinidumpMemoryInfoListHeader *header;
216 Status error = consumeObject(data, header);
217 if (error.Fail() ||
218 header->size_of_header < sizeof(MinidumpMemoryInfoListHeader) ||
219 header->size_of_entry < sizeof(MinidumpMemoryInfo))
220 return {};
221
222 data = data.drop_front(header->size_of_header -
223 sizeof(MinidumpMemoryInfoListHeader));
224
225 if (header->size_of_entry * header->num_of_entries > data.size())
226 return {};
227
228 std::vector<const MinidumpMemoryInfo *> result;
229 for (uint64_t i = 0; i < header->num_of_entries; ++i) {
230 result.push_back(reinterpret_cast<const MinidumpMemoryInfo *>(
231 data.data() + i * header->size_of_entry));
232 }
233
234 return result;
235}