-
Notifications
You must be signed in to change notification settings - Fork 15
/
div_before_mul.cpp
136 lines (118 loc) · 5.1 KB
/
div_before_mul.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/**
* @file div_before_mul.cpp
* @brief find all division before multiplication that may lead to precision loss
*
* @ref https://github.com/crytic/slither/blob/master/slither/detectors/statements/divide_before_multiply.py
*
*/
#include "near_core.h"
#include <cstring>
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Pass.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
namespace {
struct DBM : public llvm::FunctionPass {
static char ID;
private:
llvm::raw_fd_ostream *os = nullptr;
bool isMul(llvm::Instruction *I) {
using namespace llvm;
const char *opName = I->getOpcodeName();
// mul, smul, umul, fmul
return !strncmp(opName, "mul", 3) || !strncmp(opName + 1, "mul", 3);
}
bool isLlvmMul(llvm::Instruction *I) {
using namespace llvm;
// llvm.[mul, smul, umul, fmul]
if (auto *callInst = dyn_cast<CallBase>(I)) {
if (callInst->getCalledFunction()) // !!! important
if (Regex("llvm\\.[a-z]?mul\\.with\\.overflow\\.").match(callInst->getCalledFunction()->getName()))
return true;
}
return false;
}
/**
* @brief
*
* @param I
* @return true
* @return false
*/
bool isDiv(llvm::Instruction *I) {
using namespace llvm;
const char *opName = I->getOpcodeName();
// sdiv, udiv, fdiv
return !strncmp(opName + 1, "div", 3);
}
public:
DBM() : FunctionPass(ID) {
std::error_code EC;
os = new llvm::raw_fd_ostream(std::string(getenv("TMP_DIR")) + std::string("/.div-before-mul.tmp"), EC, llvm::sys::fs::OpenFlags::OF_Append);
}
~DBM() { os->close(); }
/**
* @brief
*
* @param F current function
* @return true
* @return false
*/
bool runOnFunction(llvm::Function &F) override {
using namespace llvm;
if (!Rustle::debug_check_all_func && Rustle::regexForLibFunc.match(F.getName()))
return false;
if (Rustle::debug_print_function)
Rustle::Logger().Debug("Checking function ", F.getName());
bool foundOnFunc = false;
for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
if (!I.getDebugLoc().get() || Rustle::regexForLibLoc.match(I.getDebugLoc().get()->getFilename()))
continue;
if (isDiv(&I)) {
std::set<Value *> set;
Rustle::simpleFindUsers(&I, set, true);
bool found = false;
for (auto &i : set) {
if (auto *inst = dyn_cast<Instruction>(i)) {
if (!inst->getDebugLoc().get() || Rustle::regexForLibLoc.match(inst->getDebugLoc().get()->getFilename()))
continue;
if (isMul(inst) || isLlvmMul(inst)) {
*os << F.getName() << "@" << I.getDebugLoc()->getFilename() << "@" << I.getDebugLoc().getLine() << "\n";
found = true;
foundOnFunc = true;
break;
}
}
}
if (found) {
std::vector<llvm::DebugLoc> mulLoc;
for (auto &i : set) {
if (auto *inst = dyn_cast<Instruction>(i)) {
if (!inst->getDebugLoc().get() || Rustle::regexForLibLoc.match(inst->getDebugLoc().get()->getFilename()))
continue;
if (isMul(inst) || isLlvmMul(inst)) {
mulLoc.push_back(inst->getDebugLoc());
}
}
}
Rustle::Logger().Warning("Found div-before-mul, div at ", I.getDebugLoc(), ", mul at ", mulLoc);
}
}
}
}
if (!foundOnFunc && Rustle::debug_print_notfound)
Rustle::Logger().Info("Division before multiplication not found");
return false;
}
};
} // namespace
char DBM::ID = 0;
static llvm::RegisterPass<DBM> X("div-before-mul", "", false /* Only looks at CFG */, false /* Analysis Pass */);
static llvm::RegisterStandardPasses Y(llvm::PassManagerBuilder::EP_EarlyAsPossible, [](const llvm::PassManagerBuilder &builder, llvm::legacy::PassManagerBase &PM) { PM.add(new DBM()); });