void goto_checkt::check_rec( const exprt &expr, guardt &guard, bool address) { // we don't look into quantifiers if(expr.id()==ID_exists || expr.id()==ID_forall) return; if(address) { if(expr.id()==ID_dereference) { assert(expr.operands().size()==1); check_rec(expr.op0(), guard, false); } else if(expr.id()==ID_index) { assert(expr.operands().size()==2); check_rec(expr.op0(), guard, true); check_rec(expr.op1(), guard, false); } else { forall_operands(it, expr) check_rec(*it, guard, true); } return; } if(expr.id()==ID_address_of) { assert(expr.operands().size()==1); check_rec(expr.op0(), guard, true); return; } else if(expr.id()==ID_and || expr.id()==ID_or) { if(!expr.is_boolean()) throw "`"+expr.id_string()+"' must be Boolean, but got "+ expr.pretty(); guardt old_guard=guard; for(unsigned i=0; i<expr.operands().size(); i++) { const exprt &op=expr.operands()[i]; if(!op.is_boolean()) throw "`"+expr.id_string()+"' takes Boolean operands only, but got "+ op.pretty(); check_rec(op, guard, false); if(expr.id()==ID_or) guard.add(not_exprt(op)); else guard.add(op); } guard.swap(old_guard); return; } else if(expr.id()==ID_if) { if(expr.operands().size()!=3) throw "if takes three arguments"; if(!expr.op0().is_boolean()) { std::string msg= "first argument of if must be boolean, but got " +expr.op0().pretty(); throw msg; } check_rec(expr.op0(), guard, false); { guardt old_guard=guard; guard.add(expr.op0()); check_rec(expr.op1(), guard, false); guard.swap(old_guard); } { guardt old_guard=guard; guard.add(not_exprt(expr.op0())); check_rec(expr.op2(), guard, false); guard.swap(old_guard); } return; } forall_operands(it, expr) check_rec(*it, guard, false); if(expr.id()==ID_index) { bounds_check(to_index_expr(expr), guard); } else if(expr.id()==ID_div) { div_by_zero_check(to_div_expr(expr), guard); if(expr.type().id()==ID_signedbv) integer_overflow_check(expr, guard); else if(expr.type().id()==ID_floatbv) { nan_check(expr, guard); float_overflow_check(expr, guard); } } else if(expr.id()==ID_shl || expr.id()==ID_ashr || expr.id()==ID_lshr) { undefined_shift_check(to_shift_expr(expr), guard); } else if(expr.id()==ID_mod) { mod_by_zero_check(to_mod_expr(expr), guard); } else if(expr.id()==ID_plus || expr.id()==ID_minus || expr.id()==ID_mult || expr.id()==ID_unary_minus) { if(expr.type().id()==ID_signedbv || expr.type().id()==ID_unsignedbv) { if(expr.operands().size()==2 && expr.op0().type().id()==ID_pointer) pointer_overflow_check(expr, guard); else integer_overflow_check(expr, guard); } else if(expr.type().id()==ID_floatbv) { nan_check(expr, guard); float_overflow_check(expr, guard); } else if(expr.type().id()==ID_pointer) { pointer_overflow_check(expr, guard); } } else if(expr.id()==ID_typecast) conversion_check(expr, guard); else if(expr.id()==ID_le || expr.id()==ID_lt || expr.id()==ID_ge || expr.id()==ID_gt) pointer_rel_check(expr, guard); else if(expr.id()==ID_dereference) pointer_validity_check(to_dereference_expr(expr), guard); }
void goto_checkt::check_rec(const exprt &expr, guardt &guard, bool address) { if (address) { if (expr.id() == "dereference") { assert(expr.operands().size() == 1); check_rec(expr.op0(), guard, false); } else if (expr.id() == "index") { assert(expr.operands().size() == 2); check_rec(expr.op0(), guard, true); check_rec(expr.op1(), guard, false); } else { forall_operands(it, expr) check_rec(*it, guard, true); } return; } if (expr.is_address_of()) { assert(expr.operands().size() == 1); check_rec(expr.op0(), guard, true); return; } else if (expr.is_and() || expr.id() == "or") { if (!expr.is_boolean()) throw expr.id_string() + " must be Boolean, but got " + expr.pretty(); unsigned old_guards = guard.size(); for (unsigned i = 0; i < expr.operands().size(); i++) { const exprt &op = expr.operands()[i]; if (!op.is_boolean()) throw expr.id_string() + " takes Boolean operands only, but got " + op.pretty(); check_rec(op, guard, false); if (expr.id() == "or") { exprt tmp(op); tmp.make_not(); expr2tc tmp_expr; migrate_expr(tmp, tmp_expr); guard.move(tmp_expr); } else { expr2tc tmp; migrate_expr(op, tmp); guard.add(tmp); } } guard.resize(old_guards); return; } else if (expr.id() == "if") { if (expr.operands().size() != 3) throw "if takes three arguments"; if (!expr.op0().is_boolean()) { std::string msg = "first argument of if must be boolean, but got " + expr.op0().to_string(); throw msg; } check_rec(expr.op0(), guard, false); { unsigned old_guard = guard.size(); expr2tc tmp; migrate_expr(expr.op0(), tmp); guard.add(tmp); check_rec(expr.op1(), guard, false); guard.resize(old_guard); } { unsigned old_guard = guard.size(); exprt tmp(expr.op0()); tmp.make_not(); expr2tc tmp_expr; migrate_expr(tmp, tmp_expr); guard.move(tmp_expr); check_rec(expr.op2(), guard, false); guard.resize(old_guard); } return; } forall_operands(it, expr) check_rec(*it, guard, false); if (expr.id() == "index") { bounds_check(expr, guard); } else if (expr.id() == "/") { div_by_zero_check(expr, guard); if (expr.type().id() == "signedbv") { overflow_check(expr, guard); } else if (expr.type().id() == "floatbv") { nan_check(expr, guard); } } else if (expr.id() == "+" || expr.id() == "-" || expr.id() == "*" || expr.id() == "unary-" || expr.id() == "typecast") { if (expr.type().id() == "signedbv") { overflow_check(expr, guard); } else if (expr.type().id() == "floatbv") { nan_check(expr, guard); } } else if (expr.id() == "<=" || expr.id() == "<" || expr.id() == ">=" || expr.id() == ">") { pointer_rel_check(expr, guard); } else if (expr.id() == "mod") { div_by_zero_check(expr, guard); if (expr.type().id() == "signedbv") { overflow_check(expr, guard); } else if (expr.type().id() == "floatbv") { nan_check(expr, guard); } } }