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..3832fd6867c7a0780697210dfc1cea16c497e9c8 |
| --- /dev/null |
| +++ b/unittests/Bitcode/NaClMungeWriteErrorTests.cpp |
| @@ -0,0 +1,327 @@ |
| +//===- 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 (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 that we can't write more local abbreviations than specified in |
| +// the corresponding enclosing block. |
| +TEST(NaClMungeWriteErrorTests, CantDumpTooManyLocalAbbreviations) { |
|
jvoung (off chromium)
2015/05/13 00:58:17
Maybe "define" instead of "dump"? I think of the o
Karl
2015/05/13 21:39:25
Changing CantWriteTooManyLocallAbbreviations.
|
| + 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("CantDumpTooManyLocalAbbreviations")); |
| + EXPECT_EQ( |
| + "Error (Block 12): Exceeds abbreviation index limit of 3: 2:" |
| + " [65533, 1, 1, 10]\n" |
| + "Error (Block 12): 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 more enter blocks then exit blocks. |
| +TEST(NaClMungeWriteErrorTests, TooManyEnterBlocks) { |
| + 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")); |
| + 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, TooFewExitBlocks) { |
|
jvoung (off chromium)
2015/05/13 00:58:17
re: TooFewExitBlocks, in this case there are too f
Karl
2015/05/13 21:39:24
Fixing to TooMayExitBlocks.
|
| + 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("TooFewExitBlocks")); |
|
jvoung (off chromium)
2015/05/13 00:58:17
"TooFewExitBlocks" -> ?
Karl
2015/05/13 21:39:24
Done.
|
| + 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 error recovery works when parsing bitcode with a bad |
| +// abbreviation index. |
|
jvoung (off chromium)
2015/05/13 00:58:17
So to be clear -- the error recovery is in the wri
Karl
2015/05/13 21:39:24
Yes.
Rewriting error recovery comments to be clea
|
| +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 dumping bitcode with a bad |
| +// abbreviation index. |
| +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 there is too many locally |
| +// defined abbreviations for the corresponding number of bits defined |
| +// in the corresponding enter block. |
| +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 there are more enter blocks than |
| +// exit blocks. |
| +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 there are fewer enter blocks |
| +// than exit blocks. |
|
jvoung (off chromium)
2015/05/13 00:58:17
Similar comment to TooFewExitBlocks
|
| +TEST(NaClMungeWriteErrorTests, RecoverTooFewExitBlocks) { |
| + 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("RecoverTooFewExitBlocks")); |
| + 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. |
| +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. |