2016-01-26 19:48:36 +01:00
|
|
|
//===- llvm/unittest/IR/VerifierTest.cpp - Verifier unit tests --*- C++ -*-===//
|
2010-02-15 23:09:09 +01:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-06-06 13:06:56 +02:00
|
|
|
#include "llvm/IR/Verifier.h"
|
2013-01-02 12:36:10 +01:00
|
|
|
#include "llvm/IR/Constants.h"
|
2016-01-14 23:42:02 +01:00
|
|
|
#include "llvm/IR/DIBuilder.h"
|
2013-01-02 12:36:10 +01:00
|
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/GlobalAlias.h"
|
|
|
|
#include "llvm/IR/GlobalVariable.h"
|
2016-09-14 19:30:37 +02:00
|
|
|
#include "llvm/IR/IRBuilder.h"
|
2017-06-06 13:06:56 +02:00
|
|
|
#include "llvm/IR/Instructions.h"
|
2013-01-02 12:36:10 +01:00
|
|
|
#include "llvm/IR/LLVMContext.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
2010-02-15 23:09:09 +01:00
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
TEST(VerifierTest, Branch_i1) {
|
2016-04-14 23:59:01 +02:00
|
|
|
LLVMContext C;
|
2013-10-30 23:37:51 +01:00
|
|
|
Module M("M", C);
|
2010-02-15 23:09:09 +01:00
|
|
|
FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false);
|
2013-10-30 23:37:51 +01:00
|
|
|
Function *F = cast<Function>(M.getOrInsertFunction("foo", FTy));
|
|
|
|
BasicBlock *Entry = BasicBlock::Create(C, "entry", F);
|
|
|
|
BasicBlock *Exit = BasicBlock::Create(C, "exit", F);
|
2010-02-15 23:09:09 +01: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 03:22:18 +01:00
|
|
|
EXPECT_TRUE(verifyFunction(*F));
|
2010-02-15 23:09:09 +01:00
|
|
|
}
|
|
|
|
|
2013-06-19 21:26:44 +02:00
|
|
|
TEST(VerifierTest, InvalidRetAttribute) {
|
2016-04-14 23:59:01 +02:00
|
|
|
LLVMContext C;
|
2013-06-19 21:26:44 +02:00
|
|
|
Module M("M", C);
|
|
|
|
FunctionType *FTy = FunctionType::get(Type::getInt32Ty(C), /*isVarArg=*/false);
|
|
|
|
Function *F = cast<Function>(M.getOrInsertFunction("foo", FTy));
|
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-21 17:57:19 +01:00
|
|
|
AttributeList AS = F->getAttributes();
|
|
|
|
F->setAttributes(
|
|
|
|
AS.addAttribute(C, AttributeList::ReturnIndex, Attribute::UWTable));
|
2013-06-19 21:26:44 +02:00
|
|
|
|
|
|
|
std::string Error;
|
2014-01-19 03:22:18 +01: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-19 21:26:44 +02:00
|
|
|
}
|
|
|
|
|
2015-12-01 20:06:36 +01:00
|
|
|
TEST(VerifierTest, CrossModuleRef) {
|
2016-04-14 23:59:01 +02:00
|
|
|
LLVMContext C;
|
2015-12-01 20:06:36 +01:00
|
|
|
Module M1("M1", C);
|
|
|
|
Module M2("M2", C);
|
2016-01-14 23:20:56 +01:00
|
|
|
Module M3("M3", C);
|
2015-12-01 20:06:36 +01:00
|
|
|
FunctionType *FTy = FunctionType::get(Type::getInt32Ty(C), /*isVarArg=*/false);
|
|
|
|
Function *F1 = cast<Function>(M1.getOrInsertFunction("foo1", FTy));
|
|
|
|
Function *F2 = cast<Function>(M2.getOrInsertFunction("foo2", FTy));
|
|
|
|
Function *F3 = cast<Function>(M3.getOrInsertFunction("foo3", FTy));
|
|
|
|
|
|
|
|
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-14 23:20:56 +01: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-01 20:06:36 +01: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 15:23:52 +02: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-02 20:31:29 +02:00
|
|
|
TEST(VerifierTest, DetectInvalidDebugInfo) {
|
2016-09-14 19:30:37 +02:00
|
|
|
{
|
|
|
|
LLVMContext C;
|
|
|
|
Module M("M", C);
|
|
|
|
DIBuilder DIB(M);
|
2016-12-14 21:24:54 +01:00
|
|
|
DIB.createCompileUnit(dwarf::DW_LANG_C89, DIB.createFile("broken.c", "/"),
|
|
|
|
"unittest", false, "", 0);
|
2016-09-14 19:30:37 +02: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-14 21:24:54 +01:00
|
|
|
auto *CU = DIB.createCompileUnit(dwarf::DW_LANG_C89,
|
|
|
|
DIB.createFile("broken.c", "/"),
|
2016-09-14 19:30:37 +02:00
|
|
|
"unittest", false, "", 0);
|
|
|
|
new GlobalVariable(M, Type::getInt8Ty(C), false,
|
|
|
|
GlobalValue::ExternalLinkage, nullptr, "g");
|
|
|
|
|
|
|
|
auto *F = cast<Function>(M.getOrInsertFunction(
|
|
|
|
"f", FunctionType::get(Type::getVoidTy(C), false)));
|
|
|
|
IRBuilder<> Builder(BasicBlock::Create(C, "", F));
|
|
|
|
Builder.CreateUnreachable();
|
2018-11-19 19:29:28 +01:00
|
|
|
F->setSubprogram(DIB.createFunction(
|
|
|
|
CU, "f", "f", DIB.createFile("broken.c", "/"), 1, nullptr, 1,
|
|
|
|
DINode::FlagZero,
|
|
|
|
DISubprogram::SPFlagLocalToUnit | DISubprogram::SPFlagDefinition));
|
2016-09-14 19:30:37 +02: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-09 21:57:29 +02:00
|
|
|
}
|
|
|
|
|
2016-01-26 19:48:36 +01:00
|
|
|
} // end anonymous namespace
|
|
|
|
} // end namespace llvm
|