Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit e439162

Browse files
committed
Fix abbreviation handling in munged bitcode writer.
The bitstream writer assumes several properties, and will fail (either through assert or core dump) if these properties aren't true. Fixing munged bitcode writer to handle the following assumptions: 1) Don't write out an abbreviation if the abbreviation can't be applied to the record. 2) Don't write out an abbreviation definition if the record doesn't define a valid abbreviation (previous code was checking this, but not correctly for the abbreviation operand). 3) Don't use abbreviations whose abbreviation index is larger than couldn't be written out (case 2). Such indices will be broken because the bitstream reader doesn't correctly match. BUG=https://code.google.com/p/nativeclient/issues/detail?id=4169 [email protected] Review URL: https://codereview.chromium.org/1146203003
1 parent 65bb2dd commit e439162

File tree

3 files changed

+350
-60
lines changed

3 files changed

+350
-60
lines changed

include/llvm/Bitcode/NaCl/NaClBitstreamWriter.h

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,14 @@ class NaClBitstreamWriter {
4444
std::vector<NaClBitCodeAbbrev*> CurAbbrevs;
4545

4646
struct Block {
47-
NaClBitcodeSelectorAbbrev PrevCodeSize;
48-
unsigned StartSizeWord;
47+
const NaClBitcodeSelectorAbbrev PrevCodeSize;
48+
const unsigned StartSizeWord;
4949
std::vector<NaClBitCodeAbbrev*> PrevAbbrevs;
50-
Block(const NaClBitcodeSelectorAbbrev& PCS, unsigned SSW)
51-
: PrevCodeSize(PCS), StartSizeWord(SSW) {}
50+
const unsigned AbbreviationIndexLimit;
51+
Block(const NaClBitcodeSelectorAbbrev& PCS, unsigned SSW,
52+
unsigned AbbreviationIndexLimit)
53+
: PrevCodeSize(PCS), StartSizeWord(SSW),
54+
AbbreviationIndexLimit(AbbreviationIndexLimit) {}
5255
};
5356

5457
/// BlockScope - This tracks the current blocks that we have entered.
@@ -158,11 +161,15 @@ class NaClBitstreamWriter {
158161
// Basic Primitives for emitting bits to the stream.
159162
//===--------------------------------------------------------------------===//
160163

164+
// Max Number of bits that can be written using Emit.
165+
static const unsigned MaxEmitNumBits = 32;
166+
161167
void Emit(uint32_t Val, unsigned NumBits) {
162-
assert(NumBits && NumBits <= 32 && "Invalid value size!");
163-
assert((Val & ~(~0U >> (32-NumBits))) == 0 && "High bits set!");
168+
assert(NumBits && NumBits <= MaxEmitNumBits && "Invalid value size!");
169+
assert((Val &
170+
~(~0U >> (MaxEmitNumBits-NumBits))) == 0 && "High bits set!");
164171
CurValue |= Val << CurBit;
165-
if (CurBit + NumBits < 32) {
172+
if (CurBit + NumBits < MaxEmitNumBits) {
166173
CurBit += NumBits;
167174
return;
168175
}
@@ -171,19 +178,19 @@ class NaClBitstreamWriter {
171178
WriteWord(CurValue);
172179

173180
if (CurBit)
174-
CurValue = Val >> (32-CurBit);
181+
CurValue = Val >> (MaxEmitNumBits-CurBit);
175182
else
176183
CurValue = 0;
177-
CurBit = (CurBit+NumBits) & 31;
184+
CurBit = (CurBit+NumBits) & (MaxEmitNumBits-1);
178185
}
179186

180187
void Emit64(uint64_t Val, unsigned NumBits) {
181-
if (NumBits <= 32)
182-
Emit((uint32_t)Val, NumBits);
183-
else {
184-
Emit((uint32_t)Val, 32);
185-
Emit((uint32_t)(Val >> 32), NumBits-32);
188+
while (NumBits > MaxEmitNumBits) {
189+
Emit((uint32_t)Val, MaxEmitNumBits);
190+
Val >>= MaxEmitNumBits;
191+
NumBits -= MaxEmitNumBits;
186192
}
193+
Emit((uint32_t)Val, NumBits);
187194
}
188195

189196
void flushToByte() {
@@ -287,7 +294,8 @@ class NaClBitstreamWriter {
287294

288295
// Push the outer block's abbrev set onto the stack, start out with an
289296
// empty abbrev set.
290-
BlockScope.push_back(Block(OldCodeSize, BlockSizeWordIndex));
297+
BlockScope.push_back(Block(OldCodeSize, BlockSizeWordIndex,
298+
1 << CodeLen.NumBits));
291299
BlockScope.back().PrevAbbrevs.swap(CurAbbrevs);
292300

293301
// If there is a blockinfo for this BlockID, add all the predefined abbrevs
@@ -389,9 +397,8 @@ class NaClBitstreamWriter {
389397
template<typename uintty>
390398
void EmitRecordWithAbbrevImpl(unsigned Abbrev,
391399
const AbbrevValues<uintty> &Vals) {
392-
unsigned AbbrevNo = Abbrev-naclbitc::FIRST_APPLICATION_ABBREV;
393-
assert(AbbrevNo < CurAbbrevs.size() && "Invalid abbrev #!");
394-
NaClBitCodeAbbrev *Abbv = CurAbbrevs[AbbrevNo];
400+
const NaClBitCodeAbbrev *Abbv = getAbbreviation(Abbrev);
401+
assert(Abbv && "Abbreviation index is invalid");
395402

396403
EmitCode(Abbrev);
397404

@@ -421,11 +428,17 @@ class NaClBitstreamWriter {
421428

422429
public:
423430

424-
/// Returns true if the given abbreviation index corresponds to a user-defined
425-
/// abbreviation.
426-
bool isUserRecordAbbreviation(unsigned Abbrev) const {
427-
return Abbrev >= naclbitc::FIRST_APPLICATION_ABBREV
428-
&& Abbrev < (CurAbbrevs.size() + naclbitc::FIRST_APPLICATION_ABBREV);
431+
/// Returns a pointer to the abbreviation currently associated with
432+
/// the abbreviation index. Returns nullptr if no such abbreviation.
433+
const NaClBitCodeAbbrev *getAbbreviation(unsigned Index) const {
434+
if (Index < naclbitc::FIRST_APPLICATION_ABBREV)
435+
return nullptr;
436+
if (Index >= BlockScope.back().AbbreviationIndexLimit)
437+
return nullptr;
438+
unsigned AbbrevNo = Index - naclbitc::FIRST_APPLICATION_ABBREV;
439+
if (AbbrevNo >= CurAbbrevs.size())
440+
return nullptr;
441+
return CurAbbrevs[AbbrevNo];
429442
}
430443

431444
/// EmitRecord - Emit the specified record to the stream, using an abbrev if

lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp

Lines changed: 128 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
1717
#include "llvm/Support/raw_ostream.h"
1818

19+
#include <set>
20+
1921
using namespace llvm;
2022

2123
namespace {
@@ -27,13 +29,19 @@ static bool DebugEmit = false;
2729
// Description of current block scope
2830
struct BlockScope {
2931
BlockScope(unsigned CurBlockID, size_t AbbrevIndexLimit)
30-
: CurBlockID(CurBlockID), AbbrevIndexLimit(AbbrevIndexLimit) {}
32+
: CurBlockID(CurBlockID), AbbrevIndexLimit(AbbrevIndexLimit),
33+
OmittedAbbreviations(false) {}
3134
unsigned CurBlockID;
3235
// Defines the maximum value for abbreviation indices in block.
3336
size_t AbbrevIndexLimit;
37+
// Defines if an abbreviation definition was omitted (i.e. not
38+
// written) from this block. Used to turn off writing further
39+
// abbreviation definitions for this block.
40+
bool OmittedAbbreviations;
3441
void print(raw_ostream &Out) const {
3542
Out << "BlockScope(ID=" << CurBlockID << ", AbbrevIndexLimit="
36-
<< AbbrevIndexLimit << ")";
43+
<< AbbrevIndexLimit << "OmittedAbbreviations="
44+
<< OmittedAbbreviations << ")";
3745
}
3846
};
3947

@@ -49,13 +57,16 @@ struct WriteState {
4957
// The SetBID for the blockinfo block.
5058
unsigned SetBID = UnknownWriteBlockID;
5159
// The stack of scopes the writer is in.
52-
SmallVector<BlockScope, 3> ScopeStack;
60+
SmallVector<BlockScope, 4> ScopeStack;
5361
// The set of write flags to use.
5462
const NaClMungedBitcode::WriteFlags &Flags;
5563
// The results of the attempted write.
5664
NaClMungedBitcode::WriteResults Results;
5765
// The minimum number of bits allowed to be specified in a block.
5866
const unsigned BlockMinBits;
67+
// The set of block IDs for which abbreviation definitions have been
68+
// omitted in the blockinfo block.
69+
std::set<unsigned> BlocksWithOmittedAbbrevs;
5970

6071
WriteState(const NaClMungedBitcode::WriteFlags &Flags)
6172
: Flags(Flags),
@@ -90,14 +101,32 @@ struct WriteState {
90101
return ScopeStack.back().AbbrevIndexLimit;
91102
}
92103

104+
// Returns whether any abbreviation definitions were not written to
105+
// the bitcode buffer.
106+
bool curBlockHasOmittedAbbreviations() const {
107+
assert(!ScopeStack.empty());
108+
return ScopeStack.back().OmittedAbbreviations
109+
|| BlocksWithOmittedAbbrevs.count(getCurWriteBlockID());
110+
}
111+
112+
// Marks that an abbreviation definition is being omitted (i.e. not
113+
// written) for the current block.
114+
void markCurrentBlockWithOmittedAbbreviations() {
115+
assert(!ScopeStack.empty());
116+
ScopeStack.back().OmittedAbbreviations = true;
117+
if (getCurWriteBlockID() == naclbitc::BLOCKINFO_BLOCK_ID)
118+
BlocksWithOmittedAbbrevs.insert(SetBID);
119+
}
120+
93121
// Converts the abbreviation record to the corresponding abbreviation.
94122
// Returns nullptr if unable to build abbreviation.
95123
NaClBitCodeAbbrev *buildAbbrev(const NaClBitcodeAbbrevRecord &Record);
96124

97125
// Emits the given record to the bitcode file. Returns true if
98126
// successful.
99127
bool LLVM_ATTRIBUTE_UNUSED_RESULT
100-
emitRecord(NaClBitstreamWriter &Writer, const NaClBitcodeAbbrevRecord &Record);
128+
emitRecord(NaClBitstreamWriter &Writer,
129+
const NaClBitcodeAbbrevRecord &Record);
101130

102131
// Enter the given block
103132
bool LLVM_ATTRIBUTE_UNUSED_RESULT
@@ -118,6 +147,21 @@ struct WriteState {
118147
return true;
119148
}
120149

150+
void WriteRecord(NaClBitstreamWriter &Writer,
151+
const NaClBitcodeAbbrevRecord &Record,
152+
bool UsesDefaultAbbrev) {
153+
if (UsesDefaultAbbrev)
154+
Writer.EmitRecord(Record.Code, Record.Values);
155+
else
156+
Writer.EmitRecord(Record.Code, Record.Values, Record.Abbrev);
157+
}
158+
159+
// Returns true if the abbreviation index defines an abbreviation
160+
// that can be applied to the record.
161+
bool LLVM_ATTRIBUTE_UNUSED_RESULT
162+
canApplyAbbreviation(NaClBitstreamWriter &Writer,
163+
const NaClBitcodeAbbrevRecord &Record);
164+
121165
// Completes the write.
122166
NaClMungedBitcode::WriteResults &finish(NaClBitstreamWriter &Writer,
123167
bool RecoverSilently);
@@ -185,6 +229,55 @@ bool WriteState::enterBlock(NaClBitstreamWriter &Writer, uint64_t WriteBlockID,
185229
return true;
186230
}
187231

232+
bool WriteState::canApplyAbbreviation(
233+
NaClBitstreamWriter &Writer, const NaClBitcodeAbbrevRecord &Record) {
234+
const NaClBitCodeAbbrev *Abbrev = Writer.getAbbreviation(Record.Abbrev);
235+
if (Abbrev == nullptr)
236+
return false;
237+
238+
// Merge record code into values and then match abbreviation.
239+
NaClBitcodeValues Values(Record);
240+
size_t ValueIndex = 0;
241+
size_t ValuesSize = Values.size();
242+
size_t AbbrevIndex = 0;
243+
size_t AbbrevSize = Abbrev->getNumOperandInfos();
244+
bool FoundArray = false;
245+
while (ValueIndex < ValuesSize && AbbrevIndex < AbbrevSize) {
246+
const NaClBitCodeAbbrevOp *Op = &Abbrev->getOperandInfo(AbbrevIndex++);
247+
uint64_t Value = Values[ValueIndex++];
248+
if (Op->getEncoding() == NaClBitCodeAbbrevOp::Array) {
249+
if (AbbrevIndex + 1 != AbbrevSize)
250+
return false;
251+
Op = &Abbrev->getOperandInfo(AbbrevIndex);
252+
--AbbrevIndex; // i.e. don't advance to next abbreviation op.
253+
FoundArray = true;
254+
}
255+
switch (Op->getEncoding()) {
256+
case NaClBitCodeAbbrevOp::Literal:
257+
if (Value != Op->getValue())
258+
return false;
259+
continue;
260+
case NaClBitCodeAbbrevOp::Fixed:
261+
if (Value >= (static_cast<uint64_t>(1)
262+
<< NaClBitstreamWriter::MaxEmitNumBits)
263+
|| NaClBitsNeededForValue(Value) > Op->getValue())
264+
return false;
265+
continue;
266+
case NaClBitCodeAbbrevOp::VBR:
267+
if (Op->getValue() < 2)
268+
return false;
269+
continue;
270+
case NaClBitCodeAbbrevOp::Array:
271+
llvm_unreachable("Array(Array) abbreviation is not legal!");
272+
case NaClBitCodeAbbrevOp::Char6:
273+
if (!Op->isChar6(Value))
274+
return false;
275+
continue;
276+
}
277+
}
278+
return ValueIndex == ValuesSize && (FoundArray || AbbrevIndex == AbbrevSize);
279+
}
280+
188281
NaClMungedBitcode::WriteResults &WriteState::finish(
189282
NaClBitstreamWriter &Writer, bool RecoverSilently) {
190283
// Be sure blocks are balanced.
@@ -271,23 +364,24 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer,
271364
break;
272365
}
273366
case naclbitc::BLK_CODE_DEFINE_ABBREV: {
367+
if (curBlockHasOmittedAbbreviations()) {
368+
// If reached, a previous abbreviation for the block was omitted. Can't
369+
// generate more abbreviations without having to fix abbreviation indices.
370+
RecoverableError() << "Ignoring abbreviation: " << Record << "\n";
371+
return Flags.getTryToRecover();
372+
}
274373
if (Record.Abbrev != naclbitc::DEFINE_ABBREV) {
275374
RecoverableError()
276375
<< "Uses illegal abbreviation index in define abbreviation record: "
277376
<< Record << "\n";
278377
if (!Flags.getTryToRecover())
279378
return false;
280379
}
281-
if (getCurWriteBlockID() != naclbitc::BLOCKINFO_BLOCK_ID
282-
&& Writer.getMaxCurAbbrevIndex() >= getCurAbbrevIndexLimit()) {
283-
RecoverableError() << "Exceeds abbreviation index limit of "
284-
<< getCurAbbrevIndexLimit() << ": " << Record << "\n";
285-
// Recover by not writing.
286-
return Flags.getTryToRecover();
287-
}
288380
NaClBitCodeAbbrev *Abbrev = buildAbbrev(Record);
289-
if (Abbrev == NULL)
381+
if (Abbrev == nullptr) {
382+
markCurrentBlockWithOmittedAbbreviations();
290383
return Flags.getTryToRecover();
384+
}
291385
if (getCurWriteBlockID() == naclbitc::BLOCKINFO_BLOCK_ID) {
292386
Writer.EmitBlockInfoAbbrev(SetBID, Abbrev);
293387
} else {
@@ -314,10 +408,21 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer,
314408
}
315409
UsesDefaultAbbrev = true;
316410
}
317-
if (!UsesDefaultAbbrev
318-
&& !Writer.isUserRecordAbbreviation(Record.Abbrev)) {
319-
// Illegal abbreviation index found.
411+
if (!UsesDefaultAbbrev && !canApplyAbbreviation(Writer, Record)) {
412+
if (Writer.getAbbreviation(Record.Abbrev) != nullptr) {
413+
RecoverableError() << "Abbreviation doesn't apply to record: "
414+
<< Record << "\n";
415+
UsesDefaultAbbrev = true;
416+
if (!Flags.getTryToRecover())
417+
return false;
418+
WriteRecord(Writer, Record, UsesDefaultAbbrev);
419+
return true;
420+
}
320421
if (Flags.getWriteBadAbbrevIndex()) {
422+
// The abbreviation is not understood by the bitcode writer,
423+
// and the flag value implies that we should still write it
424+
// out so that unit tests for this error condition can be
425+
// applied.
321426
Error() << "Uses illegal abbreviation index: " << Record << "\n";
322427
// Generate bad abbreviation index so that the bitcode reader
323428
// can be tested, and then quit.
@@ -329,9 +434,11 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer,
329434
}
330435
RecoverableError() << "Uses illegal abbreviation index: "
331436
<< Record << "\n";
437+
UsesDefaultAbbrev = true;
332438
if (!Flags.getTryToRecover())
333439
return false;
334-
UsesDefaultAbbrev = true;
440+
WriteRecord(Writer, Record, UsesDefaultAbbrev);
441+
return true;
335442
}
336443
if (getCurWriteBlockID() == naclbitc::BLOCKINFO_BLOCK_ID
337444
&& Record.Code == naclbitc::BLOCKINFO_CODE_SETBID) {
@@ -347,10 +454,8 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer,
347454
SetBID = Record.Values[0];
348455
return true;
349456
}
350-
if (UsesDefaultAbbrev)
351-
Writer.EmitRecord(Record.Code, Record.Values);
352-
else
353-
Writer.EmitRecord(Record.Code, Record.Values, Record.Abbrev);
457+
WriteRecord(Writer, Record, UsesDefaultAbbrev);
458+
break;
354459
}
355460
return true;
356461
}
@@ -381,7 +486,7 @@ NaClBitCodeAbbrev *WriteState::buildAbbrev(
381486
if (Index >= NumValues) {
382487
RecoverableError()
383488
<< "Malformed abbreviation found. Expects " << NumAbbreviations
384-
<< " operands but ound " << Count << ": " << Record << "\n";
489+
<< " operands but found " << Count << ": " << Record << "\n";
385490
return deleteAbbrev(Abbrev);
386491
}
387492
switch (Record.Values[Index++]) {
@@ -438,8 +543,8 @@ NaClBitCodeAbbrev *WriteState::buildAbbrev(
438543
break;
439544
}
440545
default:
441-
RecoverableError() << "Error: Bad literal flag " << Record.Values[Index]
442-
<< ": " << Record << "\n";
546+
RecoverableError() << "Error: Bad abbreviation operand encoding "
547+
<< Record.Values[Index-1] << ": " << Record << "\n";
443548
return deleteAbbrev(Abbrev);
444549
}
445550
}

0 commit comments

Comments
 (0)