For PR797:

Make the Bytecode Reader use setjmp/longjump instead of exceptions to handle
errors. The alternative was even uglier than setjmp/longjump as it would
impact the interface and workings of nearly every function in the reader.

llvm-svn: 29819
This commit is contained in:
Reid Spencer 2006-08-22 16:09:19 +00:00
parent 88b3207059
commit d00c37651a
2 changed files with 118 additions and 117 deletions

View File

@ -51,13 +51,10 @@ namespace {
} }
// Provide some details on error // Provide some details on error
inline void BytecodeReader::error(std::string err) { inline void BytecodeReader::error(const std::string& err) {
err += " (Vers=" ; ErrorMsg = err + " (Vers=" + itostr(RevisionNum) + ", Pos="
err += itostr(RevisionNum) ; + itostr(At-MemStart) + ")";
err += ", Pos=" ; longjmp(context,1);
err += itostr(At-MemStart);
err += ")";
throw err;
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -470,7 +467,8 @@ Value * BytecodeReader::getValue(unsigned type, unsigned oNum, bool Create) {
ForwardReferences.insert(I, std::make_pair(KeyValue, Val)); ForwardReferences.insert(I, std::make_pair(KeyValue, Val));
return Val; return Val;
} }
throw "Can't create placeholder for value of type slot #" + utostr(type); error("Can't create placeholder for value of type slot #" + utostr(type));
return 0; // just silence warning, error calls longjmp
} }
/// This is just like getValue, but when a compaction table is in use, it /// This is just like getValue, but when a compaction table is in use, it
@ -718,12 +716,12 @@ void BytecodeReader::ParseInstruction(std::vector<unsigned> &Oprnds,
} }
case Instruction::ExtractElement: { case Instruction::ExtractElement: {
if (Oprnds.size() != 2) if (Oprnds.size() != 2)
throw std::string("Invalid extractelement instruction!"); error("Invalid extractelement instruction!");
Value *V1 = getValue(iType, Oprnds[0]); Value *V1 = getValue(iType, Oprnds[0]);
Value *V2 = getValue(Type::UIntTyID, Oprnds[1]); Value *V2 = getValue(Type::UIntTyID, Oprnds[1]);
if (!ExtractElementInst::isValidOperands(V1, V2)) if (!ExtractElementInst::isValidOperands(V1, V2))
throw std::string("Invalid extractelement instruction!"); error("Invalid extractelement instruction!");
Result = new ExtractElementInst(V1, V2); Result = new ExtractElementInst(V1, V2);
break; break;
@ -731,28 +729,28 @@ void BytecodeReader::ParseInstruction(std::vector<unsigned> &Oprnds,
case Instruction::InsertElement: { case Instruction::InsertElement: {
const PackedType *PackedTy = dyn_cast<PackedType>(InstTy); const PackedType *PackedTy = dyn_cast<PackedType>(InstTy);
if (!PackedTy || Oprnds.size() != 3) if (!PackedTy || Oprnds.size() != 3)
throw std::string("Invalid insertelement instruction!"); error("Invalid insertelement instruction!");
Value *V1 = getValue(iType, Oprnds[0]); Value *V1 = getValue(iType, Oprnds[0]);
Value *V2 = getValue(getTypeSlot(PackedTy->getElementType()), Oprnds[1]); Value *V2 = getValue(getTypeSlot(PackedTy->getElementType()), Oprnds[1]);
Value *V3 = getValue(Type::UIntTyID, Oprnds[2]); Value *V3 = getValue(Type::UIntTyID, Oprnds[2]);
if (!InsertElementInst::isValidOperands(V1, V2, V3)) if (!InsertElementInst::isValidOperands(V1, V2, V3))
throw std::string("Invalid insertelement instruction!"); error("Invalid insertelement instruction!");
Result = new InsertElementInst(V1, V2, V3); Result = new InsertElementInst(V1, V2, V3);
break; break;
} }
case Instruction::ShuffleVector: { case Instruction::ShuffleVector: {
const PackedType *PackedTy = dyn_cast<PackedType>(InstTy); const PackedType *PackedTy = dyn_cast<PackedType>(InstTy);
if (!PackedTy || Oprnds.size() != 3) if (!PackedTy || Oprnds.size() != 3)
throw std::string("Invalid shufflevector instruction!"); error("Invalid shufflevector instruction!");
Value *V1 = getValue(iType, Oprnds[0]); Value *V1 = getValue(iType, Oprnds[0]);
Value *V2 = getValue(iType, Oprnds[1]); Value *V2 = getValue(iType, Oprnds[1]);
const PackedType *EltTy = const PackedType *EltTy =
PackedType::get(Type::UIntTy, PackedTy->getNumElements()); PackedType::get(Type::UIntTy, PackedTy->getNumElements());
Value *V3 = getValue(getTypeSlot(EltTy), Oprnds[2]); Value *V3 = getValue(getTypeSlot(EltTy), Oprnds[2]);
if (!ShuffleVectorInst::isValidOperands(V1, V2, V3)) if (!ShuffleVectorInst::isValidOperands(V1, V2, V3))
throw std::string("Invalid shufflevector instruction!"); error("Invalid shufflevector instruction!");
Result = new ShuffleVectorInst(V1, V2, V3); Result = new ShuffleVectorInst(V1, V2, V3);
break; break;
} }
@ -2403,95 +2401,14 @@ void BytecodeReader::ParseModule() {
/// This function completely parses a bytecode buffer given by the \p Buf /// This function completely parses a bytecode buffer given by the \p Buf
/// and \p Length parameters. /// and \p Length parameters.
void BytecodeReader::ParseBytecode(BufPtr Buf, unsigned Length, bool BytecodeReader::ParseBytecode(BufPtr Buf, unsigned Length,
const std::string &ModuleID) { const std::string &ModuleID,
std::string* ErrMsg) {
try { /// We handle errors by
RevisionNum = 0; if (setjmp(context)) {
At = MemStart = BlockStart = Buf; // Cleanup after error
MemEnd = BlockEnd = Buf + Length; if (Handler) Handler->handleError(ErrorMsg);
// Create the module
TheModule = new Module(ModuleID);
if (Handler) Handler->handleStart(TheModule, Length);
// Read the four bytes of the signature.
unsigned Sig = read_uint();
// If this is a compressed file
if (Sig == ('l' | ('l' << 8) | ('v' << 16) | ('c' << 24))) {
// Invoke the decompression of the bytecode. Note that we have to skip the
// file's magic number which is not part of the compressed block. Hence,
// the Buf+4 and Length-4. The result goes into decompressedBlock, a data
// member for retention until BytecodeReader is destructed.
unsigned decompressedLength = Compressor::decompressToNewBuffer(
(char*)Buf+4,Length-4,decompressedBlock);
// We must adjust the buffer pointers used by the bytecode reader to point
// into the new decompressed block. After decompression, the
// decompressedBlock will point to a contiguous memory area that has
// the decompressed data.
At = MemStart = BlockStart = Buf = (BufPtr) decompressedBlock;
MemEnd = BlockEnd = Buf + decompressedLength;
// else if this isn't a regular (uncompressed) bytecode file, then its
// and error, generate that now.
} else if (Sig != ('l' | ('l' << 8) | ('v' << 16) | ('m' << 24))) {
error("Invalid bytecode signature: " + utohexstr(Sig));
}
// Tell the handler we're starting a module
if (Handler) Handler->handleModuleBegin(ModuleID);
// Get the module block and size and verify. This is handled specially
// because the module block/size is always written in long format. Other
// blocks are written in short format so the read_block method is used.
unsigned Type, Size;
Type = read_uint();
Size = read_uint();
if (Type != BytecodeFormat::ModuleBlockID) {
error("Expected Module Block! Type:" + utostr(Type) + ", Size:"
+ utostr(Size));
}
// It looks like the darwin ranlib program is broken, and adds trailing
// garbage to the end of some bytecode files. This hack allows the bc
// reader to ignore trailing garbage on bytecode files.
if (At + Size < MemEnd)
MemEnd = BlockEnd = At+Size;
if (At + Size != MemEnd)
error("Invalid Top Level Block Length! Type:" + utostr(Type)
+ ", Size:" + utostr(Size));
// Parse the module contents
this->ParseModule();
// Check for missing functions
if (hasFunctions())
error("Function expected, but bytecode stream ended!");
// Look for intrinsic functions to upgrade, upgrade them, and save the
// mapping from old function to new for use later when instructions are
// converted.
for (Module::iterator FI = TheModule->begin(), FE = TheModule->end();
FI != FE; ++FI)
if (Function* newF = UpgradeIntrinsicFunction(FI)) {
upgradedFunctions.insert(std::make_pair(FI, newF));
FI->setName("");
}
// Tell the handler we're done with the module
if (Handler)
Handler->handleModuleEnd(ModuleID);
// Tell the handler we're finished the parse
if (Handler) Handler->handleFinish();
} catch (std::string& errstr) {
if (Handler) Handler->handleError(errstr);
freeState(); freeState();
delete TheModule; delete TheModule;
TheModule = 0; TheModule = 0;
@ -2499,19 +2416,98 @@ void BytecodeReader::ParseBytecode(BufPtr Buf, unsigned Length,
::free(decompressedBlock); ::free(decompressedBlock);
decompressedBlock = 0; decompressedBlock = 0;
} }
throw; // Set caller's error message, if requested
} catch (...) { if (ErrMsg)
std::string msg("Unknown Exception Occurred"); *ErrMsg = ErrorMsg;
if (Handler) Handler->handleError(msg); // Indicate an error occurred
freeState(); return true;
delete TheModule;
TheModule = 0;
if (decompressedBlock != 0) {
::free(decompressedBlock);
decompressedBlock = 0;
}
throw msg;
} }
RevisionNum = 0;
At = MemStart = BlockStart = Buf;
MemEnd = BlockEnd = Buf + Length;
// Create the module
TheModule = new Module(ModuleID);
if (Handler) Handler->handleStart(TheModule, Length);
// Read the four bytes of the signature.
unsigned Sig = read_uint();
// If this is a compressed file
if (Sig == ('l' | ('l' << 8) | ('v' << 16) | ('c' << 24))) {
// Invoke the decompression of the bytecode. Note that we have to skip the
// file's magic number which is not part of the compressed block. Hence,
// the Buf+4 and Length-4. The result goes into decompressedBlock, a data
// member for retention until BytecodeReader is destructed.
unsigned decompressedLength = Compressor::decompressToNewBuffer(
(char*)Buf+4,Length-4,decompressedBlock);
// We must adjust the buffer pointers used by the bytecode reader to point
// into the new decompressed block. After decompression, the
// decompressedBlock will point to a contiguous memory area that has
// the decompressed data.
At = MemStart = BlockStart = Buf = (BufPtr) decompressedBlock;
MemEnd = BlockEnd = Buf + decompressedLength;
// else if this isn't a regular (uncompressed) bytecode file, then its
// and error, generate that now.
} else if (Sig != ('l' | ('l' << 8) | ('v' << 16) | ('m' << 24))) {
error("Invalid bytecode signature: " + utohexstr(Sig));
}
// Tell the handler we're starting a module
if (Handler) Handler->handleModuleBegin(ModuleID);
// Get the module block and size and verify. This is handled specially
// because the module block/size is always written in long format. Other
// blocks are written in short format so the read_block method is used.
unsigned Type, Size;
Type = read_uint();
Size = read_uint();
if (Type != BytecodeFormat::ModuleBlockID) {
error("Expected Module Block! Type:" + utostr(Type) + ", Size:"
+ utostr(Size));
}
// It looks like the darwin ranlib program is broken, and adds trailing
// garbage to the end of some bytecode files. This hack allows the bc
// reader to ignore trailing garbage on bytecode files.
if (At + Size < MemEnd)
MemEnd = BlockEnd = At+Size;
if (At + Size != MemEnd)
error("Invalid Top Level Block Length! Type:" + utostr(Type)
+ ", Size:" + utostr(Size));
// Parse the module contents
this->ParseModule();
// Check for missing functions
if (hasFunctions())
error("Function expected, but bytecode stream ended!");
// Look for intrinsic functions to upgrade, upgrade them, and save the
// mapping from old function to new for use later when instructions are
// converted.
for (Module::iterator FI = TheModule->begin(), FE = TheModule->end();
FI != FE; ++FI)
if (Function* newF = UpgradeIntrinsicFunction(FI)) {
upgradedFunctions.insert(std::make_pair(FI, newF));
FI->setName("");
}
// Tell the handler we're done with the module
if (Handler)
Handler->handleModuleEnd(ModuleID);
// Tell the handler we're finished the parse
if (Handler) Handler->handleFinish();
return false;
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -24,6 +24,7 @@
#include "llvm/Bytecode/Analyzer.h" #include "llvm/Bytecode/Analyzer.h"
#include <utility> #include <utility>
#include <map> #include <map>
#include <setjmp.h>
namespace llvm { namespace llvm {
@ -136,11 +137,13 @@ public:
/// @name Methods /// @name Methods
/// @{ /// @{
public: public:
/// @returns true if an error occurred
/// @brief Main interface to parsing a bytecode buffer. /// @brief Main interface to parsing a bytecode buffer.
void ParseBytecode( bool ParseBytecode(
const unsigned char *Buf, ///< Beginning of the bytecode buffer const unsigned char *Buf, ///< Beginning of the bytecode buffer
unsigned Length, ///< Length of the bytecode buffer unsigned Length, ///< Length of the bytecode buffer
const std::string &ModuleID ///< An identifier for the module constructed. const std::string &ModuleID, ///< An identifier for the module constructed.
std::string* ErrMsg = 0 ///< Optional place for error message
); );
/// @brief Parse all function bodies /// @brief Parse all function bodies
@ -260,6 +263,8 @@ protected:
/// @name Data /// @name Data
/// @{ /// @{
private: private:
std::string ErrorMsg; ///< A place to hold an error message through longjmp
jmp_buf context; ///< Where to return to if an error occurs.
char* decompressedBlock; ///< Result of decompression char* decompressedBlock; ///< Result of decompression
BufPtr MemStart; ///< Start of the memory buffer BufPtr MemStart; ///< Start of the memory buffer
BufPtr MemEnd; ///< End of the memory buffer BufPtr MemEnd; ///< End of the memory buffer
@ -487,7 +492,7 @@ private:
} }
} }
inline void error(std::string errmsg); inline void error(const std::string& errmsg);
BytecodeReader(const BytecodeReader &); // DO NOT IMPLEMENT BytecodeReader(const BytecodeReader &); // DO NOT IMPLEMENT
void operator=(const BytecodeReader &); // DO NOT IMPLEMENT void operator=(const BytecodeReader &); // DO NOT IMPLEMENT