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

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: Fix nits. 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 maximun value for abbreviation indices in block.
jvoung (off chromium) 2015/05/13 00:58:16 maximun -> maximum
Karl 2015/05/13 21:39:24 Done.
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;
38 57
39 WriteState(const NaClMungedBitcode::WriteFlags &Flags) : Flags(Flags) {} 58 WriteState(const NaClMungedBitcode::WriteFlags &Flags) : Flags(Flags) {
59 BlockScope Scope(UnknownWriteBlockID, naclbitc::DEFAULT_MAX_ABBREV);
60 ScopeStack.push_back(Scope);
61 }
40 62
41 // Returns stream to print error message to. 63 // Returns stream to print error message to.
42 raw_ostream &Error() { 64 raw_ostream &Error();
43 ++Results.NumErrors;
44 return Flags.getErrStream() << "Error (Block " << WriteBlockID << "): ";
45 }
46 65
47 // Returns stream to print error message to, assuming that 66 // Returns stream to print error message to, assuming that
48 // the error message can be repaired if Flags.TryToRecover is true. 67 // the error message can be repaired if Flags.TryToRecover is true.
49 raw_ostream &RecoverableError() { 68 raw_ostream &RecoverableError() {
50 if (Flags.getTryToRecover()) 69 if (Flags.getTryToRecover())
51 ++Results.NumRepairs; 70 ++Results.NumRepairs;
52 return Error(); 71 return Error();
53 } 72 }
54 73
74 bool atOutermostScope() {
75 assert(!ScopeStack.empty());
76 return ScopeStack.size() == 1;
77 }
78
79 unsigned getCurWriteBlockID() const {
80 assert(!ScopeStack.empty());
81 return ScopeStack.back().CurBlockID;
82 }
83
84 unsigned getCurAbbrevIndexLimit() const {
85 assert(!ScopeStack.empty());
86 return ScopeStack.back().AbbrevIndexLimit;
87 }
88
55 // Converts the abbreviation record to the corresponding abbreviation. 89 // Converts the abbreviation record to the corresponding abbreviation.
56 // Returns nullptr if unable to build abbreviation. 90 // Returns nullptr if unable to build abbreviation.
57 NaClBitCodeAbbrev *buildAbbrev(const NaClBitcodeAbbrevRecord &Record); 91 NaClBitCodeAbbrev *buildAbbrev(const NaClBitcodeAbbrevRecord &Record);
58 92
59 // Emits the given record to the bitcode file. Returns true if 93 // Emits the given record to the bitcode file. Returns true if
60 // successful. 94 // successful.
61 bool emitRecord(NaClBitstreamWriter &Writer, 95 bool emitRecord(NaClBitstreamWriter &Writer,
62 const NaClBitcodeAbbrevRecord &Record); 96 const NaClBitcodeAbbrevRecord &Record);
63 97
64 // Adds any missing end blocks to written bitcode. 98 // Enter the given block
65 void writeMissingEndBlocks(NaClBitstreamWriter &Writer) { 99 bool enterBlock(NaClBitstreamWriter &Writer, unsigned WriteBlockID,
66 while (!AbbrevIndexLimitStack.empty()) { 100 unsigned NumBits, const NaClBitcodeAbbrevRecord &Record);
67 Writer.ExitBlock(); 101
68 AbbrevIndexLimitStack.pop_back(); 102 // Exit current block and return to previous block. Silently recovers
69 } 103 // if at outermost scope.
104 void exitBlock(NaClBitstreamWriter &Writer) {
105 Writer.ExitBlock();
106 ScopeStack.pop_back();
jvoung (off chromium) 2015/05/13 00:58:17 Hmm, I don't see how this prevents popping too muc
Karl 2015/05/13 21:39:24 Hmm, I'm confused too. Earlier versions had the ch
107 if (DebugEmit)
108 printScopeStack(errs());
109 }
110
111 // Completes the write.
112 NaClMungedBitcode::WriteResults &finish(NaClBitstreamWriter &Writer,
113 bool RecoverSilently = false);
114
115 void printScopeStack(raw_ostream &Out) {
116 Out << "Scope Stack:\n";
117 for (auto Scope : ScopeStack)
jvoung (off chromium) 2015/05/13 00:58:17 auto &Scope ? Not sure if this is one of those cas
Karl 2015/05/13 21:39:23 Done.
118 Out << " " << Scope << "\n";
70 } 119 }
71 }; 120 };
72 121
122 raw_ostream &WriteState::Error() {
123 ++Results.NumErrors;
124 raw_ostream &ErrStrm = Flags.getErrStream();
125 unsigned WriteBlockID = getCurWriteBlockID();
126 ErrStrm << "Error (Block ";
127 if (WriteBlockID == UnknownWriteBlockID)
128 ErrStrm << "unknown";
129 else
130 ErrStrm << WriteBlockID;
131 return ErrStrm << "): ";
132 }
133
134 bool WriteState::enterBlock(NaClBitstreamWriter &Writer, unsigned WriteBlockID,
135 unsigned NumBits,
136 const NaClBitcodeAbbrevRecord &Record) {
137 uint64_t MaxAbbrev = (static_cast<uint64_t>(1) << NumBits) - 1;
jvoung (off chromium) 2015/05/13 00:58:17 maybe assert NumBits < 64 or some smaller limit --
Karl 2015/05/13 21:39:23 Good point. The code reader/writer assumes 32. Add
138 BlockScope Scope(WriteBlockID, MaxAbbrev);
139 ScopeStack.push_back(Scope);
140 if (DebugEmit)
141 printScopeStack(errs());
142 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) {
143 unsigned DefaultMaxBits =
144 NaClBitsNeededForValue(naclbitc::DEFAULT_MAX_ABBREV);
145 if (NumBits != DefaultMaxBits) {
146 RecoverableError()
147 << "Numbits entry for abbreviations record not "
148 << DefaultMaxBits << " but found " << NumBits <<
149 ": " << Record << "\n";
150 if (!Flags.getTryToRecover())
151 return false;
152 }
153 Writer.EnterBlockInfoBlock();
154 } else {
155 NaClBitcodeSelectorAbbrev CurCodeLen(MaxAbbrev);
156 Writer.EnterSubblock(WriteBlockID, CurCodeLen);
157 }
158 return true;
159 }
160
161 NaClMungedBitcode::WriteResults & WriteState::finish(
jvoung (off chromium) 2015/05/13 00:58:17 flush the & in the return type to the right
Karl 2015/05/13 21:39:24 Done.
162 NaClBitstreamWriter &Writer, bool RecoverSilently) {
163 // Be sure blocks are balanced.
164 while (!atOutermostScope()) {
165 if (!RecoverSilently)
166 RecoverableError() << "Missing close block.\n";
167 exitBlock(Writer);
168 }
169
170 // Be sure that generated bitcode buffer is word aligned.
171 if (Writer.GetCurrentBitNo() % 4 * CHAR_BIT) {
172 if (!RecoverSilently)
173 RecoverableError() << "Written bitstream not word aligned\n";
174 // Force a repair so that the bitstream writer doesn't crash.
175 Writer.FlushToWord();
176 }
177 return Results;
178 }
179
73 bool WriteState::emitRecord(NaClBitstreamWriter &Writer, 180 bool WriteState::emitRecord(NaClBitstreamWriter &Writer,
74 const NaClBitcodeAbbrevRecord &Record) { 181 const NaClBitcodeAbbrevRecord &Record) {
75 size_t NumValues = Record.Values.size(); 182 size_t NumValues = Record.Values.size();
76 if (DebugEmitRecord) { 183 if (DebugEmit) {
77 errs() << "Emit " << Record.Abbrev << ": <" << Record.Code; 184 errs() << "Emit " << Record.Abbrev << ": <" << Record.Code;
78 for (size_t i = 0; i < NumValues; ++i) { 185 for (size_t i = 0; i < NumValues; ++i) {
79 errs() << ", " << Record.Values[i]; 186 errs() << ", " << Record.Values[i];
80 } 187 }
81 errs() << ">\n"; 188 errs() << ">\n";
82 } 189 }
83 190
84 switch (Record.Code) { 191 switch (Record.Code) {
85 case naclbitc::BLK_CODE_ENTER: { 192 case naclbitc::BLK_CODE_ENTER: {
86 unsigned NumBits = NaClBitsNeededForValue(naclbitc::DEFAULT_MAX_ABBREV); 193 unsigned MinNumBits = NaClBitsNeededForValue(naclbitc::DEFAULT_MAX_ABBREV);
87 WriteBlockID = -1; 194 unsigned WriteBlockID = UnknownWriteBlockID;
195 unsigned NumBits = MinNumBits;
88 if (Record.Abbrev != naclbitc::ENTER_SUBBLOCK) { 196 if (Record.Abbrev != naclbitc::ENTER_SUBBLOCK) {
89 RecoverableError() 197 RecoverableError()
90 << "Uses illegal abbreviation index in enter block record: " 198 << "Uses illegal abbreviation index in enter block record: "
91 << Record << "\n"; 199 << Record << "\n";
92 if (!Flags.getTryToRecover()) 200 if (!Flags.getTryToRecover())
93 return false; 201 return false;
94 } 202 }
95 if (NumValues == 2) { 203 if (NumValues != 2) {
96 WriteBlockID = Record.Values[0]; 204 RecoverableError()
97 NumBits = Record.Values[1]; 205 << "Values for enter record should be of size 2, but found "
98 if (NumBits > 32 || NumBits < 2) { 206 << NumValues << ": " << Record << "\n";
99 RecoverableError() 207 if (!Flags.getTryToRecover())
100 << "Bit size " << NumBits << " for record should be " 208 return false;
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 } 209 }
111 uint64_t MaxAbbrev = (static_cast<uint64_t>(1) << NumBits) - 1; 210 if (NumValues == 0)
112 AbbrevIndexLimitStack.push_back(MaxAbbrev); 211 return enterBlock(Writer, WriteBlockID, NumBits, Record);
113 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) { 212 WriteBlockID = Record.Values[0];
114 unsigned DefaultMaxBits = 213 if (Record.Values[0] > UINT_MAX) {
115 NaClBitsNeededForValue(naclbitc::DEFAULT_MAX_ABBREV); 214 RecoverableError() << "Block id must be less than << " << UINT_MAX
116 if (NumBits != DefaultMaxBits) { 215 << ": " << Record << "\n";
117 RecoverableError() 216 if (!Flags.getTryToRecover())
118 << "Numbits entry for abbreviations record not " 217 return false;
119 << DefaultMaxBits << " but found " << NumBits << 218 WriteBlockID = UnknownWriteBlockID;
120 ": " << Record << "\n"; 219 enterBlock(Writer, WriteBlockID, NumBits, Record);
jvoung (off chromium) 2015/05/13 00:58:17 return enterBlock(...); To avoid falling through
jvoung (off chromium) 2015/05/13 00:58:17 At this point, it's still possible for NumValues =
Karl 2015/05/13 21:39:24 Removing call to writeBlock(). Rather, let the cod
121 if (!Flags.getTryToRecover())
122 return false;
123 }
124 Writer.EnterBlockInfoBlock();
125 } else {
126 NaClBitcodeSelectorAbbrev CurCodeLen(MaxAbbrev);
127 Writer.EnterSubblock(WriteBlockID, CurCodeLen);
128 } 220 }
129 break; 221 if (NumValues < 2)
222 return enterBlock(Writer, WriteBlockID, NumBits, Record);
223 NumBits = Record.Values[1];
224 if (NumBits > 32 || MinNumBits < 2) {
jvoung (off chromium) 2015/05/13 00:58:17 "MinNumBits < 2" MinNumBits is pretty much a const
Karl 2015/05/13 21:39:24 Good catch. Using MinNumBits.
225 raw_ostream &ErrStrm = RecoverableError();
226 ErrStrm << "Bit size " << NumBits << " for record should be ";
227 if (NumBits > 32)
228 ErrStrm << "<= 32";
229 else
230 ErrStrm << ">= " << MinNumBits;
231 ErrStrm << ": " << Record << "\n";
232 if (!Flags.getTryToRecover())
233 return false;
234 NumBits = 32;
235 }
236 return enterBlock(Writer, WriteBlockID, NumBits, Record);
130 } 237 }
131 case naclbitc::BLK_CODE_EXIT: 238 case naclbitc::BLK_CODE_EXIT:
239 if (atOutermostScope()) {
240 RecoverableError()
241 << "Extraneous exit block: " << Record << "\n";
242 if (!Flags.getTryToRecover())
243 return false;
244 break;
245 }
132 if (Record.Abbrev != naclbitc::END_BLOCK) { 246 if (Record.Abbrev != naclbitc::END_BLOCK) {
133 RecoverableError() 247 RecoverableError()
134 << "Uses illegal abbreviation index in exit block record: " 248 << "Uses illegal abbreviation index in exit block record: "
135 << Record << "\n"; 249 << Record << "\n";
136 if (!Flags.getTryToRecover()) 250 if (!Flags.getTryToRecover())
137 return false; 251 return false;
138 } 252 }
139 if (NumValues != 0) { 253 if (NumValues != 0) {
140 RecoverableError() << "Exit block should not have values: " 254 RecoverableError() << "Exit block should not have values: "
141 << Record << "\n"; 255 << Record << "\n";
142 if (!Flags.getTryToRecover()) 256 if (!Flags.getTryToRecover())
143 return false; 257 return false;
144 } 258 }
145 if (!AbbrevIndexLimitStack.empty()) 259 exitBlock(Writer);
jvoung (off chromium) 2015/05/13 22:24:05 btw: I was about to suggest adding LLVM_ATTRIBUTE_
Karl 2015/05/14 17:08:11 Added and fixed code (3 cases). In all three, they
146 AbbrevIndexLimitStack.pop_back();
147 Writer.ExitBlock();
148 break; 260 break;
149 case naclbitc::BLK_CODE_DEFINE_ABBREV: { 261 case naclbitc::BLK_CODE_DEFINE_ABBREV: {
150 if (Record.Abbrev != naclbitc::DEFINE_ABBREV) { 262 if (Record.Abbrev != naclbitc::DEFINE_ABBREV) {
151 RecoverableError() 263 RecoverableError()
152 << "Uses illegal abbreviation index in define abbreviation record: " 264 << "Uses illegal abbreviation index in define abbreviation record: "
153 << Record << "\n"; 265 << Record << "\n";
154 if (!Flags.getTryToRecover()) 266 if (!Flags.getTryToRecover())
155 return false; 267 return false;
156 } 268 }
269 if (getCurWriteBlockID() != naclbitc::BLOCKINFO_BLOCK_ID
270 && Writer.getMaxCurAbbrevIndex() >= getCurAbbrevIndexLimit()) {
jvoung (off chromium) 2015/05/13 00:58:17 ">= " ">= "
Karl 2015/05/13 21:39:23 Done.
jvoung (off chromium) 2015/05/13 22:24:06 Ping =) >=
Karl 2015/05/14 17:08:11 Done.
271 RecoverableError() << "Exceeds abbreviation index limit of "
272 << getCurAbbrevIndexLimit() << ": " << Record << "\n";
273 // Recover by not writing.
274 return Flags.getTryToRecover();
275 }
157 NaClBitCodeAbbrev *Abbrev = buildAbbrev(Record); 276 NaClBitCodeAbbrev *Abbrev = buildAbbrev(Record);
158 if (Abbrev == NULL) 277 if (Abbrev == NULL)
159 return Flags.getTryToRecover(); 278 return Flags.getTryToRecover();
160 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) { 279 if (getCurWriteBlockID() == naclbitc::BLOCKINFO_BLOCK_ID) {
161 Writer.EmitBlockInfoAbbrev(SetBID, Abbrev); 280 Writer.EmitBlockInfoAbbrev(SetBID, Abbrev);
162 } else { 281 } else {
163 Writer.EmitAbbrev(Abbrev); 282 Writer.EmitAbbrev(Abbrev);
164 } 283 }
165 break; 284 break;
166 } 285 }
167 case naclbitc::BLK_CODE_HEADER: 286 case naclbitc::BLK_CODE_HEADER:
168 // Note: There is no abbreviation index here. Ignore. 287 // Note: There is no abbreviation index here. Ignore.
169 for (uint64_t Value : Record.Values) 288 for (uint64_t Value : Record.Values)
170 Writer.Emit(Value, 8); 289 Writer.Emit(Value, 8);
171 break; 290 break;
172 default: 291 default:
173 if (AbbrevIndexLimitStack.empty()) { 292 bool UsesDefaultAbbrev = Record.Abbrev == naclbitc::UNABBREV_RECORD;
174 Error() << "Can't write record outside record block: " << Record << "\n"; 293 if (atOutermostScope()) {
175 return false; 294 RecoverableError() << "Record outside block: " << Record << "\n";
295 if (!Flags.getTryToRecover())
296 return false;
297 // Create a dummy block to hold record.
298 enterBlock(Writer, UnknownWriteBlockID, naclbitc::DEFAULT_MAX_ABBREV,
299 Record);
300 UsesDefaultAbbrev = true;
176 } 301 }
177 bool UsesDefaultAbbrev = Record.Abbrev == naclbitc::UNABBREV_RECORD;
178 if (!UsesDefaultAbbrev 302 if (!UsesDefaultAbbrev
179 && !Writer.isUserRecordAbbreviation(Record.Abbrev)) { 303 && !Writer.isUserRecordAbbreviation(Record.Abbrev)) {
180 // Illegal abbreviation index found. 304 // Illegal abbreviation index found.
181 if (Flags.getWriteBadAbbrevIndex()) { 305 if (Flags.getWriteBadAbbrevIndex()) {
182 Error() << "Uses illegal abbreviation index: " << Record << "\n"; 306 Error() << "Uses illegal abbreviation index: " << Record << "\n";
183 // Generate bad abbreviation index so that the bitcode reader 307 // Generate bad abbreviation index so that the bitcode reader
184 // can be tested. 308 // can be tested, and then quit.
185 Results.WroteBadAbbrevIndex = true; 309 Results.WroteBadAbbrevIndex = true;
186 Writer.EmitCode(Record.Abbrev); 310 Writer.EmitCode(Record.Abbrev);
187 // Note: We need to close blocks or the bitcode Writer will terminate 311 finish(Writer, /* RecoverSilently = */ true);
188 // due to assertions. 312 return true;
189 writeMissingEndBlocks(Writer);
190 return false;
191 } 313 }
192 RecoverableError() << "Uses illegal abbreviation index: " 314 RecoverableError() << "Uses illegal abbreviation index: "
193 << Record << "\n"; 315 << Record << "\n";
194 if (!Flags.getTryToRecover()) 316 if (!Flags.getTryToRecover())
195 return false; 317 return false;
196 UsesDefaultAbbrev = true; 318 UsesDefaultAbbrev = true;
197 } 319 }
198 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID 320 if (getCurWriteBlockID() == naclbitc::BLOCKINFO_BLOCK_ID
199 && Record.Code == naclbitc::BLOCKINFO_CODE_SETBID) { 321 && Record.Code == naclbitc::BLOCKINFO_CODE_SETBID) {
200 // Note: SetBID records are handled by Writer->EmitBlockInfoAbbrev, 322 // Note: SetBID records are handled by Writer->EmitBlockInfoAbbrev,
201 // based on the SetBID value. Don't bother to generate SetBID record here. 323 // based on the SetBID value. Don't bother to generate SetBID record here.
202 // Rather just set SetBID and let call to Writer->EmitBlockInfoAbbrev 324 // Rather just set SetBID and let call to Writer->EmitBlockInfoAbbrev
203 // generate the SetBID record. 325 // generate the SetBID record.
204 if (NumValues != 1) { 326 if (NumValues != 1) {
205 Error() << "SetBID record expects 1 value but found " 327 Error() << "SetBID record expects 1 value but found "
206 << NumValues << ": " << Record << "\n"; 328 << NumValues << ": " << Record << "\n";
207 return false; 329 return false;
208 } 330 }
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 const WriteFlags &Flags) const { 437 const WriteFlags &Flags) const {
316 NaClBitstreamWriter Writer(Buffer); 438 NaClBitstreamWriter Writer(Buffer);
317 WriteState State(Flags); 439 WriteState State(Flags);
318 if (AddHeader) { 440 if (AddHeader) {
319 NaClWriteHeader(Writer, true); 441 NaClWriteHeader(Writer, true);
320 } 442 }
321 for (const NaClBitcodeAbbrevRecord &Record : *this) { 443 for (const NaClBitcodeAbbrevRecord &Record : *this) {
322 if (!State.emitRecord(Writer, Record)) 444 if (!State.emitRecord(Writer, Record))
323 break; 445 break;
324 } 446 }
325 if (!State.AbbrevIndexLimitStack.empty()) { 447 return State.finish(Writer);
326 State.RecoverableError()
327 << "Bitcode missing " << State.AbbrevIndexLimitStack.size()
328 << " close blocks.\n";
329 if (Flags.getTryToRecover())
330 State.writeMissingEndBlocks(Writer);
331 }
332 return State.Results;
333 } 448 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698