// read a binary tag value from the specified buffer and get whatever // hash object it represents from the buffer, returning a reference // on that object. we will just match against the types of values that // can appear at the top level of a database entry. HashObject* ReadSingleValue(Buffer *buf) { switch (PeekOpenTag(buf)) { case TAG_BlockCFG: return BlockCFG::Read(buf); case TAG_CompositeCSU: return CompositeCSU::Read(buf); case TAG_EscapeEdgeSet: return EscapeEdgeSet::Read(buf); case TAG_EscapeAccessSet: return EscapeAccessSet::Read(buf); case TAG_CallEdgeSet: return CallEdgeSet::Read(buf); case TAG_BlockModset: return BlockModset::Read(buf); case TAG_BlockSummary: return BlockSummary::Read(buf); // special case: get the CFG too. case TAG_BlockMemory: { BlockMemory *mcfg = BlockMemory::Read(buf); BlockCFG *cfg = GetBlockCFG(mcfg->GetId()); if (cfg) mcfg->SetCFG(cfg); return mcfg; } default: logout << "ERROR: Unknown top-level tag in entry: " << PeekOpenTag(buf) << endl; Assert(false); } }
// returns whether the error condition is satisfiable within frame. bool TestErrorSatisfiable(CheckerState *state, CheckerFrame *frame, Bit *bit) { BlockMemory *mcfg = frame->Memory(); Solver *solver = state->GetSolver(); if (!solver->IsSatisfiable()) { if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": Guard unsatisfiable: " << bit << " [" << bit->Hash() << "]" << endl; return false; } state->PushContext(); state->AssertBaseBits(); if (!solver->IsSatisfiable()) { if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": Error unsatisfiable: " << bit << " [" << bit->Hash() << "]" << endl; state->PopContext(); return false; } if (!frame->m_checked_assertions) { frame->m_checked_assertions = true; // check to see if the error is contradicted by previous assertions // in this frame. assert the previous assertions, but don't keep // them around past this function to avoid polluting the solver // with worthless extra checks. BlockSummary *sum = GetBlockSummary(mcfg->GetId()); const Vector<AssertInfo> *asserts = sum->GetAsserts(); size_t assert_count = VectorSize<AssertInfo>(asserts); for (size_t ind = 0; ind < assert_count; ind++) { const AssertInfo &info = asserts->At(ind); // only use the same kind of assertion to check for redundancy. if (info.kind != state->GetAssertKind()) continue; if (info.cls != ASC_Check) continue; if (info.point < frame->EndPoint()) { // get the asserted condition relative to block entry. Bit *assert_value; mcfg->TranslateBit(TRK_Point, info.point, info.bit, &assert_value); assert_value->MoveRef(&assert_value, NULL); Bit *point_guard = mcfg->GetGuard(info.point); point_guard->IncRef(); Bit *imply_assert = Bit::MakeImply(point_guard, assert_value); solver->AddConstraint(frame->Id(), imply_assert); } } sum->DecRef(); if (!solver->IsSatisfiable()) { if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": Unsatisfiable from assertions" << endl; state->PopContext(); return false; } } state->PopContext(); return true; }
void MultiMap(Exp *exp, Vector<Exp*> *res) { // follow possible equalities for lvalues and non-arithmetic binops // appearing in the input formula. bool handle_exp = false; if (exp->IsLvalue() || exp->IsBound() || exp->IsTerminate()) handle_exp = true; else if (ExpBinop *nexp = exp->IfBinop()) { switch (nexp->GetBinopKind()) { case B_Mod: case B_BitwiseAnd: case B_BitwiseOr: case B_BitwiseXOr: case B_Min: case B_Max: handle_exp = true; default: break; } } /* // special cased constant substitution. if we see an 'n < val' // or 'n+1 <= val' and a comparison 'n+1 ~ oval', try substituting // 'oval <= val'. if (ExpBinop *nexp = exp->IfBinop()) { long left_value, right_value; BinopKind kind = nexp->GetBinopKind(); Exp *left = nexp->GetLeftOperand(); Exp *right = nexp->GetRightOperand(); if ((kind == B_LessThan || kind == B_LessEqual) && left->IsInt() && left->AsInt()->GetInt(&left_value)) { for (size_t ind = 0; ind < equalities.Size(); ind++) { const BaseCompare &equality = equalities[ind]; if (equality.target->IsInt() && equality.target->AsInt()->GetInt(&right_value) && right_value == left_value + (kind == B_LessThan ? 1 : 0)) { Exp *new_exp = Exp::MakeBinop(B_LessEqual, equality.source, right); ExpAddResult(new_exp, res); } } } } */ if (!handle_exp) { ExpAddResult(exp, res); return; } bool is_loop = (mcfg->GetId()->Kind() == B_Loop); // for loops, only follow equalities for terms which change with // each iteration. if (is_loop && mcfg->IsExpPreserved(exp)) { ExpAddResult(exp, res); return; } ExpAddResult(exp, res); // try to substitute the expression for anything it might share // an ==/<=/>= relationship with. for (size_t ind = 0; ind < equalities.Size(); ind++) { const BaseCompare &equality = equalities[ind]; // watch for recursion when following compares. if (expand_stack.Contains(equality.test)) continue; // check if there is a match between the exp and equality source. Exp *new_target = MatchEquality(exp, equality); if (new_target) { // keep track of the tests we use during recursive mapping. expand_stack.PushBack(equality.test); // list to hold result of mapping this substitution. Vector<Exp*> sub_res; EqualityMapper sub_mapper(mcfg, verbose, equalities, expand_stack); new_target->DoMultiMap(&sub_mapper, &sub_res); expand_stack.PopBack(); // for functions, filter out substitutions which resulted in an // increase in the number of leaf terms in the expression. this both // gets rid of results we don't care about and prevents exponential // blowup. we don't need to worry about this for loops because // we only follow substitutions for values which change in each // iteration, a similar (and less crude) filtering. size_t base_term_count = exp->TermCount(); if (verbose) logout << "SUFFICIENT: Substituted: " << exp << " [" << sub_res.Size() << "]" << endl; for (size_t rind = 0; rind < sub_res.Size(); rind++) { Exp *res_exp = sub_res[rind]; if (is_loop || res_exp->TermCount() <= base_term_count) { if (verbose) logout << " Added: " << res_exp << endl; ExpAddResult(res_exp, res); } else { if (verbose) logout << " Dropped: " << res_exp << endl; } } } } }