2016-01-27 02:48:36 +08:00
|
|
|
//===- llvm/unittest/IR/VerifierTest.cpp - Verifier unit tests --*- C++ -*-===//
|
2010-02-16 06:09:09 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2010-02-16 06:09:09 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-06-06 19:06:56 +08:00
|
|
|
#include "llvm/IR/Verifier.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/Constants.h"
|
2016-01-15 06:42:02 +08:00
|
|
|
#include "llvm/IR/DIBuilder.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/GlobalAlias.h"
|
|
|
|
#include "llvm/IR/GlobalVariable.h"
|
2016-09-15 01:30:37 +08:00
|
|
|
#include "llvm/IR/IRBuilder.h"
|
2017-06-06 19:06:56 +08:00
|
|
|
#include "llvm/IR/Instructions.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/LLVMContext.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
2010-02-16 06:09:09 +08:00
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
TEST(VerifierTest, Branch_i1) {
|
2016-04-15 05:59:01 +08:00
|
|
|
LLVMContext C;
|
2013-10-31 06:37:51 +08:00
|
|
|
Module M("M", C);
|
2010-02-16 06:09:09 +08:00
|
|
|
FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false);
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", M);
|
2013-10-31 06:37:51 +08:00
|
|
|
BasicBlock *Entry = BasicBlock::Create(C, "entry", F);
|
|
|
|
BasicBlock *Exit = BasicBlock::Create(C, "exit", F);
|
2010-02-16 06:09:09 +08:00
|
|
|
ReturnInst::Create(C, Exit);
|
|
|
|
|
|
|
|
// To avoid triggering an assertion in BranchInst::Create, we first create
|
|
|
|
// a branch with an 'i1' condition ...
|
|
|
|
|
|
|
|
Constant *False = ConstantInt::getFalse(C);
|
|
|
|
BranchInst *BI = BranchInst::Create(Exit, Exit, False, Entry);
|
|
|
|
|
|
|
|
// ... then use setOperand to redirect it to a value of different type.
|
|
|
|
|
|
|
|
Constant *Zero32 = ConstantInt::get(IntegerType::get(C, 32), 0);
|
|
|
|
BI->setOperand(0, Zero32);
|
|
|
|
|
2014-01-19 10:22:18 +08:00
|
|
|
EXPECT_TRUE(verifyFunction(*F));
|
2010-02-16 06:09:09 +08:00
|
|
|
}
|
|
|
|
|
[IR] Redefine Freeze instruction
Summary:
This patch redefines freeze instruction from being UnaryOperator to a subclass of UnaryInstruction.
ConstantExpr freeze is removed, as discussed in the previous review.
FreezeOperator is not added because there's no ConstantExpr freeze.
`freeze i8* null` test is added to `test/Bindings/llvm-c/freeze.ll` as well, because the null pointer-related bug in `tools/llvm-c/echo.cpp` is now fixed.
InstVisitor has visitFreeze now because freeze is not unaryop anymore.
Reviewers: whitequark, deadalnix, craig.topper, jdoerfert, lebedev.ri
Reviewed By: craig.topper, lebedev.ri
Subscribers: regehr, nlopes, mehdi_amini, hiraditya, steven_wu, dexonsmith, jfb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D69932
2019-11-07 00:17:49 +08:00
|
|
|
TEST(VerifierTest, Freeze) {
|
|
|
|
LLVMContext C;
|
|
|
|
Module M("M", C);
|
|
|
|
FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false);
|
|
|
|
Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", M);
|
|
|
|
BasicBlock *Entry = BasicBlock::Create(C, "entry", F);
|
|
|
|
ReturnInst *RI = ReturnInst::Create(C, Entry);
|
|
|
|
|
|
|
|
IntegerType *ITy = IntegerType::get(C, 32);
|
|
|
|
ConstantInt *CI = ConstantInt::get(ITy, 0);
|
|
|
|
|
|
|
|
// Valid type : freeze(<2 x i32>)
|
|
|
|
Constant *CV = ConstantVector::getSplat(2, CI);
|
|
|
|
FreezeInst *FI_vec = new FreezeInst(CV);
|
|
|
|
FI_vec->insertBefore(RI);
|
|
|
|
|
|
|
|
EXPECT_FALSE(verifyFunction(*F));
|
|
|
|
|
|
|
|
FI_vec->eraseFromParent();
|
|
|
|
|
|
|
|
// Valid type : freeze(float)
|
|
|
|
Constant *CFP = ConstantFP::get(Type::getDoubleTy(C), 0.0);
|
|
|
|
FreezeInst *FI_dbl = new FreezeInst(CFP);
|
|
|
|
FI_dbl->insertBefore(RI);
|
|
|
|
|
|
|
|
EXPECT_FALSE(verifyFunction(*F));
|
|
|
|
|
|
|
|
FI_dbl->eraseFromParent();
|
|
|
|
|
|
|
|
// Valid type : freeze(i32*)
|
|
|
|
PointerType *PT = PointerType::get(ITy, 0);
|
|
|
|
ConstantPointerNull *CPN = ConstantPointerNull::get(PT);
|
|
|
|
FreezeInst *FI_ptr = new FreezeInst(CPN);
|
|
|
|
FI_ptr->insertBefore(RI);
|
|
|
|
|
|
|
|
EXPECT_FALSE(verifyFunction(*F));
|
|
|
|
|
|
|
|
FI_ptr->eraseFromParent();
|
|
|
|
|
|
|
|
// Valid type : freeze(int)
|
|
|
|
FreezeInst *FI = new FreezeInst(CI);
|
|
|
|
FI->insertBefore(RI);
|
|
|
|
|
|
|
|
EXPECT_FALSE(verifyFunction(*F));
|
|
|
|
|
2019-11-12 10:23:19 +08:00
|
|
|
FI->eraseFromParent();
|
[IR] Redefine Freeze instruction
Summary:
This patch redefines freeze instruction from being UnaryOperator to a subclass of UnaryInstruction.
ConstantExpr freeze is removed, as discussed in the previous review.
FreezeOperator is not added because there's no ConstantExpr freeze.
`freeze i8* null` test is added to `test/Bindings/llvm-c/freeze.ll` as well, because the null pointer-related bug in `tools/llvm-c/echo.cpp` is now fixed.
InstVisitor has visitFreeze now because freeze is not unaryop anymore.
Reviewers: whitequark, deadalnix, craig.topper, jdoerfert, lebedev.ri
Reviewed By: craig.topper, lebedev.ri
Subscribers: regehr, nlopes, mehdi_amini, hiraditya, steven_wu, dexonsmith, jfb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D69932
2019-11-07 00:17:49 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 03:26:44 +08:00
|
|
|
TEST(VerifierTest, InvalidRetAttribute) {
|
2016-04-15 05:59:01 +08:00
|
|
|
LLVMContext C;
|
2013-06-20 03:26:44 +08:00
|
|
|
Module M("M", C);
|
|
|
|
FunctionType *FTy = FunctionType::get(Type::getInt32Ty(C), /*isVarArg=*/false);
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", M);
|
Rename AttributeSet to AttributeList
Summary:
This class is a list of AttributeSetNodes corresponding the function
prototype of a call or function declaration. This class used to be
called ParamAttrListPtr, then AttrListPtr, then AttributeSet. It is
typically accessed by parameter and return value index, so
"AttributeList" seems like a more intuitive name.
Rename AttributeSetImpl to AttributeListImpl to follow suit.
It's useful to rename this class so that we can rename AttributeSetNode
to AttributeSet later. AttributeSet is the set of attributes that apply
to a single function, argument, or return value.
Reviewers: sanjoy, javed.absar, chandlerc, pete
Reviewed By: pete
Subscribers: pete, jholewinski, arsenm, dschuff, mehdi_amini, jfb, nhaehnle, sbc100, void, llvm-commits
Differential Revision: https://reviews.llvm.org/D31102
llvm-svn: 298393
2017-03-22 00:57:19 +08:00
|
|
|
AttributeList AS = F->getAttributes();
|
|
|
|
F->setAttributes(
|
|
|
|
AS.addAttribute(C, AttributeList::ReturnIndex, Attribute::UWTable));
|
2013-06-20 03:26:44 +08:00
|
|
|
|
|
|
|
std::string Error;
|
2014-01-19 10:22:18 +08:00
|
|
|
raw_string_ostream ErrorOS(Error);
|
|
|
|
EXPECT_TRUE(verifyModule(M, &ErrorOS));
|
|
|
|
EXPECT_TRUE(StringRef(ErrorOS.str()).startswith(
|
|
|
|
"Attribute 'uwtable' only applies to functions!"));
|
2013-06-20 03:26:44 +08:00
|
|
|
}
|
|
|
|
|
2015-12-02 03:06:36 +08:00
|
|
|
TEST(VerifierTest, CrossModuleRef) {
|
2016-04-15 05:59:01 +08:00
|
|
|
LLVMContext C;
|
2015-12-02 03:06:36 +08:00
|
|
|
Module M1("M1", C);
|
|
|
|
Module M2("M2", C);
|
2016-01-15 06:20:56 +08:00
|
|
|
Module M3("M3", C);
|
2015-12-02 03:06:36 +08:00
|
|
|
FunctionType *FTy = FunctionType::get(Type::getInt32Ty(C), /*isVarArg=*/false);
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
Function *F1 = Function::Create(FTy, Function::ExternalLinkage, "foo1", M1);
|
|
|
|
Function *F2 = Function::Create(FTy, Function::ExternalLinkage, "foo2", M2);
|
|
|
|
Function *F3 = Function::Create(FTy, Function::ExternalLinkage, "foo3", M3);
|
2015-12-02 03:06:36 +08:00
|
|
|
|
|
|
|
BasicBlock *Entry1 = BasicBlock::Create(C, "entry", F1);
|
|
|
|
BasicBlock *Entry3 = BasicBlock::Create(C, "entry", F3);
|
|
|
|
|
|
|
|
// BAD: Referencing function in another module
|
|
|
|
CallInst::Create(F2,"call",Entry1);
|
|
|
|
|
|
|
|
// BAD: Referencing personality routine in another module
|
|
|
|
F3->setPersonalityFn(F2);
|
|
|
|
|
|
|
|
// Fill in the body
|
|
|
|
Constant *ConstZero = ConstantInt::get(Type::getInt32Ty(C), 0);
|
|
|
|
ReturnInst::Create(C, ConstZero, Entry1);
|
|
|
|
ReturnInst::Create(C, ConstZero, Entry3);
|
|
|
|
|
|
|
|
std::string Error;
|
|
|
|
raw_string_ostream ErrorOS(Error);
|
2016-01-15 06:20:56 +08:00
|
|
|
EXPECT_TRUE(verifyModule(M2, &ErrorOS));
|
|
|
|
EXPECT_TRUE(StringRef(ErrorOS.str())
|
|
|
|
.equals("Global is used by function in a different module\n"
|
|
|
|
"i32 ()* @foo2\n"
|
|
|
|
"; ModuleID = 'M2'\n"
|
|
|
|
"i32 ()* @foo3\n"
|
|
|
|
"; ModuleID = 'M3'\n"
|
|
|
|
"Global is referenced in a different module!\n"
|
|
|
|
"i32 ()* @foo2\n"
|
|
|
|
"; ModuleID = 'M2'\n"
|
|
|
|
" %call = call i32 @foo2()\n"
|
|
|
|
"i32 ()* @foo1\n"
|
|
|
|
"; ModuleID = 'M1'\n"));
|
|
|
|
|
|
|
|
Error.clear();
|
2015-12-02 03:06:36 +08:00
|
|
|
EXPECT_TRUE(verifyModule(M1, &ErrorOS));
|
|
|
|
EXPECT_TRUE(StringRef(ErrorOS.str()).equals(
|
|
|
|
"Referencing function in another module!\n"
|
|
|
|
" %call = call i32 @foo2()\n"
|
|
|
|
"; ModuleID = 'M1'\n"
|
|
|
|
"i32 ()* @foo2\n"
|
|
|
|
"; ModuleID = 'M2'\n"));
|
|
|
|
|
|
|
|
Error.clear();
|
|
|
|
EXPECT_TRUE(verifyModule(M3, &ErrorOS));
|
|
|
|
EXPECT_TRUE(StringRef(ErrorOS.str()).startswith(
|
|
|
|
"Referencing personality function in another module!"));
|
|
|
|
|
|
|
|
// Erase bad methods to avoid triggering an assertion failure on destruction
|
|
|
|
F1->eraseFromParent();
|
|
|
|
F3->eraseFromParent();
|
|
|
|
}
|
|
|
|
|
2016-05-11 21:23:52 +08:00
|
|
|
TEST(VerifierTest, InvalidVariableLinkage) {
|
|
|
|
LLVMContext C;
|
|
|
|
Module M("M", C);
|
|
|
|
new GlobalVariable(M, Type::getInt8Ty(C), false,
|
|
|
|
GlobalValue::LinkOnceODRLinkage, nullptr, "Some Global");
|
|
|
|
std::string Error;
|
|
|
|
raw_string_ostream ErrorOS(Error);
|
|
|
|
EXPECT_TRUE(verifyModule(M, &ErrorOS));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
StringRef(ErrorOS.str()).startswith("Global is external, but doesn't "
|
|
|
|
"have external or weak linkage!"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(VerifierTest, InvalidFunctionLinkage) {
|
|
|
|
LLVMContext C;
|
|
|
|
Module M("M", C);
|
|
|
|
|
|
|
|
FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false);
|
|
|
|
Function::Create(FTy, GlobalValue::LinkOnceODRLinkage, "foo", &M);
|
|
|
|
std::string Error;
|
|
|
|
raw_string_ostream ErrorOS(Error);
|
|
|
|
EXPECT_TRUE(verifyModule(M, &ErrorOS));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
StringRef(ErrorOS.str()).startswith("Global is external, but doesn't "
|
|
|
|
"have external or weak linkage!"));
|
|
|
|
}
|
|
|
|
|
2017-10-03 02:31:29 +08:00
|
|
|
TEST(VerifierTest, DetectInvalidDebugInfo) {
|
2016-09-15 01:30:37 +08:00
|
|
|
{
|
|
|
|
LLVMContext C;
|
|
|
|
Module M("M", C);
|
|
|
|
DIBuilder DIB(M);
|
2016-12-15 04:24:54 +08:00
|
|
|
DIB.createCompileUnit(dwarf::DW_LANG_C89, DIB.createFile("broken.c", "/"),
|
|
|
|
"unittest", false, "", 0);
|
2016-09-15 01:30:37 +08:00
|
|
|
DIB.finalize();
|
|
|
|
EXPECT_FALSE(verifyModule(M));
|
|
|
|
|
|
|
|
// Now break it by inserting non-CU node to the list of CUs.
|
|
|
|
auto *File = DIB.createFile("not-a-CU.f", ".");
|
|
|
|
NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu");
|
|
|
|
NMD->addOperand(File);
|
|
|
|
EXPECT_TRUE(verifyModule(M));
|
|
|
|
}
|
|
|
|
{
|
|
|
|
LLVMContext C;
|
|
|
|
Module M("M", C);
|
|
|
|
DIBuilder DIB(M);
|
2016-12-15 04:24:54 +08:00
|
|
|
auto *CU = DIB.createCompileUnit(dwarf::DW_LANG_C89,
|
|
|
|
DIB.createFile("broken.c", "/"),
|
2016-09-15 01:30:37 +08:00
|
|
|
"unittest", false, "", 0);
|
|
|
|
new GlobalVariable(M, Type::getInt8Ty(C), false,
|
|
|
|
GlobalValue::ExternalLinkage, nullptr, "g");
|
|
|
|
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
auto *F = Function::Create(FunctionType::get(Type::getVoidTy(C), false),
|
|
|
|
Function::ExternalLinkage, "f", M);
|
2016-09-15 01:30:37 +08:00
|
|
|
IRBuilder<> Builder(BasicBlock::Create(C, "", F));
|
|
|
|
Builder.CreateUnreachable();
|
2018-11-20 02:29:28 +08:00
|
|
|
F->setSubprogram(DIB.createFunction(
|
|
|
|
CU, "f", "f", DIB.createFile("broken.c", "/"), 1, nullptr, 1,
|
|
|
|
DINode::FlagZero,
|
|
|
|
DISubprogram::SPFlagLocalToUnit | DISubprogram::SPFlagDefinition));
|
2016-09-15 01:30:37 +08:00
|
|
|
DIB.finalize();
|
|
|
|
EXPECT_FALSE(verifyModule(M));
|
|
|
|
|
|
|
|
// Now break it by not listing the CU at all.
|
|
|
|
M.eraseNamedMetadata(M.getOrInsertNamedMetadata("llvm.dbg.cu"));
|
|
|
|
EXPECT_TRUE(verifyModule(M));
|
|
|
|
}
|
2016-05-10 03:57:29 +08:00
|
|
|
}
|
|
|
|
|
2016-01-27 02:48:36 +08:00
|
|
|
} // end anonymous namespace
|
|
|
|
} // end namespace llvm
|