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. |