void goto_checkt::undefined_shift_check( const shift_exprt &expr, const guardt &guard) { if(!enable_undefined_shift_check) return; // Undefined for all types and shifts if distance exceeds width, // and also undefined for negative distances. const typet &distance_type= ns.follow(expr.distance().type()); if(distance_type.id()==ID_signedbv) { binary_relation_exprt inequality( expr.distance(), ID_ge, gen_zero(distance_type)); add_guarded_claim( inequality, "shift distance is negative", "undefined-shift", expr.find_source_location(), expr, guard); } const typet &op_type= ns.follow(expr.op().type()); if(op_type.id()==ID_unsignedbv || op_type.id()==ID_signedbv) { exprt width_expr= from_integer(to_bitvector_type(op_type).get_width(), distance_type); if(width_expr.is_nil()) throw "no number for width for operator "+expr.id_string(); binary_relation_exprt inequality( expr.distance(), ID_lt, width_expr); add_guarded_claim( inequality, "shift distance too large", "undefined-shift", expr.find_source_location(), expr, guard); } }
void goto_checkt::mod_by_zero_check( const mod_exprt &expr, const guardt &guard) { if(!enable_div_by_zero_check) return; // add divison by zero subgoal exprt zero=gen_zero(expr.op1().type()); if(zero.is_nil()) throw "no zero of argument type of operator "+expr.id_string(); exprt inequality(ID_notequal, bool_typet()); inequality.copy_to_operands(expr.op1(), zero); add_guarded_claim( inequality, "division by zero", "division-by-zero", expr.find_source_location(), expr, guard); }
void goto_checkt::div_by_zero_check(const exprt &expr, const guardt &guard) { if (options.get_bool_option("no-div-by-zero-check")) return; if (expr.operands().size() != 2) throw expr.id_string() + " takes two arguments"; // add divison by zero subgoal exprt zero = gen_zero(expr.op1().type()); if (zero.is_nil()) throw "no zero of argument type of operator " + expr.id_string(); exprt inequality("notequal", bool_typet()); inequality.copy_to_operands(expr.op1(), zero); add_guarded_claim(inequality, "division by zero", "division-by-zero", expr.find_location(), guard); }
void goto_checkt::bounds_check( const index_exprt &expr, const guardt &guard) { if(!enable_bounds_check) return; if(expr.find("bounds_check").is_not_nil() && !expr.get_bool("bounds_check")) return; typet array_type=ns.follow(expr.array().type()); if(array_type.id()==ID_pointer) return; // done by the pointer code else if(array_type.id()==ID_incomplete_array) throw "index got incomplete array"; else if(array_type.id()!=ID_array && array_type.id()!=ID_vector) throw "bounds check expected array or vector type, got " +array_type.id_string(); std::string name=array_name(expr.array()); const exprt &index=expr.index(); object_descriptor_exprt ode; ode.build(expr, ns); if(index.type().id()!=ID_unsignedbv) { // we undo typecasts to signedbv if(index.id()==ID_typecast && index.operands().size()==1 && index.op0().type().id()==ID_unsignedbv) { // ok } else { mp_integer i; if(!to_integer(index, i) && i>=0) { // ok } else { exprt effective_offset=ode.offset(); if(ode.root_object().id()==ID_dereference) { exprt p_offset=pointer_offset( to_dereference_expr(ode.root_object()).pointer()); assert(p_offset.type()==effective_offset.type()); effective_offset=plus_exprt(p_offset, effective_offset); } exprt zero=gen_zero(ode.offset().type()); assert(zero.is_not_nil()); // the final offset must not be negative binary_relation_exprt inequality(effective_offset, ID_ge, zero); add_guarded_claim( inequality, name+" lower bound", "array bounds", expr.find_source_location(), expr, guard); } } } if(ode.root_object().id()==ID_dereference) { const exprt &pointer= to_dereference_expr(ode.root_object()).pointer(); if_exprt size( dynamic_object(pointer), typecast_exprt(dynamic_size(ns), object_size(pointer).type()), object_size(pointer)); plus_exprt effective_offset(ode.offset(), pointer_offset(pointer)); assert(effective_offset.op0().type()==effective_offset.op1().type()); assert(effective_offset.type()==size.type()); binary_relation_exprt inequality(effective_offset, ID_lt, size); or_exprt precond( and_exprt( dynamic_object(pointer), not_exprt(malloc_object(pointer, ns))), inequality); add_guarded_claim( precond, name+" upper bound", "array bounds", expr.find_source_location(), expr, guard); return; } const exprt &size=array_type.id()==ID_array ? to_array_type(array_type).size() : to_vector_type(array_type).size(); if(size.is_nil()) { // Linking didn't complete, we don't have a size. // Not clear what to do. } else if(size.id()==ID_infinity) { } else if(size.is_zero() && expr.array().id()==ID_member) { // a variable sized struct member } else { binary_relation_exprt inequality(index, ID_lt, size); // typecast size if(inequality.op1().type()!=inequality.op0().type()) inequality.op1().make_typecast(inequality.op0().type()); // typecast size if(inequality.op1().type()!=inequality.op0().type()) inequality.op1().make_typecast(inequality.op0().type()); add_guarded_claim( inequality, name+" upper bound", "array bounds", expr.find_source_location(), expr, guard); } }
void value_set_dereferencet::bounds_check( const index_exprt &expr, const guardt &guard) { if(!options.get_bool_option("pointer-check")) return; if(!options.get_bool_option("bounds-check")) return; const typet &array_type=ns.follow(expr.op0().type()); if(array_type.id()!=ID_array) throw "bounds check expected array type"; std::string name=array_name(ns, expr.array()); { mp_integer i; if(!to_integer(expr.index(), i) && i>=0) { } else { exprt zero=from_integer(0, expr.index().type()); if(zero.is_nil()) throw "no zero constant of index type "+ expr.index().type().pretty(); binary_relation_exprt inequality(expr.index(), ID_lt, zero); guardt tmp_guard(guard); tmp_guard.add(inequality); dereference_callback.dereference_failure( "array bounds", name+" lower bound", tmp_guard); } } const exprt &size_expr= to_array_type(array_type).size(); if(size_expr.id()==ID_infinity) { } else if(size_expr.is_zero() && expr.array().id()==ID_member) { // this is a variable-sized struct field } else { if(size_expr.is_nil()) throw "index array operand of wrong type"; binary_relation_exprt inequality(expr.index(), ID_ge, size_expr); if(c_implicit_typecast( inequality.op0(), inequality.op1().type(), ns)) throw "index address of wrong type"; guardt tmp_guard(guard); tmp_guard.add(inequality); dereference_callback.dereference_failure( "array bounds", name+" upper bound", tmp_guard); } }
void goto_checkt::bounds_check(const exprt &expr, const guardt &guard) { if (options.get_bool_option("no-bounds-check")) return; if (expr.id() != "index") return; if (expr.operands().size() != 2) throw "index takes two operands"; // Don't bounds check the initial index of argv in the "main" function; it's // always correct, and just adds needless claims. In the past a "no bounds // check" attribute in old irep handled this. if (expr.op0().id_string() == "symbol" && expr.op0().identifier() == "c::argv'" && expr.op1().id_string() == "symbol" && expr.op1().identifier() == "c::argc'") return; if (expr.op0().id_string() == "symbol" && expr.op0().identifier() == "c::envp'" && expr.op1().id_string() == "symbol" && expr.op1().identifier() == "c::envp_size'") return; typet array_type = ns.follow(expr.op0().type()); if (array_type.id() == "pointer") return; // done by the pointer code else if (array_type.id() == "incomplete_array") { std::cerr << expr.pretty() << std::endl; throw "index got incomplete array"; } else if (!array_type.is_array()) throw "bounds check expected array type, got " + array_type.id_string(); // Otherwise, if there's a dereference in the array source, this bounds check // should be performed by the symex-time dereferencing code, as the base thing // being accessed may be anything. if (has_dereference(expr.op0())) return; std::string name = "array bounds violated: " + array_name(expr.op0()); const exprt &index = expr.op1(); if (index.type().id() != "unsignedbv") { // we undo typecasts to signedbv if (index.id() == "typecast" && index.operands().size() == 1 && index.op0().type().id() == "unsignedbv") { // ok } else { mp_integer i; if (!to_integer(index, i) && i >= 0) { // ok } else { exprt zero = gen_zero(index.type()); if (zero.is_nil()) throw "no zero constant of index type " + index.type().to_string(); exprt inequality(">=", bool_typet()); inequality.copy_to_operands(index, zero); add_guarded_claim(inequality, name + " lower bound", "array bounds", expr.find_location(), guard); } } } { if (array_type.size_irep().is_nil()) throw "index array operand of wrong type"; const exprt &size = (const exprt &) array_type.size_irep(); if (size.id() != "infinity") { exprt inequality("<", bool_typet()); inequality.copy_to_operands(index, size); // typecast size if (inequality.op1().type() != inequality.op0().type()) inequality.op1().make_typecast(inequality.op0().type()); add_guarded_claim(inequality, name + " upper bound", "array bounds", expr.find_location(), guard); } } }