OLD | NEW |
(Empty) | |
| 1 //===- llvm/unittest/Bitcode/NaClMungeWriteErrorTests.cpp -----------------===// |
| 2 // Tests parser for PNaCl bitcode instructions. |
| 3 // |
| 4 // The LLVM Compiler Infrastructure |
| 5 // |
| 6 // This file is distributed under the University of Illinois Open Source |
| 7 // License. See LICENSE.TXT for details. |
| 8 // |
| 9 //===----------------------------------------------------------------------===// |
| 10 |
| 11 // Tests write errors for munged bitcode. |
| 12 |
| 13 #include "llvm/ADT/STLExtras.h" |
| 14 #include "llvm/Bitcode/NaCl/NaClBitcodeMunge.h" |
| 15 #include "llvm/Bitcode/NaCl/NaClBitcodeParser.h" |
| 16 #include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h" |
| 17 |
| 18 #include "gtest/gtest.h" |
| 19 |
| 20 using namespace llvm; |
| 21 |
| 22 namespace { |
| 23 |
| 24 // Test list of bitcode records. |
| 25 static const uint64_t Terminator = 0x5768798008978675LL; |
| 26 const uint64_t BitcodeRecords[] = { |
| 27 1, naclbitc::BLK_CODE_ENTER, naclbitc::MODULE_BLOCK_ID, 2, Terminator, |
| 28 1, naclbitc::BLK_CODE_ENTER, naclbitc::TYPE_BLOCK_ID_NEW, 3, Terminator, |
| 29 3, naclbitc::TYPE_CODE_NUMENTRY, 2, Terminator, |
| 30 3, naclbitc::TYPE_CODE_VOID, Terminator, |
| 31 3, naclbitc::TYPE_CODE_FUNCTION, 0, 0, Terminator, |
| 32 0, naclbitc::BLK_CODE_EXIT, Terminator, |
| 33 3, naclbitc::MODULE_CODE_FUNCTION, 1, 0, 0, 0, Terminator, |
| 34 1, naclbitc::BLK_CODE_ENTER, naclbitc::FUNCTION_BLOCK_ID, 2, Terminator, |
| 35 3, naclbitc::FUNC_CODE_DECLAREBLOCKS, 1, Terminator, |
| 36 3, naclbitc::FUNC_CODE_INST_RET, Terminator, |
| 37 0, naclbitc::BLK_CODE_EXIT, Terminator, |
| 38 0, naclbitc::BLK_CODE_EXIT, Terminator |
| 39 }; |
| 40 |
| 41 // Expected output when bitcode records are dumped. |
| 42 const char* ExpectedDump = |
| 43 " 0:0|<65532, 80, 69, 88, 69, 1, 0,|Magic Number: 'PEXE' (80, 69, " |
| 44 "88, 69)\n" |
| 45 " | 8, 0, 17, 0, 4, 0, 2, 0, 0, |PNaCl Version: 2\n" |
| 46 " | 0> |\n" |
| 47 " 16:0|1: <65535, 8, 2> |module { // BlockID = 8\n" |
| 48 " 24:0| 1: <65535, 17, 3> | types { // BlockID = 17\n" |
| 49 " 32:0| 3: <1, 2> | count 2;\n" |
| 50 " 34:5| 3: <2> | @t0 = void;\n" |
| 51 " 36:4| 3: <21, 0, 0> | @t1 = void ();\n" |
| 52 " 39:7| 0: <65534> | }\n" |
| 53 " 44:0| 3: <8, 1, 0, 0, 0> | define external void @f0();\n" |
| 54 " 48:6| 1: <65535, 12, 2> | function void @f0() { \n" |
| 55 " | | // BlockID " |
| 56 "= 12\n" |
| 57 " 56:0| 3: <1, 1> | blocks 1;\n" |
| 58 " | | %b0:\n" |
| 59 " 58:4| 3: <10> | ret void;\n" |
| 60 " 60:2| 0: <65534> | }\n" |
| 61 " 64:0|0: <65534> |}\n" |
| 62 ; |
| 63 |
| 64 // Edit to change void type with an illegal abbreviation index. |
| 65 const uint64_t VoidTypeIndex = 3; // Index for "@t0 = void". |
| 66 const uint64_t AbbrevIndex4VoidTypeEdit[] = { |
| 67 VoidTypeIndex, NaClMungedBitcode::Replace, |
| 68 4, naclbitc::TYPE_CODE_VOID, Terminator, |
| 69 }; |
| 70 |
| 71 // Edit to add local abbreviation for "ret void", and then use on that |
| 72 // instruction. |
| 73 const uint64_t RetVoidIndex = 9; // return void; |
| 74 const uint64_t UseLocalRetVoidAbbrevEdits[] = { |
| 75 RetVoidIndex, NaClMungedBitcode::AddBefore, |
| 76 2, naclbitc::BLK_CODE_DEFINE_ABBREV, 1, 1, |
| 77 naclbitc::FUNC_CODE_INST_RET, Terminator, |
| 78 RetVoidIndex, NaClMungedBitcode::Replace, |
| 79 4, naclbitc::FUNC_CODE_INST_RET, Terminator |
| 80 }; |
| 81 |
| 82 #define ARRAY_ARGS(Records) Records, array_lengthof(Records) |
| 83 |
| 84 #define ARRAY_ARGS_TERM(Records) ARRAY_ARGS(Records), Terminator |
| 85 |
| 86 std::string stringify(NaClBitcodeMunger &Munger) { |
| 87 std::string Buffer; |
| 88 raw_string_ostream StrBuf(Buffer); |
| 89 Munger.getMungedBitcode().print(StrBuf); |
| 90 return StrBuf.str(); |
| 91 } |
| 92 |
| 93 // Show that we can dump the bitcode records |
| 94 TEST(NaClMungeWriteErrorTests, DumpBitcodeRecords) { |
| 95 NaClObjDumpMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| 96 EXPECT_TRUE(Munger.runTest()); |
| 97 EXPECT_EQ(ExpectedDump, Munger.getTestResults()); |
| 98 } |
| 99 |
| 100 // Show that by default, one can't write a bad abbreviation index. |
| 101 TEST(NaClMungeWriteErrorTests, CantWriteBadAbbrevIndex) { |
| 102 NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| 103 EXPECT_FALSE(Munger.runTest(ARRAY_ARGS(AbbrevIndex4VoidTypeEdit))); |
| 104 EXPECT_EQ( |
| 105 "Error (Block 17): Uses illegal abbreviation index: 4: [2]\n" |
| 106 "Error: Unable to generate bitcode file due to write errors\n", |
| 107 Munger.getTestResults()); |
| 108 } |
| 109 |
| 110 // Show that we can't write more local abbreviations than specified in |
| 111 // the corresponding enclosing block. |
| 112 TEST(NaClMungeWriteErrorTests, CantWriteTooManyLocalAbbreviations) { |
| 113 NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| 114 Munger.munge(ARRAY_ARGS(UseLocalRetVoidAbbrevEdits)); |
| 115 EXPECT_EQ( |
| 116 " 1: [65535, 8, 2]\n" |
| 117 " 1: [65535, 17, 3]\n" |
| 118 " 3: [1, 2]\n" |
| 119 " 3: [2]\n" |
| 120 " 3: [21, 0, 0]\n" |
| 121 " 0: [65534]\n" |
| 122 " 3: [8, 1, 0, 0, 0]\n" |
| 123 " 1: [65535, 12, 2]\n" |
| 124 " 3: [1, 1]\n" |
| 125 " 2: [65533, 1, 1, 10]\n" |
| 126 " 4: [10]\n" |
| 127 " 0: [65534]\n" |
| 128 " 0: [65534]\n", |
| 129 stringify(Munger)); |
| 130 |
| 131 EXPECT_FALSE(Munger.runTest()); |
| 132 EXPECT_EQ( |
| 133 "Error (Block 12): Exceeds abbreviation index limit of 3: 2: [65533," |
| 134 " 1, 1, 10]\n" |
| 135 "Error: Unable to generate bitcode file due to write errors\n", |
| 136 Munger.getTestResults()); |
| 137 } |
| 138 |
| 139 // Show what happens when there are more enter blocks then exit blocks. |
| 140 TEST(NaClMungeWriteErrorTests, CantWriteTooManyEnterBlocks) { |
| 141 NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| 142 // Remove all but first two records (i.e. two enter blocks). |
| 143 NaClMungedBitcode &MungedBitcode = Munger.getMungedBitcode(); |
| 144 for (size_t i = 2; i < MungedBitcode.getBaseRecords().size(); ++i) { |
| 145 MungedBitcode.remove(i); |
| 146 } |
| 147 |
| 148 EXPECT_FALSE(Munger.runTest()); |
| 149 EXPECT_EQ( |
| 150 "Error (Block 17): Missing close block.\n" |
| 151 "Error (Block 8): Missing close block.\n" |
| 152 "Error: Unable to generate bitcode file due to write errors\n", |
| 153 Munger.getTestResults()); |
| 154 } |
| 155 |
| 156 // Show what happens when there are fewer enter blocks than exit |
| 157 // blocks. |
| 158 TEST(NaClMungeWriteErrorTests, CantWriteTooManyExitBlocks) { |
| 159 NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| 160 // Add two exit blocks. |
| 161 NaClMungedBitcode &MungedBitcode = Munger.getMungedBitcode(); |
| 162 NaClRecordVector Values; |
| 163 NaClBitcodeAbbrevRecord Record(0, naclbitc::BLK_CODE_EXIT, Values); |
| 164 for (size_t i = 0; i < 2; ++i) |
| 165 MungedBitcode.addAfter(MungedBitcode.getBaseRecords().size() - 1, Record); |
| 166 |
| 167 EXPECT_FALSE(Munger.runTest()); |
| 168 EXPECT_EQ( |
| 169 "Error (Block unknown): Extraneous exit block: 0: [65534]\n" |
| 170 "Error: Unable to generate bitcode file due to write errors\n", |
| 171 Munger.getTestResults()); |
| 172 } |
| 173 |
| 174 // Show that an error occurs when writing a bitcode record that isn't |
| 175 // in any block. |
| 176 TEST(NaClMungeWriteErrorTests, CantWriteRecordOutsideBlock) { |
| 177 NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| 178 NaClMungedBitcode &MungedBitcode = Munger.getMungedBitcode(); |
| 179 NaClRecordVector Values; |
| 180 Values.push_back(4); |
| 181 NaClBitcodeAbbrevRecord Record(naclbitc::UNABBREV_RECORD, |
| 182 naclbitc::MODULE_CODE_VERSION, |
| 183 Values); |
| 184 |
| 185 MungedBitcode.addAfter(MungedBitcode.getBaseRecords().size() - 1, Record); |
| 186 EXPECT_FALSE(Munger.runTest()); |
| 187 EXPECT_EQ( |
| 188 "Error (Block unknown): Record outside block: 3: [1, 4]\n" |
| 189 "Error: Unable to generate bitcode file due to write errors\n", |
| 190 Munger.getTestResults()); |
| 191 } |
| 192 |
| 193 // Show that no error occurs if we write out the maximum allowable |
| 194 // block abbreviation index bit limit. |
| 195 TEST(NaClMungerWriteErrorTests, CanWriteBlockWithMaxLimit) { |
| 196 // Replace initial block enter with maximum bit size. |
| 197 const uint64_t Edit[] = { |
| 198 0, NaClMungedBitcode::Replace, |
| 199 1, naclbitc::BLK_CODE_ENTER, naclbitc::MODULE_BLOCK_ID, |
| 200 naclbitc::MaxAbbrevWidth, Terminator |
| 201 }; |
| 202 NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| 203 EXPECT_TRUE(Munger.runTest(ARRAY_ARGS(Edit))); |
| 204 EXPECT_EQ( |
| 205 " 1: [65535, 8, 32]\n" |
| 206 " 1: [65535, 17, 3]\n" |
| 207 " 3: [1, 2]\n" |
| 208 " 3: [2]\n" |
| 209 " 3: [21, 0, 0]\n" |
| 210 " 0: [65534]\n" |
| 211 " 3: [8, 1, 0, 0, 0]\n" |
| 212 " 1: [65535, 12, 2]\n" |
| 213 " 3: [1, 1]\n" |
| 214 " 3: [10]\n" |
| 215 " 0: [65534]\n" |
| 216 " 0: [65534]\n", |
| 217 Munger.getTestResults()); |
| 218 } |
| 219 |
| 220 // Show that an error occurs if the block abbreviation index bit limit is |
| 221 // greater than the maximum allowable. |
| 222 TEST(NaClMungerWriteErrorTests, CantWriteBlockWithBadBitLimit) { |
| 223 // Replace initial block enter with value out of range. |
| 224 const uint64_t Edit[] = { |
| 225 0, NaClMungedBitcode::Replace, |
| 226 1, naclbitc::BLK_CODE_ENTER, naclbitc::MODULE_BLOCK_ID, |
| 227 naclbitc::MaxAbbrevWidth + 1, Terminator |
| 228 }; |
| 229 NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| 230 EXPECT_FALSE(Munger.runTest(ARRAY_ARGS(Edit))); |
| 231 EXPECT_EQ( |
| 232 "Error (Block unknown): Block index bit limit 33 invalid. Must be in" |
| 233 " [2..32]: 1: [65535, 8, 33]\n" |
| 234 "Error: Unable to generate bitcode file due to write errors\n", |
| 235 Munger.getTestResults()); |
| 236 } |
| 237 |
| 238 // Show that we can't write an enter block with a very large block id. |
| 239 TEST(NaClMungerWriteErrorTests, CantWriteBlockWithLargeBlockID) { |
| 240 // Replace initial block enter with value out of range. |
| 241 const uint64_t Edit[] = { |
| 242 0, NaClMungedBitcode::Replace, |
| 243 1, naclbitc::BLK_CODE_ENTER, (uint64_t)1 << 33, 2, Terminator |
| 244 }; |
| 245 NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| 246 EXPECT_FALSE(Munger.runTest(ARRAY_ARGS(Edit))); |
| 247 EXPECT_EQ( |
| 248 "Error (Block unknown): Block id must be <= 4294967295: 1:" |
| 249 " [65535, 8589934592, 2]\n" |
| 250 "Error: Unable to generate bitcode file due to write errors\n", |
| 251 Munger.getTestResults()); |
| 252 } |
| 253 |
| 254 // Show that writing successfully writes out an illegal abbreviation |
| 255 // index, and then the parser fails to parse that illegal abbreviation. |
| 256 TEST(MyNaClMungerWriteErrorTests, DieOnWriteBadAbbreviationIndex) { |
| 257 NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| 258 Munger.setWriteBadAbbrevIndex(true); |
| 259 Munger.setRunAsDeathTest(true); |
| 260 EXPECT_DEATH( |
| 261 Munger.runTest(ARRAY_ARGS(AbbrevIndex4VoidTypeEdit)), |
| 262 ".*" |
| 263 // Report problem while writing. |
| 264 "Error \\(Block 17\\)\\: Uses illegal abbreviation index\\: 4\\: \\[2\\]" |
| 265 ".*" |
| 266 // Corresponding error while parsing. |
| 267 "Fatal\\(35\\:0)\\: Invalid abbreviation \\# 4 defined for record" |
| 268 ".*" |
| 269 // Output of report_fatal_error. |
| 270 "LLVM ERROR\\: Unable to continue" |
| 271 ".*"); |
| 272 } |
| 273 |
| 274 // Show that error recovery works when writing an illegal abbreviation |
| 275 // index. Show success by parsing fixed bitcode. |
| 276 TEST(NaClMungeWriteErrorTests, RecoverWhenParsingBadAbbrevIndex) { |
| 277 NaClParseBitcodeMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| 278 Munger.setTryToRecoverOnWrite(true); |
| 279 EXPECT_TRUE( |
| 280 Munger.runTest(ARRAY_ARGS(AbbrevIndex4VoidTypeEdit), true)); |
| 281 EXPECT_EQ( |
| 282 "Error (Block 17): Uses illegal abbreviation index: 4: [2]\n" |
| 283 "Successful parse!\n", |
| 284 Munger.getTestResults()); |
| 285 } |
| 286 |
| 287 // Show that error recovery works when writing an illegal abbreviation |
| 288 // index. Show success by Dumping fixed bitcode. |
| 289 TEST(NaClMungeWriteErrorTests, RecoverWhenParsingBadAbbreviationIndex) { |
| 290 NaClObjDumpMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| 291 Munger.setTryToRecoverOnWrite(true); |
| 292 EXPECT_TRUE(Munger.runTest(ARRAY_ARGS(AbbrevIndex4VoidTypeEdit))); |
| 293 std::string Results( |
| 294 "Error (Block 17): Uses illegal abbreviation index: 4: [2]\n"); |
| 295 Results.append(ExpectedDump); |
| 296 EXPECT_EQ(Results, Munger.getTestResults()); |
| 297 } |
| 298 |
| 299 // Show that error recovery works when writing too many locally |
| 300 // defined abbreviations for the corresponding number of bits defined |
| 301 // in the corresponding enter block. Show success by dumping the fixed |
| 302 // bitcode. |
| 303 TEST(NaClMungeWriteErrorTests, RecoverTooManyLocalAbbreviations) { |
| 304 NaClObjDumpMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| 305 Munger.setTryToRecoverOnWrite(true); |
| 306 Munger.munge(ARRAY_ARGS(UseLocalRetVoidAbbrevEdits)); |
| 307 |
| 308 EXPECT_TRUE(Munger.runTest()); |
| 309 std::string Results( |
| 310 "Error (Block 12): Exceeds abbreviation index limit of 3: 2:" |
| 311 " [65533, 1, 1, 10]\n" |
| 312 "Error (Block 12): Uses illegal abbreviation index: 4: [10]\n"); |
| 313 Results.append(ExpectedDump); |
| 314 EXPECT_EQ( |
| 315 Results, |
| 316 Munger.getTestResults()); |
| 317 } |
| 318 |
| 319 // Show that error recovery works when writing and there are more |
| 320 // enter blocks than exit blocks. Show success by dumping fixed |
| 321 // bitcode. |
| 322 TEST(NaClMungeWriteErrorTests, RecoverTooManyEnterBlocks) { |
| 323 NaClObjDumpMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| 324 // Remove all but first two records (i.e. two enter blocks). |
| 325 NaClMungedBitcode &MungedBitcode = Munger.getMungedBitcode(); |
| 326 for (size_t i = 2; i < MungedBitcode.getBaseRecords().size(); ++i) { |
| 327 MungedBitcode.remove(i); |
| 328 } |
| 329 |
| 330 Munger.setTryToRecoverOnWrite(true); |
| 331 EXPECT_TRUE(Munger.runTest()); |
| 332 EXPECT_EQ( |
| 333 "Error (Block 17): Missing close block.\n" |
| 334 "Error (Block 8): Missing close block.\n" |
| 335 " 0:0|<65532, 80, 69, 88, 69, 1, 0,|Magic Number: 'PEXE' (80, 69," |
| 336 " 88, 69)\n" |
| 337 " | 8, 0, 17, 0, 4, 0, 2, 0, 0, |PNaCl Version: 2\n" |
| 338 " | 0> |\n" |
| 339 " 16:0|1: <65535, 8, 2> |module { // BlockID = 8\n" |
| 340 " 24:0| 1: <65535, 17, 3> | types { // BlockID = 17\n" |
| 341 " 32:0| 0: <65534> | }\n" |
| 342 " 36:0|0: <65534> |}\n", |
| 343 Munger.getTestResults()); |
| 344 } |
| 345 |
| 346 // Show that error recovery works when writing and there are fewer |
| 347 // enter blocks than exit blocks. Show success by dumping the fixed |
| 348 // bitcode. |
| 349 TEST(NaClMungeWriteErrorTests, RecoverTooManyExitBlocks) { |
| 350 NaClObjDumpMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| 351 // Add two exit blocks. |
| 352 NaClMungedBitcode &MungedBitcode = Munger.getMungedBitcode(); |
| 353 NaClRecordVector Values; |
| 354 NaClBitcodeAbbrevRecord Record(0, naclbitc::BLK_CODE_EXIT, Values); |
| 355 for (size_t i = 0; i < 2; ++i) |
| 356 MungedBitcode.addAfter(MungedBitcode.getBaseRecords().size() - 1, Record); |
| 357 |
| 358 Munger.setTryToRecoverOnWrite(true); |
| 359 EXPECT_TRUE(Munger.runTest()); |
| 360 std::string Results( |
| 361 "Error (Block unknown): Extraneous exit block: 0: [65534]\n" |
| 362 "Error (Block unknown): Extraneous exit block: 0: [65534]\n"); |
| 363 Results.append(ExpectedDump); |
| 364 EXPECT_EQ( |
| 365 Results, |
| 366 Munger.getTestResults()); |
| 367 } |
| 368 |
| 369 // Show that error recovery works when writing a bitcode record that |
| 370 // isn't in any block. Show success by showing fixed bitcode records. |
| 371 TEST(NaClMungeWriteErrorTests, RecoverWriteRecordOutsideBlock) { |
| 372 NaClWriteMunger Munger(ARRAY_ARGS_TERM(BitcodeRecords)); |
| 373 NaClMungedBitcode &MungedBitcode = Munger.getMungedBitcode(); |
| 374 NaClRecordVector Values; |
| 375 Values.push_back(4); |
| 376 NaClBitcodeAbbrevRecord Record(naclbitc::UNABBREV_RECORD, |
| 377 naclbitc::MODULE_CODE_VERSION, |
| 378 Values); |
| 379 MungedBitcode.addAfter(MungedBitcode.getBaseRecords().size() - 1, Record); |
| 380 |
| 381 Munger.setTryToRecoverOnWrite(true); |
| 382 EXPECT_TRUE(Munger.runTest()); |
| 383 EXPECT_EQ( |
| 384 "Error (Block unknown): Record outside block: 3: [1, 4]\n" |
| 385 "Error (Block unknown): Missing close block.\n" |
| 386 " 1: [65535, 8, 2]\n" |
| 387 " 1: [65535, 17, 3]\n" |
| 388 " 3: [1, 2]\n" |
| 389 " 3: [2]\n" |
| 390 " 3: [21, 0, 0]\n" |
| 391 " 0: [65534]\n" |
| 392 " 3: [8, 1, 0, 0, 0]\n" |
| 393 " 1: [65535, 12, 2]\n" |
| 394 " 3: [1, 1]\n" |
| 395 " 3: [10]\n" |
| 396 " 0: [65534]\n" |
| 397 " 0: [65534]\n" |
| 398 " 1: [65535, 4294967295, 3]\n" |
| 399 " 3: [1, 4]\n" |
| 400 " 0: [65534]\n", |
| 401 Munger.getTestResults()); |
| 402 } |
| 403 |
| 404 } // end of anonymous namespace. |
OLD | NEW |