Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(244)

Side by Side Diff: lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp

Issue 1139673004: Harden writer of munged bitcode for fuzzing (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-llvm.git@master
Patch Set: Added more tests. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 //===- NaClBitcodeMungeWriter.cpp - Write munged bitcode --------*- C++ -*-===// 1 //===- NaClBitcodeMungeWriter.cpp - Write munged bitcode --------*- C++ -*-===//
2 // 2 //
3 // The LLVM Compiler Infrastructure 3 // The LLVM Compiler Infrastructure
4 // 4 //
5 // This file is distributed under the University of Illinois Open Source 5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details. 6 // License. See LICENSE.TXT for details.
7 // 7 //
8 //===----------------------------------------------------------------------===// 8 //===----------------------------------------------------------------------===//
9 // 9 //
10 // Implements method NaClMungedBitcode.write(), which writes out a munged 10 // Implements method NaClMungedBitcode.write(), which writes out a munged
11 // list of bitcode records using a bitstream writer. 11 // list of bitcode records using a bitstream writer.
12 12
13 #include "llvm/Bitcode/NaCl/NaClBitcodeMungeUtils.h" 13 #include "llvm/Bitcode/NaCl/NaClBitcodeMungeUtils.h"
14 14
15 #include "llvm/Bitcode/NaCl/NaClBitstreamWriter.h" 15 #include "llvm/Bitcode/NaCl/NaClBitstreamWriter.h"
16 #include "llvm/Bitcode/NaCl/NaClReaderWriter.h" 16 #include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
17 #include "llvm/Support/raw_ostream.h"
17 18
18 using namespace llvm; 19 using namespace llvm;
19 20
20 namespace { 21 namespace {
21 22
22 // For debugging. When true, shows each PNaCl record that is 23 // For debugging. When true, shows trace information of emitting
23 // emitted to the bitcode file. 24 // bitcode.
24 static bool DebugEmitRecord = false; 25 static bool DebugEmit = false;
26
27 // Description of current block scope
28 struct BlockScope {
29 BlockScope(unsigned CurBlockID, size_t AbbrevIndexLimit)
30 : CurBlockID(CurBlockID), AbbrevIndexLimit(AbbrevIndexLimit) {}
31 unsigned CurBlockID;
32 // Defines the maximum value for abbreviation indices in block.
33 size_t AbbrevIndexLimit;
34 void print(raw_ostream &Out) const {
35 Out << "BlockScope(ID=" << CurBlockID << ", AbbrevIndexLimit="
36 << AbbrevIndexLimit << ")";
37 }
38 };
39
40 inline raw_ostream &operator<<(raw_ostream &Out, const BlockScope &Scope) {
41 Scope.print(Out);
42 return Out;
43 }
25 44
26 // State of bitcode writing. 45 // State of bitcode writing.
27 struct WriteState { 46 struct WriteState {
28 // The block ID associated with the block being written. 47 // The block ID associated with records not in any block.
29 int WriteBlockID = -1; 48 static const unsigned UnknownWriteBlockID = UINT_MAX;
30 // The SetBID for the blockinfo block. 49 // The SetBID for the blockinfo block.
31 int SetBID = -1; 50 unsigned SetBID = UnknownWriteBlockID;
32 // The stack of maximum abbreviation indices allowed by block enter record. 51 // The stack of scopes the writer is in.
33 SmallVector<uint64_t, 3> AbbrevIndexLimitStack; 52 SmallVector<BlockScope, 3> ScopeStack;
34 // The set of write flags to use. 53 // The set of write flags to use.
35 const NaClMungedBitcode::WriteFlags &Flags; 54 const NaClMungedBitcode::WriteFlags &Flags;
36 // The results of the attempted write. 55 // The results of the attempted write.
37 NaClMungedBitcode::WriteResults Results; 56 NaClMungedBitcode::WriteResults Results;
57 // The miniumum number of bits allowed to be specified in a block.
jvoung (off chromium) 2015/05/13 22:24:06 miniumum -> minimum
Karl 2015/05/14 17:08:11 Done.
58 const unsigned BlockMinBits;
38 59
39 WriteState(const NaClMungedBitcode::WriteFlags &Flags) : Flags(Flags) {} 60 WriteState(const NaClMungedBitcode::WriteFlags &Flags)
61 : Flags(Flags),
62 BlockMinBits(NaClBitsNeededForValue(naclbitc::DEFAULT_MAX_ABBREV)) {
63 BlockScope Scope(UnknownWriteBlockID, naclbitc::DEFAULT_MAX_ABBREV);
64 ScopeStack.push_back(Scope);
65 }
40 66
41 // Returns stream to print error message to. 67 // Returns stream to print error message to.
42 raw_ostream &Error() { 68 raw_ostream &Error();
43 ++Results.NumErrors;
44 return Flags.getErrStream() << "Error (Block " << WriteBlockID << "): ";
45 }
46 69
47 // Returns stream to print error message to, assuming that 70 // Returns stream to print error message to, assuming that
48 // the error message can be repaired if Flags.TryToRecover is true. 71 // the error message can be repaired if Flags.TryToRecover is true.
49 raw_ostream &RecoverableError() { 72 raw_ostream &RecoverableError() {
50 if (Flags.getTryToRecover()) 73 if (Flags.getTryToRecover())
51 ++Results.NumRepairs; 74 ++Results.NumRepairs;
52 return Error(); 75 return Error();
53 } 76 }
54 77
78 bool atOutermostScope() {
79 assert(!ScopeStack.empty());
80 return ScopeStack.size() == 1;
81 }
82
83 unsigned getCurWriteBlockID() const {
84 assert(!ScopeStack.empty());
85 return ScopeStack.back().CurBlockID;
86 }
87
88 unsigned getCurAbbrevIndexLimit() const {
89 assert(!ScopeStack.empty());
90 return ScopeStack.back().AbbrevIndexLimit;
91 }
92
55 // Converts the abbreviation record to the corresponding abbreviation. 93 // Converts the abbreviation record to the corresponding abbreviation.
56 // Returns nullptr if unable to build abbreviation. 94 // Returns nullptr if unable to build abbreviation.
57 NaClBitCodeAbbrev *buildAbbrev(const NaClBitcodeAbbrevRecord &Record); 95 NaClBitCodeAbbrev *buildAbbrev(const NaClBitcodeAbbrevRecord &Record);
58 96
59 // Emits the given record to the bitcode file. Returns true if 97 // Emits the given record to the bitcode file. Returns true if
60 // successful. 98 // successful.
61 bool emitRecord(NaClBitstreamWriter &Writer, 99 bool emitRecord(NaClBitstreamWriter &Writer,
62 const NaClBitcodeAbbrevRecord &Record); 100 const NaClBitcodeAbbrevRecord &Record);
63 101
64 // Adds any missing end blocks to written bitcode. 102 // Enter the given block
65 void writeMissingEndBlocks(NaClBitstreamWriter &Writer) { 103 bool enterBlock(NaClBitstreamWriter &Writer, uint64_t WriteBlockID,
66 while (!AbbrevIndexLimitStack.empty()) { 104 uint64_t NumBits, const NaClBitcodeAbbrevRecord &Record);
67 Writer.ExitBlock(); 105
68 AbbrevIndexLimitStack.pop_back(); 106 // Exit current block and return to previous block. Silently recovers
69 } 107 // if at outermost scope.
108 bool exitBlock(NaClBitstreamWriter &Writer,
109 const NaClBitcodeAbbrevRecord *Record = nullptr) {
110 if (ScopeStack.empty())
jvoung (off chromium) 2015/05/13 22:24:06 how about if (atOutermostScope()) return false;
Karl 2015/05/14 17:08:11 Done.
111 return false;
112 Writer.ExitBlock();
113 ScopeStack.pop_back();
114 if (DebugEmit)
115 printScopeStack(errs());
116 return true;
117 }
118
119 // Completes the write.
120 NaClMungedBitcode::WriteResults &finish(NaClBitstreamWriter &Writer,
121 bool RecoverSilently);
122
123 void printScopeStack(raw_ostream &Out) {
124 Out << "Scope Stack:\n";
125 for (auto &Scope : ScopeStack)
126 Out << " " << Scope << "\n";
70 } 127 }
71 }; 128 };
72 129
130 raw_ostream &WriteState::Error() {
131 ++Results.NumErrors;
132 raw_ostream &ErrStrm = Flags.getErrStream();
133 unsigned WriteBlockID = getCurWriteBlockID();
134 ErrStrm << "Error (Block ";
135 if (WriteBlockID == UnknownWriteBlockID)
136 ErrStrm << "unknown";
137 else
138 ErrStrm << WriteBlockID;
139 return ErrStrm << "): ";
140 }
141
142 bool WriteState::enterBlock(NaClBitstreamWriter &Writer, uint64_t WriteBlockID,
143 uint64_t NumBits,
144 const NaClBitcodeAbbrevRecord &Record) {
145 if (NumBits < BlockMinBits || NumBits > naclbitc::MaxAbbrevWidth) {
146 RecoverableError()
147 << "Block index bit limit " << NumBits << " invalid. Must be in ["
148 << BlockMinBits << ".." << naclbitc::MaxAbbrevWidth << "]: "
149 << Record << "\n";
150 if (!Flags.getTryToRecover())
151 return false;
152 NumBits = naclbitc::MaxAbbrevWidth;
153 }
154 if (WriteBlockID > UINT_MAX) {
155 RecoverableError() << "Block id must be less than << " << UINT_MAX
156 << ": " << Record << "\n";
157 if (!Flags.getTryToRecover())
158 return false;
159 WriteBlockID = UnknownWriteBlockID;
160 }
161
162 uint64_t MaxAbbrev = (static_cast<uint64_t>(1) << NumBits) - 1;
163 BlockScope Scope(WriteBlockID, MaxAbbrev);
164 ScopeStack.push_back(Scope);
165 if (DebugEmit)
166 printScopeStack(errs());
167 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) {
168 unsigned DefaultMaxBits =
169 NaClBitsNeededForValue(naclbitc::DEFAULT_MAX_ABBREV);
170 if (NumBits != DefaultMaxBits) {
171 RecoverableError()
172 << "Numbits entry for abbreviations record not "
173 << DefaultMaxBits << " but found " << NumBits <<
174 ": " << Record << "\n";
175 if (!Flags.getTryToRecover())
176 return false;
177 }
178 Writer.EnterBlockInfoBlock();
179 } else {
180 NaClBitcodeSelectorAbbrev CurCodeLen(MaxAbbrev);
181 Writer.EnterSubblock(WriteBlockID, CurCodeLen);
182 }
183 return true;
184 }
185
186 NaClMungedBitcode::WriteResults &WriteState::finish(
187 NaClBitstreamWriter &Writer, bool RecoverSilently) {
188 // Be sure blocks are balanced.
189 while (!atOutermostScope()) {
190 if (!RecoverSilently)
191 RecoverableError() << "Missing close block.\n";
192 exitBlock(Writer);
193 }
194
195 // Be sure that generated bitcode buffer is word aligned.
196 if (Writer.GetCurrentBitNo() % 4 * CHAR_BIT) {
197 if (!RecoverSilently)
198 RecoverableError() << "Written bitstream not word aligned\n";
199 // Force a repair so that the bitstream writer doesn't crash.
200 Writer.FlushToWord();
201 }
202 return Results;
203 }
204
73 bool WriteState::emitRecord(NaClBitstreamWriter &Writer, 205 bool WriteState::emitRecord(NaClBitstreamWriter &Writer,
74 const NaClBitcodeAbbrevRecord &Record) { 206 const NaClBitcodeAbbrevRecord &Record) {
75 size_t NumValues = Record.Values.size(); 207 size_t NumValues = Record.Values.size();
76 if (DebugEmitRecord) { 208 if (DebugEmit) {
77 errs() << "Emit " << Record.Abbrev << ": <" << Record.Code; 209 errs() << "Emit " << Record.Abbrev << ": <" << Record.Code;
78 for (size_t i = 0; i < NumValues; ++i) { 210 for (size_t i = 0; i < NumValues; ++i) {
79 errs() << ", " << Record.Values[i]; 211 errs() << ", " << Record.Values[i];
80 } 212 }
81 errs() << ">\n"; 213 errs() << ">\n";
82 } 214 }
83 215
84 switch (Record.Code) { 216 switch (Record.Code) {
85 case naclbitc::BLK_CODE_ENTER: { 217 case naclbitc::BLK_CODE_ENTER: {
86 unsigned NumBits = NaClBitsNeededForValue(naclbitc::DEFAULT_MAX_ABBREV); 218 uint64_t WriteBlockID = UnknownWriteBlockID;
87 WriteBlockID = -1; 219 uint64_t NumBits = naclbitc::MaxAbbrevWidth; // Default to safest value.
88 if (Record.Abbrev != naclbitc::ENTER_SUBBLOCK) { 220 if (Record.Abbrev != naclbitc::ENTER_SUBBLOCK) {
89 RecoverableError() 221 RecoverableError()
90 << "Uses illegal abbreviation index in enter block record: " 222 << "Uses illegal abbreviation index in enter block record: "
91 << Record << "\n"; 223 << Record << "\n";
92 if (!Flags.getTryToRecover()) 224 if (!Flags.getTryToRecover())
93 return false; 225 return false;
94 } 226 }
95 if (NumValues == 2) { 227 if (NumValues != 2) {
228 RecoverableError()
229 << "Values for enter record should be of size 2, but found "
230 << NumValues << ": " << Record << "\n";
231 if (!Flags.getTryToRecover())
232 return false;
233 }
234 if (NumValues > 0)
96 WriteBlockID = Record.Values[0]; 235 WriteBlockID = Record.Values[0];
236 if (NumValues > 1)
97 NumBits = Record.Values[1]; 237 NumBits = Record.Values[1];
98 if (NumBits > 32 || NumBits < 2) { 238 return enterBlock(Writer, WriteBlockID, NumBits, Record);
99 RecoverableError()
100 << "Bit size " << NumBits << " for record should be "
101 << (NumBits > 32 ? "<= 32" : ">= 2") << ": " << Record << "\n";
102 if (!Flags.getTryToRecover())
103 return false;
104 NumBits = 32;
105 }
106 } else {
107 Error() << "Values for enter record should be of size 2, but found "
108 << NumValues << ": " << Record << "\n";
109 return false;
110 }
111 uint64_t MaxAbbrev = (static_cast<uint64_t>(1) << NumBits) - 1;
112 AbbrevIndexLimitStack.push_back(MaxAbbrev);
113 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) {
114 unsigned DefaultMaxBits =
115 NaClBitsNeededForValue(naclbitc::DEFAULT_MAX_ABBREV);
116 if (NumBits != DefaultMaxBits) {
117 RecoverableError()
118 << "Numbits entry for abbreviations record not "
119 << DefaultMaxBits << " but found " << NumBits <<
120 ": " << Record << "\n";
121 if (!Flags.getTryToRecover())
122 return false;
123 }
124 Writer.EnterBlockInfoBlock();
125 } else {
126 NaClBitcodeSelectorAbbrev CurCodeLen(MaxAbbrev);
127 Writer.EnterSubblock(WriteBlockID, CurCodeLen);
128 }
129 break;
130 } 239 }
131 case naclbitc::BLK_CODE_EXIT: 240 case naclbitc::BLK_CODE_EXIT:
241 if (atOutermostScope()) {
242 RecoverableError()
243 << "Extraneous exit block: " << Record << "\n";
244 if (!Flags.getTryToRecover())
245 return false;
246 break;
247 }
132 if (Record.Abbrev != naclbitc::END_BLOCK) { 248 if (Record.Abbrev != naclbitc::END_BLOCK) {
133 RecoverableError() 249 RecoverableError()
134 << "Uses illegal abbreviation index in exit block record: " 250 << "Uses illegal abbreviation index in exit block record: "
135 << Record << "\n"; 251 << Record << "\n";
136 if (!Flags.getTryToRecover()) 252 if (!Flags.getTryToRecover())
137 return false; 253 return false;
138 } 254 }
139 if (NumValues != 0) { 255 if (NumValues != 0) {
140 RecoverableError() << "Exit block should not have values: " 256 RecoverableError() << "Exit block should not have values: "
141 << Record << "\n"; 257 << Record << "\n";
142 if (!Flags.getTryToRecover()) 258 if (!Flags.getTryToRecover())
143 return false; 259 return false;
144 } 260 }
145 if (!AbbrevIndexLimitStack.empty()) 261 if (!exitBlock(Writer)) {
146 AbbrevIndexLimitStack.pop_back(); 262 RecoverableError() << "Extraneous exit block: " << Record << "\n";
147 Writer.ExitBlock(); 263 if (!Flags.getTryToRecover())
264 return false;
265 }
148 break; 266 break;
149 case naclbitc::BLK_CODE_DEFINE_ABBREV: { 267 case naclbitc::BLK_CODE_DEFINE_ABBREV: {
150 if (Record.Abbrev != naclbitc::DEFINE_ABBREV) { 268 if (Record.Abbrev != naclbitc::DEFINE_ABBREV) {
151 RecoverableError() 269 RecoverableError()
152 << "Uses illegal abbreviation index in define abbreviation record: " 270 << "Uses illegal abbreviation index in define abbreviation record: "
153 << Record << "\n"; 271 << Record << "\n";
154 if (!Flags.getTryToRecover()) 272 if (!Flags.getTryToRecover())
155 return false; 273 return false;
156 } 274 }
275 if (getCurWriteBlockID() != naclbitc::BLOCKINFO_BLOCK_ID
276 && Writer.getMaxCurAbbrevIndex() >= getCurAbbrevIndexLimit()) {
277 RecoverableError() << "Exceeds abbreviation index limit of "
278 << getCurAbbrevIndexLimit() << ": " << Record << "\n";
279 // Recover by not writing.
280 return Flags.getTryToRecover();
281 }
157 NaClBitCodeAbbrev *Abbrev = buildAbbrev(Record); 282 NaClBitCodeAbbrev *Abbrev = buildAbbrev(Record);
158 if (Abbrev == NULL) 283 if (Abbrev == NULL)
159 return Flags.getTryToRecover(); 284 return Flags.getTryToRecover();
160 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) { 285 if (getCurWriteBlockID() == naclbitc::BLOCKINFO_BLOCK_ID) {
161 Writer.EmitBlockInfoAbbrev(SetBID, Abbrev); 286 Writer.EmitBlockInfoAbbrev(SetBID, Abbrev);
162 } else { 287 } else {
163 Writer.EmitAbbrev(Abbrev); 288 Writer.EmitAbbrev(Abbrev);
164 } 289 }
165 break; 290 break;
166 } 291 }
167 case naclbitc::BLK_CODE_HEADER: 292 case naclbitc::BLK_CODE_HEADER:
168 // Note: There is no abbreviation index here. Ignore. 293 // Note: There is no abbreviation index here. Ignore.
169 for (uint64_t Value : Record.Values) 294 for (uint64_t Value : Record.Values)
170 Writer.Emit(Value, 8); 295 Writer.Emit(Value, 8);
171 break; 296 break;
172 default: 297 default:
173 if (AbbrevIndexLimitStack.empty()) { 298 bool UsesDefaultAbbrev = Record.Abbrev == naclbitc::UNABBREV_RECORD;
174 Error() << "Can't write record outside record block: " << Record << "\n"; 299 if (atOutermostScope()) {
175 return false; 300 RecoverableError() << "Record outside block: " << Record << "\n";
301 if (!Flags.getTryToRecover())
302 return false;
303 // Create a dummy block to hold record.
304 enterBlock(Writer, UnknownWriteBlockID, naclbitc::DEFAULT_MAX_ABBREV,
305 Record);
306 UsesDefaultAbbrev = true;
176 } 307 }
177 bool UsesDefaultAbbrev = Record.Abbrev == naclbitc::UNABBREV_RECORD;
178 if (!UsesDefaultAbbrev 308 if (!UsesDefaultAbbrev
179 && !Writer.isUserRecordAbbreviation(Record.Abbrev)) { 309 && !Writer.isUserRecordAbbreviation(Record.Abbrev)) {
180 // Illegal abbreviation index found. 310 // Illegal abbreviation index found.
181 if (Flags.getWriteBadAbbrevIndex()) { 311 if (Flags.getWriteBadAbbrevIndex()) {
182 Error() << "Uses illegal abbreviation index: " << Record << "\n"; 312 Error() << "Uses illegal abbreviation index: " << Record << "\n";
183 // Generate bad abbreviation index so that the bitcode reader 313 // Generate bad abbreviation index so that the bitcode reader
184 // can be tested. 314 // can be tested, and then quit.
185 Results.WroteBadAbbrevIndex = true; 315 Results.WroteBadAbbrevIndex = true;
186 Writer.EmitCode(Record.Abbrev); 316 Writer.EmitCode(Record.Abbrev);
187 // Note: We need to close blocks or the bitcode Writer will terminate 317 bool RecoverSilently = true;
188 // due to assertions. 318 finish(Writer, RecoverSilently);
189 writeMissingEndBlocks(Writer);
190 return false; 319 return false;
191 } 320 }
192 RecoverableError() << "Uses illegal abbreviation index: " 321 RecoverableError() << "Uses illegal abbreviation index: "
193 << Record << "\n"; 322 << Record << "\n";
194 if (!Flags.getTryToRecover()) 323 if (!Flags.getTryToRecover())
195 return false; 324 return false;
196 UsesDefaultAbbrev = true; 325 UsesDefaultAbbrev = true;
197 } 326 }
198 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID 327 if (getCurWriteBlockID() == naclbitc::BLOCKINFO_BLOCK_ID
199 && Record.Code == naclbitc::BLOCKINFO_CODE_SETBID) { 328 && Record.Code == naclbitc::BLOCKINFO_CODE_SETBID) {
200 // Note: SetBID records are handled by Writer->EmitBlockInfoAbbrev, 329 // Note: SetBID records are handled by Writer->EmitBlockInfoAbbrev,
201 // based on the SetBID value. Don't bother to generate SetBID record here. 330 // based on the SetBID value. Don't bother to generate SetBID record here.
202 // Rather just set SetBID and let call to Writer->EmitBlockInfoAbbrev 331 // Rather just set SetBID and let call to Writer->EmitBlockInfoAbbrev
203 // generate the SetBID record. 332 // generate the SetBID record.
204 if (NumValues != 1) { 333 if (NumValues != 1) {
205 Error() << "SetBID record expects 1 value but found " 334 Error() << "SetBID record expects 1 value but found "
206 << NumValues << ": " << Record << "\n"; 335 << NumValues << ": " << Record << "\n";
207 return false; 336 return false;
208 } 337 }
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 const WriteFlags &Flags) const { 444 const WriteFlags &Flags) const {
316 NaClBitstreamWriter Writer(Buffer); 445 NaClBitstreamWriter Writer(Buffer);
317 WriteState State(Flags); 446 WriteState State(Flags);
318 if (AddHeader) { 447 if (AddHeader) {
319 NaClWriteHeader(Writer, true); 448 NaClWriteHeader(Writer, true);
320 } 449 }
321 for (const NaClBitcodeAbbrevRecord &Record : *this) { 450 for (const NaClBitcodeAbbrevRecord &Record : *this) {
322 if (!State.emitRecord(Writer, Record)) 451 if (!State.emitRecord(Writer, Record))
323 break; 452 break;
324 } 453 }
325 if (!State.AbbrevIndexLimitStack.empty()) { 454 bool RecoverSilently =
326 State.RecoverableError() 455 State.Results.NumErrors > 0 && !Flags.getTryToRecover();
327 << "Bitcode missing " << State.AbbrevIndexLimitStack.size() 456 return State.finish(Writer, RecoverSilently);
328 << " close blocks.\n";
329 if (Flags.getTryToRecover())
330 State.writeMissingEndBlocks(Writer);
331 }
332 return State.Results;
333 } 457 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698