Bug Summary

File:tools/yaml2obj/yaml2macho.cpp
Location:line 293, column 20
Description:Access to field 'stroff' results in a dereference of a null pointer (loaded from variable 'SymtabCmd')

Annotated Source Code

1//===- yaml2macho - Convert YAML to a Mach object file --------------------===//
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/// \file
11/// \brief The Mach component of yaml2obj.
12///
13//===----------------------------------------------------------------------===//
14
15#include "yaml2obj.h"
16#include "llvm/ObjectYAML/MachOYAML.h"
17#include "llvm/Support/Error.h"
18#include "llvm/Support/LEB128.h"
19#include "llvm/Support/MachO.h"
20#include "llvm/Support/YAMLTraits.h"
21#include "llvm/Support/raw_ostream.h"
22
23#include "llvm/Support/Format.h"
24
25using namespace llvm;
26
27namespace {
28
29class MachOWriter {
30public:
31 MachOWriter(MachOYAML::Object &Obj) : Obj(Obj), is64Bit(true), fileStart(0) {
32 is64Bit = Obj.Header.magic == MachO::MH_MAGIC_64 ||
33 Obj.Header.magic == MachO::MH_CIGAM_64;
34 memset(reinterpret_cast<void *>(&Header64), 0,
35 sizeof(MachO::mach_header_64));
36 assert((is64Bit || Obj.Header.reserved == 0xDEADBEEFu) &&(((is64Bit || Obj.Header.reserved == 0xDEADBEEFu) && "32-bit MachO has reserved in header"
) ? static_cast<void> (0) : __assert_fail ("(is64Bit || Obj.Header.reserved == 0xDEADBEEFu) && \"32-bit MachO has reserved in header\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn270899/tools/yaml2obj/yaml2macho.cpp"
, 37, __PRETTY_FUNCTION__))
37 "32-bit MachO has reserved in header")(((is64Bit || Obj.Header.reserved == 0xDEADBEEFu) && "32-bit MachO has reserved in header"
) ? static_cast<void> (0) : __assert_fail ("(is64Bit || Obj.Header.reserved == 0xDEADBEEFu) && \"32-bit MachO has reserved in header\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn270899/tools/yaml2obj/yaml2macho.cpp"
, 37, __PRETTY_FUNCTION__))
;
38 assert((!is64Bit || Obj.Header.reserved != 0xDEADBEEFu) &&(((!is64Bit || Obj.Header.reserved != 0xDEADBEEFu) &&
"64-bit MachO has missing reserved in header") ? static_cast
<void> (0) : __assert_fail ("(!is64Bit || Obj.Header.reserved != 0xDEADBEEFu) && \"64-bit MachO has missing reserved in header\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn270899/tools/yaml2obj/yaml2macho.cpp"
, 39, __PRETTY_FUNCTION__))
39 "64-bit MachO has missing reserved in header")(((!is64Bit || Obj.Header.reserved != 0xDEADBEEFu) &&
"64-bit MachO has missing reserved in header") ? static_cast
<void> (0) : __assert_fail ("(!is64Bit || Obj.Header.reserved != 0xDEADBEEFu) && \"64-bit MachO has missing reserved in header\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn270899/tools/yaml2obj/yaml2macho.cpp"
, 39, __PRETTY_FUNCTION__))
;
40 }
41
42 Error writeMachO(raw_ostream &OS);
43
44private:
45 Error writeHeader(raw_ostream &OS);
46 Error writeLoadCommands(raw_ostream &OS);
47 Error writeSectionData(raw_ostream &OS);
48 Error writeLinkEditData(raw_ostream &OS);
49
50 void ZeroToOffset(raw_ostream &OS, size_t offset);
51
52 MachOYAML::Object &Obj;
53 bool is64Bit;
54 uint64_t fileStart;
55
56 union {
57 MachO::mach_header_64 Header64;
58 MachO::mach_header Header;
59 };
60};
61
62Error MachOWriter::writeMachO(raw_ostream &OS) {
63 fileStart = OS.tell();
64 if (auto Err = writeHeader(OS))
65 return Err;
66 if (auto Err = writeLoadCommands(OS))
67 return Err;
68 if (auto Err = writeSectionData(OS))
69 return Err;
70 return Error::success();
71}
72
73Error MachOWriter::writeHeader(raw_ostream &OS) {
74 Header.magic = Obj.Header.magic;
75 Header.cputype = Obj.Header.cputype;
76 Header.cpusubtype = Obj.Header.cpusubtype;
77 Header.filetype = Obj.Header.filetype;
78 Header.ncmds = Obj.Header.ncmds;
79 Header.sizeofcmds = Obj.Header.sizeofcmds;
80 Header.flags = Obj.Header.flags;
81 Header64.reserved = Obj.Header.reserved;
82
83 if (is64Bit)
84 OS.write((const char *)&Header64, sizeof(MachO::mach_header_64));
85 else
86 OS.write((const char *)&Header, sizeof(MachO::mach_header));
87
88 return Error::success();
89}
90
91template <typename SectionType>
92SectionType constructSection(MachOYAML::Section Sec) {
93 SectionType TempSec;
94 memcpy(reinterpret_cast<void *>(&TempSec.sectname[0]), &Sec.sectname[0], 16);
95 memcpy(reinterpret_cast<void *>(&TempSec.segname[0]), &Sec.segname[0], 16);
96 TempSec.addr = Sec.addr;
97 TempSec.size = Sec.size;
98 TempSec.offset = Sec.offset;
99 TempSec.align = Sec.align;
100 TempSec.reloff = Sec.reloff;
101 TempSec.nreloc = Sec.nreloc;
102 TempSec.flags = Sec.flags;
103 TempSec.reserved1 = Sec.reserved1;
104 TempSec.reserved2 = Sec.reserved2;
105 return TempSec;
106}
107
108template <typename StructType>
109size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, raw_ostream &OS) {
110 return 0;
111}
112
113template <>
114size_t writeLoadCommandData<MachO::segment_command>(MachOYAML::LoadCommand &LC,
115 raw_ostream &OS) {
116 size_t BytesWritten = 0;
117 for (auto Sec : LC.Sections) {
118 auto TempSec = constructSection<MachO::section>(Sec);
119 OS.write(reinterpret_cast<const char *>(&(TempSec)),
120 sizeof(MachO::section));
121 BytesWritten += sizeof(MachO::section);
122 }
123 return BytesWritten;
124}
125
126template <>
127size_t
128writeLoadCommandData<MachO::segment_command_64>(MachOYAML::LoadCommand &LC,
129 raw_ostream &OS) {
130 size_t BytesWritten = 0;
131 for (auto Sec : LC.Sections) {
132 auto TempSec = constructSection<MachO::section_64>(Sec);
133 TempSec.reserved3 = Sec.reserved3;
134 OS.write(reinterpret_cast<const char *>(&(TempSec)),
135 sizeof(MachO::section_64));
136 BytesWritten += sizeof(MachO::section_64);
137 }
138 return BytesWritten;
139}
140
141size_t writePayloadString(MachOYAML::LoadCommand &LC, raw_ostream &OS) {
142 size_t BytesWritten = 0;
143 if (!LC.PayloadString.empty()) {
144 OS.write(LC.PayloadString.c_str(), LC.PayloadString.length());
145 BytesWritten = LC.PayloadString.length();
146 }
147 return BytesWritten;
148}
149
150template <>
151size_t writeLoadCommandData<MachO::dylib_command>(MachOYAML::LoadCommand &LC,
152 raw_ostream &OS) {
153 return writePayloadString(LC, OS);
154}
155
156template <>
157size_t writeLoadCommandData<MachO::dylinker_command>(MachOYAML::LoadCommand &LC,
158 raw_ostream &OS) {
159 return writePayloadString(LC, OS);
160}
161
162void ZeroFillBytes(raw_ostream &OS, size_t Size) {
163 std::vector<uint8_t> FillData;
164 FillData.insert(FillData.begin(), Size, 0);
165 OS.write(reinterpret_cast<char *>(FillData.data()), Size);
166}
167
168void Fill(raw_ostream &OS, size_t Size, uint32_t Data) {
169 std::vector<uint32_t> FillData;
170 FillData.insert(FillData.begin(), (Size / 4) + 1, Data);
171 OS.write(reinterpret_cast<char *>(FillData.data()), Size);
172}
173
174void MachOWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) {
175 auto currOffset = OS.tell() - fileStart;
176 if (currOffset < Offset)
177 ZeroFillBytes(OS, Offset - currOffset);
178}
179
180Error MachOWriter::writeLoadCommands(raw_ostream &OS) {
181 for (auto &LC : Obj.LoadCommands) {
182 size_t BytesWritten = 0;
183#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
184 case MachO::LCName: \
185 OS.write(reinterpret_cast<const char *>(&(LC.Data.LCStruct##_data)), \
186 sizeof(MachO::LCStruct)); \
187 BytesWritten = sizeof(MachO::LCStruct); \
188 BytesWritten += writeLoadCommandData<MachO::LCStruct>(LC, OS); \
189 break;
190
191 switch (LC.Data.load_command_data.cmd) {
192 default:
193 OS.write(reinterpret_cast<const char *>(&(LC.Data.load_command_data)),
194 sizeof(MachO::load_command));
195 BytesWritten = sizeof(MachO::load_command);
196 BytesWritten += writeLoadCommandData<MachO::load_command>(LC, OS);
197 break;
198#include "llvm/Support/MachO.def"
199 }
200
201 if (LC.PayloadBytes.size() > 0) {
202 OS.write(reinterpret_cast<const char *>(LC.PayloadBytes.data()),
203 LC.PayloadBytes.size());
204 BytesWritten += LC.PayloadBytes.size();
205 }
206
207 if (LC.ZeroPadBytes > 0) {
208 ZeroFillBytes(OS, LC.ZeroPadBytes);
209 BytesWritten += LC.ZeroPadBytes;
210 }
211
212 // Fill remaining bytes with 0. This will only get hit in partially
213 // specified test cases.
214 auto BytesRemaining = LC.Data.load_command_data.cmdsize - BytesWritten;
215 if (BytesRemaining > 0) {
216 ZeroFillBytes(OS, BytesRemaining);
217 }
218 }
219 return Error::success();
220}
221
222Error MachOWriter::writeSectionData(raw_ostream &OS) {
223 for (auto &LC : Obj.LoadCommands) {
224 switch (LC.Data.load_command_data.cmd) {
225 case MachO::LC_SEGMENT:
226 case MachO::LC_SEGMENT_64:
227 auto currOffset = OS.tell() - fileStart;
228 auto segname = LC.Data.segment_command_data.segname;
229 uint64_t segOff = is64Bit ? LC.Data.segment_command_64_data.fileoff
230 : LC.Data.segment_command_data.fileoff;
231
232 if (0 == strncmp(&segname[0], "__LINKEDIT", 16)) {
233 if (auto Err = writeLinkEditData(OS))
234 return Err;
235 } else {
236 // Zero Fill any data between the end of the last thing we wrote and the
237 // start of this section.
238 if (currOffset < segOff) {
239 ZeroFillBytes(OS, segOff - currOffset);
240 }
241
242 for (auto &Sec : LC.Sections) {
243 // Zero Fill any data between the end of the last thing we wrote and
244 // the
245 // start of this section.
246 assert(((OS.tell() - fileStart <= Sec.offset && "Wrote too much data somewhere, section offsets don't line up."
) ? static_cast<void> (0) : __assert_fail ("OS.tell() - fileStart <= Sec.offset && \"Wrote too much data somewhere, section offsets don't line up.\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn270899/tools/yaml2obj/yaml2macho.cpp"
, 248, __PRETTY_FUNCTION__))
247 OS.tell() - fileStart <= Sec.offset &&((OS.tell() - fileStart <= Sec.offset && "Wrote too much data somewhere, section offsets don't line up."
) ? static_cast<void> (0) : __assert_fail ("OS.tell() - fileStart <= Sec.offset && \"Wrote too much data somewhere, section offsets don't line up.\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn270899/tools/yaml2obj/yaml2macho.cpp"
, 248, __PRETTY_FUNCTION__))
248 "Wrote too much data somewhere, section offsets don't line up.")((OS.tell() - fileStart <= Sec.offset && "Wrote too much data somewhere, section offsets don't line up."
) ? static_cast<void> (0) : __assert_fail ("OS.tell() - fileStart <= Sec.offset && \"Wrote too much data somewhere, section offsets don't line up.\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn270899/tools/yaml2obj/yaml2macho.cpp"
, 248, __PRETTY_FUNCTION__))
;
249 currOffset = OS.tell() - fileStart;
250 if (currOffset < Sec.offset) {
251 ZeroFillBytes(OS, Sec.offset - currOffset);
252 }
253
254 // Fills section data with 0xDEADBEEF
255 Fill(OS, Sec.size, 0xDEADBEEFu);
256 }
257 }
258 uint64_t segSize = is64Bit ? LC.Data.segment_command_64_data.filesize
259 : LC.Data.segment_command_data.filesize;
260 ZeroToOffset(OS, segOff + segSize);
261 break;
262 }
263 }
264 return Error::success();
265}
266
267Error MachOWriter::writeLinkEditData(raw_ostream &OS) {
268 MachOYAML::LinkEditData &LinkEdit = Obj.LinkEdit;
269 MachO::dyld_info_command *DyldInfoOnlyCmd = 0;
270 MachO::symtab_command *SymtabCmd = 0;
1
'SymtabCmd' initialized to a null pointer value
271 for (auto &LC : Obj.LoadCommands) {
272 switch (LC.Data.load_command_data.cmd) {
2
Control jumps to 'case LC_DYLD_INFO_ONLY:' at line 276
273 case MachO::LC_SYMTAB:
274 SymtabCmd = &LC.Data.symtab_command_data;
275 break;
276 case MachO::LC_DYLD_INFO_ONLY:
277 DyldInfoOnlyCmd = &LC.Data.dyld_info_command_data;
278 break;
3
Execution continues on line 271
279 }
280 }
281
282 ZeroToOffset(OS, DyldInfoOnlyCmd->rebase_off);
283
284 for (auto Opcode : LinkEdit.RebaseOpcodes) {
285 uint8_t OpByte = Opcode.Opcode | Opcode.Imm;
286 OS.write(reinterpret_cast<char *>(&OpByte), 1);
287 for (auto Data : Opcode.ExtraData) {
288 encodeULEB128(Data, OS);
289 }
290 }
291
292 // Fill to the end of the string table
293 ZeroToOffset(OS, SymtabCmd->stroff + SymtabCmd->strsize);
4
Access to field 'stroff' results in a dereference of a null pointer (loaded from variable 'SymtabCmd')
294
295 return Error::success();
296}
297
298} // end anonymous namespace
299
300int yaml2macho(yaml::Input &YIn, raw_ostream &Out) {
301 MachOYAML::Object Doc;
302 YIn >> Doc;
303 if (YIn.error()) {
304 errs() << "yaml2obj: Failed to parse YAML file!\n";
305 return 1;
306 }
307
308 MachOWriter Writer(Doc);
309 if (auto Err = Writer.writeMachO(Out)) {
310 errs() << toString(std::move(Err));
311 return 1;
312 }
313 return 0;
314}