Be more careful in parsing Module::ModFlagBehavior value

to make sure we don't do invalid load of an enum. Share the
conversion code between llvm::Module implementation and the
verifier.

This bug was reported by UBSan.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@217395 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Alexey Samsonov
2014-09-08 19:16:28 +00:00
parent 16ee570cc3
commit e769dc39fd
3 changed files with 36 additions and 18 deletions

View File

@@ -182,9 +182,17 @@ public:
/// Appends the two values, which are required to be metadata /// Appends the two values, which are required to be metadata
/// nodes. However, duplicate entries in the second list are dropped /// nodes. However, duplicate entries in the second list are dropped
/// during the append operation. /// during the append operation.
AppendUnique = 6 AppendUnique = 6,
// Markers:
ModFlagBehaviorFirstVal = Error,
ModFlagBehaviorLastVal = AppendUnique
}; };
/// Checks if Value represents a valid ModFlagBehavior, and stores the
/// converted result in MFB.
static bool isValidModFlagBehavior(Value *V, ModFlagBehavior &MFB);
struct ModuleFlagEntry { struct ModuleFlagEntry {
ModFlagBehavior Behavior; ModFlagBehavior Behavior;
MDString *Key; MDString *Key;

View File

@@ -259,6 +259,17 @@ void Module::eraseNamedMetadata(NamedMDNode *NMD) {
NamedMDList.erase(NMD); NamedMDList.erase(NMD);
} }
bool Module::isValidModFlagBehavior(Value *V, ModFlagBehavior &MFB) {
if (ConstantInt *Behavior = dyn_cast<ConstantInt>(V)) {
uint64_t Val = Behavior->getLimitedValue();
if (Val >= ModFlagBehaviorFirstVal && Val <= ModFlagBehaviorLastVal) {
MFB = static_cast<ModFlagBehavior>(Val);
return true;
}
}
return false;
}
/// getModuleFlagsMetadata - Returns the module flags in the provided vector. /// getModuleFlagsMetadata - Returns the module flags in the provided vector.
void Module:: void Module::
getModuleFlagsMetadata(SmallVectorImpl<ModuleFlagEntry> &Flags) const { getModuleFlagsMetadata(SmallVectorImpl<ModuleFlagEntry> &Flags) const {
@@ -266,15 +277,15 @@ getModuleFlagsMetadata(SmallVectorImpl<ModuleFlagEntry> &Flags) const {
if (!ModFlags) return; if (!ModFlags) return;
for (const MDNode *Flag : ModFlags->operands()) { for (const MDNode *Flag : ModFlags->operands()) {
if (Flag->getNumOperands() >= 3 && isa<ConstantInt>(Flag->getOperand(0)) && ModFlagBehavior MFB;
if (Flag->getNumOperands() >= 3 &&
isValidModFlagBehavior(Flag->getOperand(0), MFB) &&
isa<MDString>(Flag->getOperand(1))) { isa<MDString>(Flag->getOperand(1))) {
// Check the operands of the MDNode before accessing the operands. // Check the operands of the MDNode before accessing the operands.
// The verifier will actually catch these failures. // The verifier will actually catch these failures.
ConstantInt *Behavior = cast<ConstantInt>(Flag->getOperand(0));
MDString *Key = cast<MDString>(Flag->getOperand(1)); MDString *Key = cast<MDString>(Flag->getOperand(1));
Value *Val = Flag->getOperand(2); Value *Val = Flag->getOperand(2);
Flags.push_back(ModuleFlagEntry(ModFlagBehavior(Behavior->getZExtValue()), Flags.push_back(ModuleFlagEntry(MFB, Key, Val));
Key, Val));
} }
} }
} }

View File

@@ -673,24 +673,23 @@ Verifier::visitModuleFlag(const MDNode *Op,
// constant int), the flag ID (an MDString), and the value. // constant int), the flag ID (an MDString), and the value.
Assert1(Op->getNumOperands() == 3, Assert1(Op->getNumOperands() == 3,
"incorrect number of operands in module flag", Op); "incorrect number of operands in module flag", Op);
ConstantInt *Behavior = dyn_cast<ConstantInt>(Op->getOperand(0)); Module::ModFlagBehavior MFB;
MDString *ID = dyn_cast<MDString>(Op->getOperand(1)); if (!Module::isValidModFlagBehavior(Op->getOperand(0), MFB)) {
Assert1(Behavior, Assert1(
dyn_cast<ConstantInt>(Op->getOperand(0)),
"invalid behavior operand in module flag (expected constant integer)", "invalid behavior operand in module flag (expected constant integer)",
Op->getOperand(0)); Op->getOperand(0));
unsigned BehaviorValue = Behavior->getZExtValue(); Assert1(false,
"invalid behavior operand in module flag (unexpected constant)",
Op->getOperand(0));
}
MDString *ID = dyn_cast<MDString>(Op->getOperand(1));
Assert1(ID, Assert1(ID,
"invalid ID operand in module flag (expected metadata string)", "invalid ID operand in module flag (expected metadata string)",
Op->getOperand(1)); Op->getOperand(1));
// Sanity check the values for behaviors with additional requirements. // Sanity check the values for behaviors with additional requirements.
switch (BehaviorValue) { switch (MFB) {
default:
Assert1(false,
"invalid behavior operand in module flag (unexpected constant)",
Op->getOperand(0));
break;
case Module::Error: case Module::Error:
case Module::Warning: case Module::Warning:
case Module::Override: case Module::Override:
@@ -726,7 +725,7 @@ Verifier::visitModuleFlag(const MDNode *Op,
} }
// Unless this is a "requires" flag, check the ID is unique. // Unless this is a "requires" flag, check the ID is unique.
if (BehaviorValue != Module::Require) { if (MFB != Module::Require) {
bool Inserted = SeenIDs.insert(std::make_pair(ID, Op)).second; bool Inserted = SeenIDs.insert(std::make_pair(ID, Op)).second;
Assert1(Inserted, Assert1(Inserted,
"module flag identifiers must be unique (or of 'require' type)", "module flag identifiers must be unique (or of 'require' type)",