Fix call instructions to check parameter types for consistency.
Checks each parameter of a call against the corresponding function
signature. It also checks that parameters are valid PNaCl parameter
types, unless the call is to an intrinsic.
BUG= https://code.google.com/p/nativeclient/issues/detail?id=4309
R=stichnot@chromium.org
Review URL: https://codereview.chromium.org/1354673002 .
diff --git a/src/PNaClTranslator.cpp b/src/PNaClTranslator.cpp
index d7678f3..ac9698e 100644
--- a/src/PNaClTranslator.cpp
+++ b/src/PNaClTranslator.cpp
@@ -2644,12 +2644,13 @@
// Extract out the called function and its return type.
uint32_t CalleeIndex = convertRelativeToAbsIndex(Values[1], BaseIndex);
Ice::Operand *Callee = getOperand(CalleeIndex);
+ const Ice::FuncSigType *Signature = nullptr;
Ice::Type ReturnType = Ice::IceType_void;
const Ice::Intrinsics::FullIntrinsicInfo *IntrinsicInfo = nullptr;
if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) {
Ice::FunctionDeclaration *Fcn = Context->getFunctionByID(CalleeIndex);
- const Ice::FuncSigType &Signature = Fcn->getSignature();
- ReturnType = Signature.getReturnType();
+ Signature = &Fcn->getSignature();
+ ReturnType = Signature->getReturnType();
// Check if this direct call is to an Intrinsic (starts with "llvm.")
bool BadIntrinsic;
@@ -2661,13 +2662,23 @@
raw_string_ostream StrBuf(Buffer);
StrBuf << "Invalid PNaCl intrinsic call to " << Name;
Error(StrBuf.str());
- appendErrorInstruction(ReturnType);
+ if (ReturnType != Ice::IceType_void)
+ appendErrorInstruction(ReturnType);
return;
}
} else {
ReturnType = Context->getSimpleTypeByID(Values[2]);
}
+ // Check return type.
+ if (IntrinsicInfo == nullptr && !isCallReturnType(ReturnType)) {
+ std::string Buffer;
+ raw_string_ostream StrBuf(Buffer);
+ StrBuf << "Return type of called function is invalid: " << ReturnType;
+ Error(StrBuf.str());
+ ReturnType = Ice::IceType_i32;
+ }
+
// Extract call information.
uint64_t CCInfo = Values[0];
CallingConv::ID CallingConv;
@@ -2677,12 +2688,21 @@
StrBuf << "Function call calling convention value " << (CCInfo >> 1)
<< " not understood.";
Error(StrBuf.str());
- appendErrorInstruction(ReturnType);
+ if (ReturnType != Ice::IceType_void)
+ appendErrorInstruction(ReturnType);
return;
}
bool IsTailCall = static_cast<bool>(CCInfo & 1);
Ice::SizeT NumParams = Values.size() - ParamsStartIndex;
-
+ if (Signature && NumParams != Signature->getNumArgs()) {
+ std::string Buffer;
+ raw_string_ostream StrBuf(Buffer);
+ StrBuf << "Call has " << NumParams
+ << " parameters. Signature expects: " << Signature->getNumArgs();
+ Error(StrBuf.str());
+ // Error recover by only checking parameters in both signature and call.
+ NumParams = std::min(NumParams, Signature->getNumArgs());
+ }
if (isIRGenerationDisabled()) {
assert(Callee == nullptr);
// Check that parameters are defined.
@@ -2695,30 +2715,67 @@
setNextLocalInstIndex(nullptr);
return;
}
-
// Create the call instruction.
Ice::Variable *Dest = (ReturnType == Ice::IceType_void)
? nullptr
: getNextInstVar(ReturnType);
- Ice::InstCall *Inst = nullptr;
+ std::unique_ptr<Ice::InstCall> Inst;
if (IntrinsicInfo) {
- Inst = Ice::InstIntrinsicCall::create(Func.get(), NumParams, Dest, Callee,
- IntrinsicInfo->Info);
+ Inst.reset(Ice::InstIntrinsicCall::create(Func.get(), NumParams, Dest,
+ Callee, IntrinsicInfo->Info));
} else {
- Inst = Ice::InstCall::create(Func.get(), NumParams, Dest, Callee,
- IsTailCall);
+ Inst.reset(Ice::InstCall::create(Func.get(), NumParams, Dest, Callee,
+ IsTailCall));
}
// Add parameters.
for (Ice::SizeT ParamIndex = 0; ParamIndex < NumParams; ++ParamIndex) {
- Inst->addArg(
- getRelativeOperand(Values[ParamsStartIndex + ParamIndex], BaseIndex));
+ Ice::Operand *Op =
+ getRelativeOperand(Values[ParamsStartIndex + ParamIndex], BaseIndex);
+ if (Op == nullptr) {
+ std::string Buffer;
+ raw_string_ostream StrBuf(Buffer);
+ StrBuf << "Parameter " << ParamIndex << " of call not defined";
+ Error(StrBuf.str());
+ if (ReturnType != Ice::IceType_void)
+ appendErrorInstruction(ReturnType);
+ return;
+ }
+
+ // Check that parameter type is valid.
+ if (Signature) {
+ if (Op->getType() != Signature->getArgType(ParamIndex)) {
+ std::string Buffer;
+ raw_string_ostream StrBuf(Buffer);
+ StrBuf << "Call argument " << *Op << " expects "
+ << Signature->getArgType(ParamIndex)
+ << ". Found: " << Op->getType();
+ Error(StrBuf.str());
+ } else if (IntrinsicInfo == nullptr &&
+ !isCallParameterType(Op->getType())) {
+ // TODO(kschimpf): Move this check to the function declaration, so
+ // that it only needs to be checked once.
+ std::string Buffer;
+ raw_string_ostream StrBuf(Buffer);
+ StrBuf << "Call argument " << *Op
+ << " matches declaration but has invalid type: "
+ << Op->getType();
+ Error(StrBuf.str());
+ }
+ } else if (!isCallParameterType(Op->getType())) {
+ std::string Buffer;
+ raw_string_ostream StrBuf(Buffer);
+ StrBuf << "Call argument " << *Op
+ << " has invalid type: " << Op->getType();
+ Error(StrBuf.str());
+ }
+ Inst->addArg(Op);
}
// If intrinsic call, validate call signature.
if (IntrinsicInfo) {
Ice::SizeT ArgIndex = 0;
- switch (IntrinsicInfo->validateCall(Inst, ArgIndex)) {
+ switch (IntrinsicInfo->validateCall(Inst.get(), ArgIndex)) {
case Ice::Intrinsics::IsValidCall:
break;
case Ice::Intrinsics::BadReturnType: {
@@ -2750,7 +2807,7 @@
}
}
- CurrentNode->appendInst(Inst);
+ CurrentNode->appendInst(Inst.release());
return;
}
case naclbitc::FUNC_CODE_INST_FORWARDTYPEREF: {