Chromium Code Reviews| Index: unittests/Bitcode/NaClMungeWriteErrorTests.cpp |
| diff --git a/unittests/Bitcode/NaClMungeWriteErrorTests.cpp b/unittests/Bitcode/NaClMungeWriteErrorTests.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..6745204e7ad28fe90b4be7ea72a216c157db2ff2 |
| --- /dev/null |
| +++ b/unittests/Bitcode/NaClMungeWriteErrorTests.cpp |
| @@ -0,0 +1,411 @@ |
| +//===- llvm/unittest/Bitcode/NaClMungeWriteErrorTests.cpp -----------------===// |
| +// Tests parser for PNaCl bitcode instructions. |
| +// |
| +// The LLVM Compiler Infrastructure |
| +// |
| +// This file is distributed under the University of Illinois Open Source |
| +// License. See LICENSE.TXT for details. |
| +// |
| +//===----------------------------------------------------------------------===// |
| + |
| +// Tests write errors for munged bitcode. |
| + |
| +#include "llvm/ADT/STLExtras.h" |
| +#include "llvm/Bitcode/NaCl/NaClBitcodeMunge.h" |
| +#include "llvm/Bitcode/NaCl/NaClBitcodeParser.h" |
| +#include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h" |
| + |
| +#include "gtest/gtest.h" |
| + |
| +using namespace llvm; |
| + |
| +namespace { |
| + |
| +// Test list of bitcode records. |
| +static const uint64_t Terminator = 0x5768798008978675LL; |
| + const uint64_t BitcodeRecords[] = { |
| + 1, naclbitc::BLK_CODE_ENTER, naclbitc::MODULE_BLOCK_ID, 2, Terminator, |
| + 1, naclbitc::BLK_CODE_ENTER, naclbitc::TYPE_BLOCK_ID_NEW, 3, Terminator, |
| + 3, naclbitc::TYPE_CODE_NUMENTRY, 2, Terminator, |
| + 3, naclbitc::TYPE_CODE_VOID, Terminator, |
| + 3, naclbitc::TYPE_CODE_FUNCTION, 0, 0, Terminator, |
| + 0, naclbitc::BLK_CODE_EXIT, Terminator, |
| + 3, naclbitc::MODULE_CODE_FUNCTION, 1, 0, 0, 0, Terminator, |
| + 1, naclbitc::BLK_CODE_ENTER, naclbitc::FUNCTION_BLOCK_ID, 2, Terminator, |
| + 3, naclbitc::FUNC_CODE_DECLAREBLOCKS, 1, Terminator, |
| + 3, naclbitc::FUNC_CODE_INST_RET, Terminator, |
| + 0, naclbitc::BLK_CODE_EXIT, Terminator, |
| + 0, naclbitc::BLK_CODE_EXIT, Terminator |
| + }; |
| + |
| +// Expected output when bitcode records are dumped. |
| +const char* ExpectedDump = |
| + " 0:0|<65532, 80, 69, 88, 69, 1, 0,|Magic Number: 'PEXE' (80, 69, " |
| + "88, 69)\n" |
| + " | 8, 0, 17, 0, 4, 0, 2, 0, 0, |PNaCl Version: 2\n" |
| + " | 0> |\n" |
| + " 16:0|1: <65535, 8, 2> |module { // BlockID = 8\n" |
| + " 24:0| 1: <65535, 17, 3> | types { // BlockID = 17\n" |
| + " 32:0| 3: <1, 2> | count 2;\n" |
| + " 34:5| 3: <2> | @t0 = void;\n" |
| + " 36:4| 3: <21, 0, 0> | @t1 = void ();\n" |
| + " 39:7| 0: <65534> | }\n" |
| + " 44:0| 3: <8, 1, 0, 0, 0> | define external void @f0();\n" |
| + " 48:6| 1: <65535, 12, 2> | function void @f0() { \n" |
| + " | | // BlockID " |
| + "= 12\n" |
| + " 56:0| 3: <1, 1> | blocks 1;\n" |
| + " | | %b0:\n" |
| + " 58:4| 3: <10> | ret void;\n" |
| + " 60:2| 0: <65534> | }\n" |
| + " 64:0|0: <65534> |}\n" |
| + ; |
| + |
| +// Edit to change void type with an illegal abbreviation index. |
| +const uint64_t VoidTypeIndex = 3; // Index for "@t0 = void". |
| +const uint64_t AbbrevIndex4VoidTypeEdit[] = { |
| + VoidTypeIndex, NaClMungedBitcode::Replace, |
| + 4, naclbitc::TYPE_CODE_VOID, Terminator, |
| +}; |
| + |
| +// Edit to add local abbreviation for "ret void", and then use on that |
| +// instruction. |
| +const uint64_t RetVoidIndex = 9; // return void; |
| +const uint64_t UseLocalRetVoidAbbrevEdits[] = { |
| + RetVoidIndex, NaClMungedBitcode::AddBefore, |
| + 2, naclbitc::BLK_CODE_DEFINE_ABBREV, 1, 1, |
| + naclbitc::FUNC_CODE_INST_RET, Terminator, |
| + RetVoidIndex, NaClMungedBitcode::Replace, |
| + 4, naclbitc::FUNC_CODE_INST_RET, Terminator |
| +}; |
| + |
| +#define ARRAY_ARGS(Records) Records, array_lengthof(Records) |
| + |
| +#define ARRAY_ARGS_TERM(Records) ARRAY_ARGS(Records), Terminator |
| + |
| +std::string stringify(NaClBitcodeMunger &Munger) { |
| + std::string Buffer; |
| + raw_string_ostream StrBuf(Buffer); |
| + Munger.getMungedBitcode().print(StrBuf); |
| + return StrBuf.str(); |
| +} |
| + |
| +// Show that we can dump the bitcode records |
| +TEST(NaClMungeWriteErrorTests, DumpBitcodeRecords) { |
| + NaClObjDumpMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| + EXPECT_TRUE(Munger.runTest("DumpBitcodeRecords")); |
| + EXPECT_EQ(ExpectedDump, Munger.getTestResults()); |
| +} |
| + |
| +// Show that by default, one can't write a bad abbreviation index. |
| +TEST(NaClMungeWriteErrorTests, CantWriteBadAbbrevIndex) { |
| + NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| + EXPECT_FALSE(Munger.runTest("CantWriteBadAbbrevIndex", |
| + ARRAY_ARGS(AbbrevIndex4VoidTypeEdit))); |
| + EXPECT_EQ( |
| + "Error (Block 17): Uses illegal abbreviation index: 4: [2]\n" |
| + "Error: Unable to generate bitcode file due to write errors\n", |
| + Munger.getTestResults()); |
| +} |
| + |
| +// Show that we can't write more local abbreviations than specified in |
| +// the corresponding enclosing block. |
| +TEST(NaClMungeWriteErrorTests, CantWriteTooManyLocalAbbreviations) { |
| + NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| + Munger.munge(ARRAY_ARGS(UseLocalRetVoidAbbrevEdits)); |
| + EXPECT_EQ( |
| + " 1: [65535, 8, 2]\n" |
| + " 1: [65535, 17, 3]\n" |
| + " 3: [1, 2]\n" |
| + " 3: [2]\n" |
| + " 3: [21, 0, 0]\n" |
| + " 0: [65534]\n" |
| + " 3: [8, 1, 0, 0, 0]\n" |
| + " 1: [65535, 12, 2]\n" |
| + " 3: [1, 1]\n" |
| + " 2: [65533, 1, 1, 10]\n" |
| + " 4: [10]\n" |
| + " 0: [65534]\n" |
| + " 0: [65534]\n", |
| + stringify(Munger)); |
| + |
| + EXPECT_FALSE(Munger.runTest("CantWriteTooManyLocalAbbreviations")); |
| + EXPECT_EQ( |
| + "Error (Block 12): Exceeds abbreviation index limit of 3: 2: [65533," |
| + " 1, 1, 10]\n" |
| + "Error: Unable to generate bitcode file due to write errors\n", |
| + Munger.getTestResults()); |
| +} |
| + |
| +// Show what happens when there are more enter blocks then exit blocks. |
| +TEST(NaClMungeWriteErrorTests, CantWriteTooManyEnterBlocks) { |
| + NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| + // Remove all but first two records (i.e. two enter blocks). |
| + NaClMungedBitcode &MungedBitcode = Munger.getMungedBitcode(); |
| + for (size_t i = 2; i < MungedBitcode.getBaseRecords().size(); ++i) { |
| + MungedBitcode.remove(i); |
| + } |
| + |
| + EXPECT_FALSE(Munger.runTest("TooManyEnterBlocks")); |
|
jvoung (off chromium)
2015/05/13 22:24:06
CantWriteTooManyEnterBlocks -- I wasn't too sure t
Karl
2015/05/14 17:08:12
I agree that these names are no longer useful. Cha
|
| + EXPECT_EQ( |
| + "Error (Block 17): Missing close block.\n" |
| + "Error (Block 8): Missing close block.\n" |
| + "Error: Unable to generate bitcode file due to write errors\n", |
| + Munger.getTestResults()); |
| +} |
| + |
| +// Show what happens when there are fewer enter blocks than exit |
| +// blocks. |
| +TEST(NaClMungeWriteErrorTests, CantWriteTooManyExitBlocks) { |
| + NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| + // Add two exit blocks. |
| + NaClMungedBitcode &MungedBitcode = Munger.getMungedBitcode(); |
| + NaClRecordVector Values; |
| + NaClBitcodeAbbrevRecord Record(0, naclbitc::BLK_CODE_EXIT, Values); |
| + for (size_t i = 0; i < 2; ++i) |
| + MungedBitcode.addAfter(MungedBitcode.getBaseRecords().size() - 1, Record); |
| + |
| + EXPECT_FALSE(Munger.runTest("CantWriteTooManyExitBlocks")); |
| + EXPECT_EQ( |
| + "Error (Block unknown): Extraneous exit block: 0: [65534]\n" |
| + "Error: Unable to generate bitcode file due to write errors\n", |
| + Munger.getTestResults()); |
| +} |
| + |
| +// Show that an error occurs when writing a bitcode record that isn't |
| +// in any block. |
| +TEST(NaClMungeWriteErrorTests, CantWriteRecordOutsideBlock) { |
| + NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| + NaClMungedBitcode &MungedBitcode = Munger.getMungedBitcode(); |
| + NaClRecordVector Values; |
| + Values.push_back(4); |
| + NaClBitcodeAbbrevRecord Record(naclbitc::UNABBREV_RECORD, |
| + naclbitc::MODULE_CODE_VERSION, |
| + Values); |
| + |
| + MungedBitcode.addAfter(MungedBitcode.getBaseRecords().size() - 1, Record); |
| + EXPECT_FALSE(Munger.runTest("CantWriteRecordOutsideBlock")); |
| + EXPECT_EQ( |
| + "Error (Block unknown): Record outside block: 3: [1, 4]\n" |
| + "Error: Unable to generate bitcode file due to write errors\n", |
| + Munger.getTestResults()); |
| +} |
| + |
| +// Show that no error occurs if we write out the maximum allowable |
| +// block abbreviation index bit limit. |
| +TEST(NaClMungerWriteErrorTests, CantWriteBlockWithMaxLimit) { |
|
Karl
2015/05/13 21:39:25
Added this test.
jvoung (off chromium)
2015/05/13 22:24:06
Seems like Cant should be Can, since this doesn't
Karl
2015/05/14 17:08:12
Good point. Fixing name.
|
| + // Replace initial block enter with maximum bit size. |
| + const uint64_t Edit[] = { |
| + 0, NaClMungedBitcode::Replace, |
| + 1, naclbitc::BLK_CODE_ENTER, naclbitc::MODULE_BLOCK_ID, |
| + naclbitc::MaxAbbrevWidth, Terminator |
| + }; |
| + NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| + EXPECT_TRUE(Munger.runTest("CantWriteBlockWithMaxLimit", ARRAY_ARGS(Edit))); |
| + EXPECT_EQ( |
| + " 1: [65535, 8, 32]\n" |
| + " 1: [65535, 17, 3]\n" |
| + " 3: [1, 2]\n" |
| + " 3: [2]\n" |
| + " 3: [21, 0, 0]\n" |
| + " 0: [65534]\n" |
| + " 3: [8, 1, 0, 0, 0]\n" |
| + " 1: [65535, 12, 2]\n" |
| + " 3: [1, 1]\n" |
| + " 3: [10]\n" |
| + " 0: [65534]\n" |
| + " 0: [65534]\n", |
| + Munger.getTestResults()); |
| +} |
| + |
| +// Show that an error occurs if the block abbreviation index bit limit is |
| +// greater than the maximum allowable. |
| +TEST(NaClMungerWriteErrorTests, CantWriteBlockWithBadBitLimit) { |
|
Karl
2015/05/13 21:39:25
Added this test.
|
| + // Replace initial block enter with value out of range. |
| + const uint64_t Edit[] = { |
| + 0, NaClMungedBitcode::Replace, |
| + 1, naclbitc::BLK_CODE_ENTER, naclbitc::MODULE_BLOCK_ID, |
| + naclbitc::MaxAbbrevWidth + 1, Terminator |
| + }; |
| + NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| + EXPECT_FALSE(Munger.runTest("CantWriteBlockWithBadBitLimit", |
| + ARRAY_ARGS(Edit))); |
| + EXPECT_EQ( |
| + "Error (Block unknown): Block index bit limit 33 invalid. Must be in" |
| + " [2..32]: 1: [65535, 8, 33]\n" |
| + "Error: Unable to generate bitcode file due to write errors\n", |
| + Munger.getTestResults()); |
| +} |
| + |
| +// Show that we can't write an enter block with a very large block id. |
| +TEST(NaClMungerWriteErrorTests, CantWriteBlockWithLargeBlockID) { |
|
Karl
2015/05/13 21:39:25
Added this test.
|
| + // Replace initial block enter with value out of range. |
| + const uint64_t Edit[] = { |
| + 0, NaClMungedBitcode::Replace, |
| + 1, naclbitc::BLK_CODE_ENTER, (uint64_t)1 << 33, 2, Terminator |
| + }; |
| + NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| + EXPECT_FALSE(Munger.runTest("CantWriteBlockWithLargeBlockID", |
| + ARRAY_ARGS(Edit))); |
| + EXPECT_EQ( |
| + "Error (Block unknown): Block id must be less than << 4294967295: 1:" |
|
jvoung (off chromium)
2015/05/13 22:24:06
"less than << 4294967295" -- why the "<<" ?
Karl
2015/05/14 17:08:11
Done.
|
| + " [65535, 8589934592, 2]\n" |
| + "Error: Unable to generate bitcode file due to write errors\n", |
| + Munger.getTestResults()); |
| +} |
| + |
| +// Show that parsing successfully recovers (i.e. not crash) if the |
|
jvoung (off chromium)
2015/05/13 22:24:06
"parsing successfully recovers" ? I thought it was
Karl
2015/05/14 17:08:11
Good point. Rewrote to better fit test.
|
| +// bitcode has a bad abbreviation index. Show this by forcing |
| +// the bad abbreviation index into the bitcode. |
| +TEST(MyNaClMungerWriteErrorTests, DieOnWriteBadAbbreviationIndex) { |
|
Karl
2015/05/13 21:39:25
Added this test.
jvoung (off chromium)
2015/05/13 22:24:06
My... -> NaClMungerWriteErrorTests
|
| + NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| + Munger.setWriteBadAbbrevIndex(true); |
| + Munger.setRunAsDeathTest(true); |
| + EXPECT_DEATH( |
| + Munger.runTest("DieOnWriteBadAbbrevIndex", |
| + ARRAY_ARGS(AbbrevIndex4VoidTypeEdit)), |
| + ".*" |
| + // Report problem while writing. |
| + "Error \\(Block 17\\)\\: Uses illegal abbreviation index\\: 4\\: \\[2\\]" |
| + ".*" |
| + // Corresponding error while parsing. |
| + "Fatal\\(35\\:0)\\: Invalid abbreviation \\# 4 defined for record" |
| + ".*" |
| + // Output of report_fatal_error. |
| + "LLVM ERROR\\: Unable to continue" |
| + ".*"); |
| +} |
| + |
| +// Show that error recovery works when writing an illegal abbreviation |
| +// index. Show success by parsing fixed bitcode. |
| +TEST(NaClMungeWriteErrorTests, RecoverWhenParsingBadAbbrevIndex) { |
| + NaClParseBitcodeMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| + Munger.setTryToRecoverOnWrite(true); |
| + EXPECT_TRUE( |
| + Munger.runTest("RecoverWhenParsingBadAbbrevIndex", |
| + ARRAY_ARGS(AbbrevIndex4VoidTypeEdit), true)); |
| + EXPECT_EQ( |
| + "Error (Block 17): Uses illegal abbreviation index: 4: [2]\n" |
| + "Successful parse!\n", |
| + Munger.getTestResults()); |
| +} |
| + |
| +// Show that error recovery works when writing an illegal abbreviation |
| +// index. Show success by Dumping fixed bitcode. |
| +TEST(NaClMungeWriteErrorTests, RecoverWhenParsingBadAbbreviationIndex) { |
| + NaClObjDumpMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| + Munger.setTryToRecoverOnWrite(true); |
| + EXPECT_TRUE(Munger.runTest("RecoverWhenParsingBadAbbreviationIndex", |
| + ARRAY_ARGS(AbbrevIndex4VoidTypeEdit))); |
| + std::string Results( |
| + "Error (Block 17): Uses illegal abbreviation index: 4: [2]\n"); |
| + Results.append(ExpectedDump); |
| + EXPECT_EQ(Results, Munger.getTestResults()); |
| +} |
| + |
| +// Show that error recovery works when writing too many locally |
| +// defined abbreviations for the corresponding number of bits defined |
| +// in the corresponding enter block. Show success by dumping the fixed |
| +// bitcode. |
| +TEST(NaClMungeWriteErrorTests, RecoverTooManyLocalAbbreviations) { |
| + NaClObjDumpMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| + Munger.setTryToRecoverOnWrite(true); |
| + Munger.munge(ARRAY_ARGS(UseLocalRetVoidAbbrevEdits)); |
| + |
| + EXPECT_TRUE(Munger.runTest("RecoverTooManyLocalAbbreviations")); |
| + std::string Results( |
| + "Error (Block 12): Exceeds abbreviation index limit of 3: 2:" |
| + " [65533, 1, 1, 10]\n" |
| + "Error (Block 12): Uses illegal abbreviation index: 4: [10]\n"); |
| + Results.append(ExpectedDump); |
| + EXPECT_EQ( |
| + Results, |
| + Munger.getTestResults()); |
| +} |
| + |
| +// Show that error recovery works when writing and there are more |
| +// enter blocks than exit blocks. Show success by dumping fixed |
| +// bitcode. |
| +TEST(NaClMungeWriteErrorTests, RecoverTooManyEnterBlocks) { |
| + NaClObjDumpMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| + // Remove all but first two records (i.e. two enter blocks). |
| + NaClMungedBitcode &MungedBitcode = Munger.getMungedBitcode(); |
| + for (size_t i = 2; i < MungedBitcode.getBaseRecords().size(); ++i) { |
| + MungedBitcode.remove(i); |
| + } |
| + |
| + Munger.setTryToRecoverOnWrite(true); |
| + EXPECT_TRUE(Munger.runTest("RecoverTooManyEnterBlocks")); |
| + EXPECT_EQ( |
| + "Error (Block 17): Missing close block.\n" |
| + "Error (Block 8): Missing close block.\n" |
| + " 0:0|<65532, 80, 69, 88, 69, 1, 0,|Magic Number: 'PEXE' (80, 69," |
| + " 88, 69)\n" |
| + " | 8, 0, 17, 0, 4, 0, 2, 0, 0, |PNaCl Version: 2\n" |
| + " | 0> |\n" |
| + " 16:0|1: <65535, 8, 2> |module { // BlockID = 8\n" |
| + " 24:0| 1: <65535, 17, 3> | types { // BlockID = 17\n" |
| + " 32:0| 0: <65534> | }\n" |
| + " 36:0|0: <65534> |}\n", |
| + Munger.getTestResults()); |
| +} |
| + |
| +// Show that error recovery works when writing and there are fewer |
| +// enter blocks than exit blocks. Show success by dumping the fixed |
| +// bitcode. |
| +TEST(NaClMungeWriteErrorTests, RecoverTooManyExitBlocks) { |
| + NaClObjDumpMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| + // Add two exit blocks. |
| + NaClMungedBitcode &MungedBitcode = Munger.getMungedBitcode(); |
| + NaClRecordVector Values; |
| + NaClBitcodeAbbrevRecord Record(0, naclbitc::BLK_CODE_EXIT, Values); |
| + for (size_t i = 0; i < 2; ++i) |
| + MungedBitcode.addAfter(MungedBitcode.getBaseRecords().size() - 1, Record); |
| + |
| + Munger.setTryToRecoverOnWrite(true); |
| + EXPECT_TRUE(Munger.runTest("RecoverTooManyExitBlocks")); |
| + std::string Results( |
| + "Error (Block unknown): Extraneous exit block: 0: [65534]\n" |
| + "Error (Block unknown): Extraneous exit block: 0: [65534]\n"); |
| + Results.append(ExpectedDump); |
| + EXPECT_EQ( |
| + Results, |
| + Munger.getTestResults()); |
| +} |
| + |
| +// Show that error recovery works when writing a bitcode record that |
| +// isn't in any block. Show success by showing fixed bitcode records. |
| +TEST(NaClMungeWriteErrorTests, RecoverWriteRecordOutsideBlock) { |
| + NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| + NaClMungedBitcode &MungedBitcode = Munger.getMungedBitcode(); |
| + NaClRecordVector Values; |
| + Values.push_back(4); |
| + NaClBitcodeAbbrevRecord Record(naclbitc::UNABBREV_RECORD, |
| + naclbitc::MODULE_CODE_VERSION, |
| + Values); |
| + MungedBitcode.addAfter(MungedBitcode.getBaseRecords().size() - 1, Record); |
| + |
| + Munger.setTryToRecoverOnWrite(true); |
| + EXPECT_TRUE(Munger.runTest("RecoverWriteRecordOutsideBlock")); |
| + EXPECT_EQ( |
| + "Error (Block unknown): Record outside block: 3: [1, 4]\n" |
| + "Error (Block unknown): Missing close block.\n" |
| + " 1: [65535, 8, 2]\n" |
| + " 1: [65535, 17, 3]\n" |
| + " 3: [1, 2]\n" |
| + " 3: [2]\n" |
| + " 3: [21, 0, 0]\n" |
| + " 0: [65534]\n" |
| + " 3: [8, 1, 0, 0, 0]\n" |
| + " 1: [65535, 12, 2]\n" |
| + " 3: [1, 1]\n" |
| + " 3: [10]\n" |
| + " 0: [65534]\n" |
| + " 0: [65534]\n" |
| + " 1: [65535, 4294967295, 3]\n" |
| + " 3: [1, 4]\n" |
| + " 0: [65534]\n", |
| + Munger.getTestResults()); |
| +} |
| + |
| +} // end of anonymous namespace. |