void Visit(Exp *exp) { if (ExpFld *nexp = exp->IfFld()) { // pick up any type invariants from the host type. String *csu_name = nexp->GetField()->GetCSUType()->GetCSUName(); Vector<BlockCFG*> *annot_list = CompAnnotCache.Lookup(csu_name); for (size_t ind = 0; annot_list && ind < annot_list->Size(); ind++) { BlockCFG *annot_cfg = annot_list->At(ind); Assert(annot_cfg->GetAnnotationKind() == AK_Invariant || annot_cfg->GetAnnotationKind() == AK_InvariantAssume); BlockId *id = annot_cfg->GetId(); Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg); if (!bit) continue; // get the *this expression. we'll replace this with the actual CSU // lvalue to get the assumed bit. id->IncRef(); Variable *this_var = Variable::Make(id, VK_This, NULL, 0, NULL); Exp *this_exp = Exp::MakeVar(this_var); Exp *this_drf = Exp::MakeDrf(this_exp); Exp *target = nexp->GetTarget(); GuardExpVector lval_res; if (mcfg) { mcfg->TranslateExp(TRK_Point, point, target, &lval_res); } else { target->IncRef(); lval_res.PushBack(GuardExp(target, Bit::MakeConstant(true))); } for (size_t lind = 0; lind < lval_res.Size(); lind++) { // ignore the guard component of the result here. this means that // accessing a field of a value means related invariants hold for // the value along all paths. which is normally right, except when // the value is the result of a cast, and could have a different type // along other paths. TODO: sort this out. const GuardExp &gs = lval_res[lind]; Bit *new_bit = BitReplaceExp(bit, this_drf, gs.exp); new_bit->MoveRef(NULL, assume_list); annot_cfg->IncRef(assume_list); AssumeInfo info; info.annot = annot_cfg; info.point = 0; info.bit = new_bit; assume_list->PushBack(info); } this_drf->DecRef(); } CompAnnotCache.Release(csu_name); } if (ExpVar *nexp = exp->IfVar()) { if (nexp->GetVariable()->Kind() == VK_Glob) { String *var_name = nexp->GetVariable()->GetName(); Vector<BlockCFG*> *annot_list = InitAnnotCache.Lookup(var_name); for (size_t ind = 0; annot_list && ind < annot_list->Size(); ind++) { BlockCFG *annot_cfg = annot_list->At(ind); Assert(annot_cfg->GetAnnotationKind() == AK_Invariant || annot_cfg->GetAnnotationKind() == AK_InvariantAssume); Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg); if (!bit) continue; bit->IncRef(assume_list); annot_cfg->IncRef(assume_list); AssumeInfo info; info.annot = annot_cfg; info.point = 0; info.bit = bit; assume_list->PushBack(info); } InitAnnotCache.Release(var_name); } } }
void FillBakedSummary(BlockSummary *sum) { Variable *name = sum->GetId()->BaseVar(); // primitive memory allocator. Exp *object; Exp *size; if (GetAllocationFunction(name, &object, &size)) { Exp *bound = GetByteUpperBound(object); // the upper bound is greater or equal to zero. bound->IncRef(); Exp *zero = Exp::MakeInt(0); Bit *bound_nonneg = Exp::MakeCompareBit(B_GreaterEqual, bound, zero); sum->AddAssume(bound_nonneg); // the upper bound of the object is exactly equal to size. Bit *bound_equal = Exp::MakeCompareBit(B_Equal, bound, size); sum->AddAssume(bound_equal); // TODO: it would be nice to assert the offset is exactly equal // to zero for the UI; however, this can lead to spurious contradiction // if unaligned pointers are in use. } // return value bears some relation with an argument. ReturnCompareFunctionInfo *cur_return = g_return_compare_functions; while (cur_return->name) { if (TextNameMatch(name, cur_return->name)) { Exp *ret_exp = GetReturnedValue(); Exp *arg_exp = GetArgumentValue(cur_return->compare_arg); Type *type = NULL; if (IsPointerBinop(cur_return->binop)) type = Type::MakeInt(1, true); Bit *bit = Exp::MakeCompareBit(cur_return->binop, ret_exp, arg_exp, type); sum->AddAssume(bit); } cur_return++; } // return value is NULL terminated. const char **cur_ret_term = g_return_terminated_functions; while (*cur_ret_term) { if (TextNameMatch(name, *cur_ret_term)) { Exp *ret_exp = GetReturnedValue(); Exp *terminate = GetNullTerminate(ret_exp); Exp *zero = Exp::MakeInt(0); Bit *bit = Exp::MakeCompareBit(B_GreaterEqual, terminate, zero); sum->AddAssume(bit); } cur_ret_term++; } // an argument is NULL terminated. TerminateFunctionInfo *cur_term = g_terminate_functions; while (cur_term->name) { if (TextNameMatch(name, cur_term->name) && cur_term->terminates) { Exp *arg_exp = GetArgumentValue(cur_term->terminate_arg); Exp *kind = GetNullTerminate(NULL); Exp *exit_term = Exp::MakeExit(arg_exp, kind); Exp *zero = Exp::MakeInt(0); Bit *bit = Exp::MakeCompareBit(B_GreaterEqual, exit_term, zero); sum->AddAssume(bit); } cur_term++; } // strchr constraint: char_arg != 0 => zterm(ret) > 0. StrchrFunctionInfo *cur_strchr = g_strchr_functions; while (cur_strchr->name) { if (TextNameMatch(name, cur_strchr->name)) { Exp *arg_exp = GetArgumentValue(cur_strchr->char_arg); Exp *ret_exp = GetReturnedValue(); Exp *terminate = GetNullTerminate(ret_exp); Exp *zero = Exp::MakeInt(0); zero->IncRef(); Bit *left = Exp::MakeCompareBit(B_NotEqual, arg_exp, zero); Bit *right = Exp::MakeCompareBit(B_GreaterThan, terminate, zero); Bit *bit = Bit::MakeImply(left, right); sum->AddAssume(bit); } cur_strchr++; } // strlen constraint: ret >= 0 && ret == zterm(arg) StrlenFunctionInfo *cur_strlen = g_strlen_functions; while (cur_strlen->name) { if (TextNameMatch(name, cur_strlen->name)) { Exp *arg_exp = GetArgumentValue(cur_strlen->string_arg); Exp *retval = GetReturnedValue(); Exp *terminate = GetNullTerminate(arg_exp); retval->IncRef(); Exp *zero = Exp::MakeInt(0); Bit *ge_zero = Exp::MakeCompareBit(B_GreaterEqual, retval, zero); sum->AddAssume(ge_zero); Bit *eq_term = Exp::MakeCompareBit(B_Equal, retval, terminate); sum->AddAssume(eq_term); } cur_strlen++; } // strcmp constraint: ret == 0 ==> zterm(arg_one) == zterm(arg_two) StrcmpFunctionInfo *cur_strcmp = g_strcmp_functions; while (cur_strcmp->name) { if (TextNameMatch(name, cur_strcmp->name)) { Exp *arg_one_exp = GetArgumentValue(cur_strcmp->string_arg_one); Exp *arg_two_exp = GetArgumentValue(cur_strcmp->string_arg_two); Exp *retval = GetReturnedValue(); Exp *terminate_one = GetNullTerminate(arg_one_exp); Exp *terminate_two = GetNullTerminate(arg_two_exp); Exp *zero = Exp::MakeInt(0); Bit *left = Exp::MakeCompareBit(B_Equal, retval, zero); Bit *right = Exp::MakeCompareBit(B_Equal, terminate_one, terminate_two); Bit *bit = Bit::MakeImply(left, right); sum->AddAssume(bit); } cur_strcmp++; } // strncmp constraint: ret == 0 ==> (zterm(arg_one) == zterm(arg_two) // || (zterm(arg_one) >= length_arg && // zterm(arg_two) >= length_arg)) StrncmpFunctionInfo *cur_strncmp = g_strncmp_functions; while (cur_strncmp->name) { if (TextNameMatch(name, cur_strncmp->name)) { Exp *arg_one_exp = GetArgumentValue(cur_strncmp->string_arg_one); Exp *arg_two_exp = GetArgumentValue(cur_strncmp->string_arg_two); Exp *length_exp = GetArgumentValue(cur_strncmp->length_arg); Exp *retval = GetReturnedValue(); Exp *terminate_one = GetNullTerminate(arg_one_exp); Exp *terminate_two = GetNullTerminate(arg_two_exp); Exp *zero = Exp::MakeInt(0); terminate_one->IncRef(); terminate_two->IncRef(); length_exp->IncRef(); Bit *left = Exp::MakeCompareBit(B_Equal, retval, zero); Bit *term_eq = Exp::MakeCompareBit(B_Equal, terminate_one, terminate_two); Bit *ge_one = Exp::MakeCompareBit(B_GreaterEqual, terminate_one, length_exp); Bit *ge_two = Exp::MakeCompareBit(B_GreaterEqual, terminate_two, length_exp); Bit *ge_both = Bit::MakeAnd(ge_one, ge_two); Bit *right = Bit::MakeOr(term_eq, ge_both); Bit *bit = Bit::MakeImply(left, right); sum->AddAssume(bit); } cur_strncmp++; } }