Skip to content

Commit 973e4cb

Browse files
committed
over-approximate more features instead of returning invalid exprs
this also introduces a mode that checks which approaximations (if any) contribute to the bug report if none, it's a real bug
1 parent e115305 commit 973e4cb

File tree

7 files changed

+51
-62
lines changed

7 files changed

+51
-62
lines changed

ir/instr.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -320,20 +320,16 @@ static StateValue fm_poison(State &s, expr a, const expr &ap, expr b,
320320
non_poison &= !val.isInf();
321321
}
322322
if (fmath.flags & FastMathFlags::ARCP) {
323-
s.useUnsupported("arcp");
324-
non_poison &= expr(); // TODO
323+
s.doesApproximation("arcp", val);
325324
}
326325
if (fmath.flags & FastMathFlags::Contract) {
327-
s.useUnsupported("contract");
328-
non_poison &= expr(); // TODO
326+
s.doesApproximation("contract", val);
329327
}
330328
if (fmath.flags & FastMathFlags::Reassoc) {
331-
s.useUnsupported("reassoc");
332-
non_poison &= expr(); // TODO
329+
s.doesApproximation("reassoc", val);
333330
}
334331
if (fmath.flags & FastMathFlags::AFN) {
335-
s.useUnsupported("afn");
336-
non_poison &= expr(); // TODO
332+
s.doesApproximation("afn", val);
337333
}
338334
if (fmath.flags & FastMathFlags::NSZ && !only_input)
339335
val = any_fp_zero(s, move(val));
@@ -606,8 +602,12 @@ StateValue BinOp::toSMT(State &s) const {
606602
case FRem:
607603
fn = [&](auto a, auto ap, auto b, auto bp) -> StateValue {
608604
// TODO; Z3 has no support for LLVM's frem which is actually an fmod
609-
s.useUnsupported("frem");
610-
return fm_poison(s, a, ap, b, bp, [](expr &a, expr &b) { return expr(); },
605+
return fm_poison(s, a, ap, b, bp,
606+
[&](expr &a, expr &b) {
607+
auto val = expr::mkUF("fmod", {a, b}, a);
608+
s.doesApproximation("frem", val);
609+
return val;
610+
},
611611
fmath, false);
612612
};
613613
break;
@@ -1285,8 +1285,9 @@ StateValue ConversionOp::toSMT(State &s) const {
12851285
break;
12861286
case Int2Ptr:
12871287
fn = [&](auto &&val, auto &to_type) -> StateValue {
1288-
s.useUnsupported("inttoptr");
1289-
return { s.getMemory().int2ptr(val), true };
1288+
auto ret = s.getMemory().int2ptr(val);
1289+
s.doesApproximation("inttoptr", ret);
1290+
return { move(ret), true };
12901291
};
12911292
break;
12921293
}
@@ -1689,7 +1690,6 @@ static void unpack_inputs(State &s, Value &argv, Type &ty,
16891690
if (ty.isPtrType()) {
16901691
expr np(true);
16911692
Pointer p(s.getMemory(), move(value.value));
1692-
p.stripAttrs();
16931693
if (argflag.has(ParamAttrs::Dereferenceable) ||
16941694
argflag.has(ParamAttrs::ByVal))
16951695
s.addUB(

ir/memory.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1619,7 +1619,8 @@ expr Memory::ptr2int(const expr &ptr) const {
16191619
expr Memory::int2ptr(const expr &val) const {
16201620
assert(!memory_unused());
16211621
// TODO
1622-
return {};
1622+
expr null = Pointer::mkNullPointer(*this).release();
1623+
return expr::mkIf(val == 0, null, expr::mkUF("int2ptr", { val }, null));
16231624
}
16241625

16251626
expr Memory::blockValRefined(const Memory &other, unsigned bid, bool local,

ir/pointer.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -517,11 +517,6 @@ expr Pointer::isReadnone() const {
517517
return p.extract(idx, idx) == 1;
518518
}
519519

520-
void Pointer::stripAttrs() {
521-
p = p.extract(totalBits()-1, bits_for_ptrattrs)
522-
.concat_zeros(bits_for_ptrattrs);
523-
}
524-
525520
Pointer Pointer::mkNullPointer(const Memory &m) {
526521
// Null pointer exists if either source or target uses it.
527522
assert(has_null_block);

ir/pointer.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,6 @@ class Pointer {
113113
smt::expr isReadonly() const;
114114
smt::expr isReadnone() const;
115115

116-
void stripAttrs();
117-
118116
smt::expr refined(const Pointer &other) const;
119117
smt::expr fninputRefined(const Pointer &other, std::set<smt::expr> &undef,
120118
bool is_byval_arg) const;

ir/state.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,7 @@ expr State::strip_undef_and_add_ub(const Value &val, const expr &e) {
334334
StateValue* State::no_more_tmp_slots() {
335335
if (i_tmp_values < tmp_values.size())
336336
return nullptr;
337-
useUnsupported("Too many temporaries");
338-
return &null_sv;
337+
throw AliveException("Too many temporaries", false);
339338
}
340339

341340
const StateValue& State::operator[](const Value &val) {
@@ -838,12 +837,8 @@ State::addFnCall(const string &name, vector<StateValue> &&inputs,
838837
return retval;
839838
}
840839

841-
void State::useUnsupported(const char *name) {
842-
used_unsupported.emplace(name);
843-
}
844-
845-
void State::doesApproximation(string &&name) {
846-
used_approximations.emplace(move(name));
840+
void State::doesApproximation(string &&name, optional<expr> e) {
841+
used_approximations.emplace(move(name), move(e));
847842
}
848843

849844
void State::addQuantVar(const expr &var) {

ir/state.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,7 @@ class State {
9494
smt::AndExpr precondition;
9595
smt::AndExpr axioms;
9696

97-
std::set<const char*> used_unsupported;
98-
std::set<std::string> used_approximations;
97+
std::set<std::pair<std::string,std::optional<smt::expr>>> used_approximations;
9998

10099
std::set<smt::expr> quantified_vars;
101100

@@ -119,7 +118,6 @@ class State {
119118
std::set<smt::expr> undef_vars;
120119
ValueAnalysis analysis;
121120
std::array<StateValue, 64> tmp_values;
122-
StateValue null_sv;
123121
unsigned i_tmp_values = 0; // next available position in tmp_values
124122

125123
StateValue* no_more_tmp_slots();
@@ -206,10 +204,7 @@ class State {
206204

207205
auto& getVarArgsData() { return var_args_data.data; }
208206

209-
void useUnsupported(const char *name);
210-
auto& getUnsupported() const { return used_unsupported; }
211-
212-
void doesApproximation(std::string &&name);
207+
void doesApproximation(std::string &&name, std::optional<smt::expr> e = {});
213208
auto& getApproximations() const { return used_approximations; }
214209

215210
void addQuantVar(const smt::expr &var);

tools/transform.cpp

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -111,20 +111,6 @@ static void error(Errors &errs, State &src_state, State &tgt_state,
111111

112112
if (r.isInvalid()) {
113113
errs.add("Invalid expr", false);
114-
auto unsupported = src_state.getUnsupported();
115-
auto &u_tgt = tgt_state.getUnsupported();
116-
unsupported.insert(u_tgt.begin(), u_tgt.end());
117-
if (!unsupported.empty()) {
118-
string str = "The program uses the following unsupported features: ";
119-
bool first = true;
120-
for (auto name : unsupported) {
121-
if (!first)
122-
str += ", ";
123-
str += name;
124-
first = false;
125-
}
126-
errs.add(move(str), false);
127-
}
128114
return;
129115
}
130116

@@ -148,20 +134,39 @@ static void error(Errors &errs, State &src_state, State &tgt_state,
148134
auto &var_name = var ? var->getName() : empty;
149135
auto &m = r.getModel();
150136

151-
auto &src_approx = src_state.getApproximations();
152-
auto &tgt_approx = tgt_state.getApproximations();
153-
if (!src_approx.empty() || !tgt_approx.empty()) {
154-
s << "Couldn't prove the correctness of the transformation\n"
155-
"Alive2 approximated the semantics of the programs and therefore we\n"
156-
"cannot conclude whether the bug found is valid or not.\n\n"
157-
"Approximations done:\n";
137+
{
138+
auto &src_approx = src_state.getApproximations();
139+
auto &tgt_approx = tgt_state.getApproximations();
158140
auto approx = src_approx;
159141
approx.insert(tgt_approx.begin(), tgt_approx.end());
160-
for (auto &a : approx) {
161-
s << " - " << a << '\n';
142+
143+
// filter out approximations that don't contribute to the bug
144+
// i.e., they don't show up in the SMT model
145+
for (auto I = approx.begin(); I != approx.end(); ) {
146+
if (!I->second) {
147+
++I;
148+
continue;
149+
}
150+
151+
auto &var = *I->second;
152+
if (m.eval(var).isConst()) {
153+
++I;
154+
} else {
155+
I = approx.erase(I);
156+
}
157+
}
158+
159+
if (!approx.empty()) {
160+
s << "Couldn't prove the correctness of the transformation\n"
161+
"Alive2 approximated the semantics of the programs and therefore we\n"
162+
"cannot conclude whether the bug found is valid or not.\n\n"
163+
"Approximations done:\n";
164+
for (auto &[msg, var] : approx) {
165+
s << " - " << msg << '\n';
166+
}
167+
errs.add(s.str(), false);
168+
return;
162169
}
163-
errs.add(s.str(), false);
164-
return;
165170
}
166171

167172
s << msg;
@@ -841,7 +846,7 @@ static void calculateAndInitConstants(Transform &t) {
841846
// check if null block is needed
842847
// Global variables cannot be null pointers
843848
has_null_block = num_ptrinputs > 0 || nullptr_is_used || has_malloc ||
844-
has_ptr_load || has_fncall;
849+
has_ptr_load || has_fncall || has_int2ptr;
845850

846851
num_nonlocals_src = num_globals_src + num_ptrinputs + num_nonlocals_inst_src +
847852
has_null_block;

0 commit comments

Comments
 (0)