BlockSummary* BlockSummary::Read(Buffer *buf) { BlockSummary *res = NULL; Try(ReadOpenTag(buf, TAG_BlockSummary)); while (!ReadCloseTag(buf, TAG_BlockSummary)) { switch (PeekOpenTag(buf)) { case TAG_BlockId: { Try(!res); BlockId *id = BlockId::Read(buf); res = Make(id); // we don't need to unpersist or drop the data we will be reading in. // if there is already a summary structure created, the adds we make // will just be ignored. break; } case TAG_SummaryAssert: { Try(res); uint32_t kind, cls; PPoint point; Try(ReadOpenTag(buf, TAG_SummaryAssert)); Try(ReadTagUInt32(buf, TAG_Kind, &kind)); Try(ReadTagUInt32(buf, TAG_OpCode, &cls)); Try(ReadTagUInt32(buf, TAG_Index, &point)); Bit *bit = Bit::Read(buf); Try(ReadCloseTag(buf, TAG_SummaryAssert)); res->AddAssert((AssertKind)kind, (AssertClass)cls, point, bit); break; } case TAG_SummaryAssume: { Try(res); Try(ReadOpenTag(buf, TAG_SummaryAssume)); Bit *bit = Bit::Read(buf); Try(ReadCloseTag(buf, TAG_SummaryAssume)); res->AddAssume(bit); break; } default: Try(false); } } Try(res); return res; }
void InferSummaries(const Vector<BlockSummary*> &summary_list) { static BaseTimer infer_timer("infer_summaries"); Timer _timer(&infer_timer); if (summary_list.Empty()) return; Variable *function = summary_list[0]->GetId()->BaseVar(); Vector<BlockCFG*> *annot_list = BodyAnnotCache.Lookup(function->GetName()); // all traces which might refer to the result of pointer arithmetic. Vector<Exp*> arithmetic_list; ArithmeticEscape escape(function, arithmetic_list); // initial pass over the CFGs to get traces used in pointer arithmetic. for (size_t ind = 0; ind < summary_list.Size(); ind++) { BlockSummary *sum = summary_list[ind]; BlockCFG *cfg = sum->GetMemory()->GetCFG(); for (size_t eind = 0; eind < cfg->GetEdgeCount(); eind++) { PEdge *edge = cfg->GetEdge(eind); if (PEdgeAssign *assign_edge = edge->IfAssign()) { Exp *left = assign_edge->GetLeftSide(); Exp *right = assign_edge->GetRightSide(); ProcessArithmeticAssign(&escape, cfg->GetId(), left, right); } } } for (size_t ind = 0; ind < summary_list.Size(); ind++) { BlockSummary *sum = summary_list[ind]; BlockMemory *mcfg = sum->GetMemory(); BlockCFG *cfg = mcfg->GetCFG(); // accumulate all the assertions at points in the CFG. Vector<AssertInfo> asserts; // add assertions at function exit for any postconditions. if (cfg->GetId()->Kind() == B_Function) { for (size_t aind = 0; annot_list && aind < annot_list->Size(); aind++) { BlockCFG *annot_cfg = annot_list->At(aind); if (annot_cfg->GetAnnotationKind() != AK_Postcondition) continue; if (Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg)) { AssertInfo info; info.kind = ASK_Annotation; info.cls = ASC_Check; info.point = cfg->GetExitPoint(); info.bit = bit; asserts.PushBack(info); } } } // add assertions for any point annotations within the CFG. for (size_t pind = 0; pind < cfg->GetPointAnnotationCount(); pind++) { PointAnnotation pann = cfg->GetPointAnnotation(pind); BlockCFG *annot_cfg = GetAnnotationCFG(pann.annot); if (!annot_cfg) continue; if (annot_cfg->GetAnnotationKind() != AK_Assert) continue; if (Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg)) { AssertInfo info; info.kind = ASK_Annotation; info.cls = ASC_Check; info.point = pann.point; info.bit = bit; asserts.PushBack(info); } } for (size_t eind = 0; eind < cfg->GetEdgeCount(); eind++) { PEdge *edge = cfg->GetEdge(eind); PPoint point = edge->GetSource(); if (PEdgeAnnotation *nedge = edge->IfAnnotation()) { // add an assertion for this annotation if it not an assume. BlockCFG *annot_cfg = GetAnnotationCFG(nedge->GetAnnotationId()); if (!annot_cfg) continue; if (annot_cfg->GetAnnotationKind() != AK_Assert && annot_cfg->GetAnnotationKind() != AK_AssertRuntime) { continue; } if (Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg)) { AssertInfo info; info.kind = (annot_cfg->GetAnnotationKind() == AK_Assert) ? ASK_Annotation : ASK_AnnotationRuntime; info.cls = ASC_Check; info.point = point; info.bit = bit; asserts.PushBack(info); } } // add assertions for any invariants affected by a write. Exp *left = NULL; if (PEdgeAssign *nedge = edge->IfAssign()) left = nedge->GetLeftSide(); if (PEdgeCall *nedge = edge->IfCall()) left = nedge->GetReturnValue(); // for now our detection of affected invariants is pretty crude; // writes to fields can affect type invariants on the field's type // which use that field, and writes to global variables can affect // invariants on that global. TODO: pin this down once we draw a // precise line between which invariants can and can't be checked. if (left && left->IsFld()) { ExpFld *nleft = left->AsFld(); String *csu_name = nleft->GetField()->GetCSUType()->GetCSUName(); Vector<BlockCFG*> *comp_annot_list = CompAnnotCache.Lookup(csu_name); for (size_t aind = 0; comp_annot_list && aind < comp_annot_list->Size(); aind++) { BlockCFG *annot_cfg = comp_annot_list->At(aind); if (annot_cfg->GetAnnotationKind() != AK_Invariant) continue; Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg); if (!bit) continue; Vector<Exp*> lval_list; LvalListVisitor visitor(&lval_list); bit->DoVisit(&visitor); bool uses_field = false; for (size_t ind = 0; ind < lval_list.Size(); ind++) { if (ExpFld *lval = lval_list[ind]->IfFld()) { if (lval->GetField() == nleft->GetField()) uses_field = true; } } if (uses_field) { // this is a type invariant which uses the field being written // as an lvalue. we need to assert this write preserves // the invariant. BlockId *id = annot_cfg->GetId(); 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); Bit *new_bit = BitReplaceExp(bit, this_drf, nleft->GetTarget()); AssertInfo info; info.kind = ASK_Invariant; info.cls = ASC_Check; info.point = point; info.bit = new_bit; asserts.PushBack(info); } } CompAnnotCache.Release(csu_name); } if (left && left->IsVar()) { Variable *var = left->AsVar()->GetVariable(); if (var->Kind() == VK_Glob) { Vector<BlockCFG*> *glob_annot_list = InitAnnotCache.Lookup(var->GetName()); for (size_t aind = 0; glob_annot_list && aind < glob_annot_list->Size(); aind++) { BlockCFG *annot_cfg = glob_annot_list->At(aind); Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg); if (!bit) continue; AssertInfo info; info.kind = ASK_Invariant; info.cls = ASC_Check; info.point = point; info.bit = bit; asserts.PushBack(info); } InitAnnotCache.Release(var->GetName()); } } if (PEdgeCall *nedge = edge->IfCall()) { // add assertions for any callee preconditions. // pull preconditions from both direct and indirect calls. Vector<Variable*> callee_names; if (Variable *callee = nedge->GetDirectFunction()) { callee_names.PushBack(callee); } else { CallEdgeSet *callees = CalleeCache.Lookup(function); if (callees) { for (size_t cind = 0; cind < callees->GetEdgeCount(); cind++) { const CallEdge &edge = callees->GetEdge(cind); if (edge.where.id == cfg->GetId() && edge.where.point == point) callee_names.PushBack(edge.callee); } } // CalleeCache release is below. } for (size_t cind = 0; cind < callee_names.Size(); cind++) { String *callee = callee_names[cind]->GetName(); Vector<BlockCFG*> *call_annot_list = BodyAnnotCache.Lookup(callee); for (size_t aind = 0; call_annot_list && aind < call_annot_list->Size(); aind++) { BlockCFG *annot_cfg = call_annot_list->At(aind); if (annot_cfg->GetAnnotationKind() != AK_Precondition) continue; if (Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg)) { ConvertCallsiteMapper mapper(cfg, point, false); Bit *caller_bit = bit->DoMap(&mapper); if (!caller_bit) continue; AssertInfo info; info.kind = ASK_Annotation; info.cls = ASC_Check; info.point = point; info.bit = caller_bit; asserts.PushBack(info); } } BodyAnnotCache.Release(callee); } if (!nedge->GetDirectFunction()) CalleeCache.Release(function); } BufferScanVisitor write_visitor(asserts, arithmetic_list, point, true); BufferScanVisitor read_visitor(asserts, arithmetic_list, point, false); IntegerScanVisitor integer_visitor(asserts, point); GCScanVisitor gcsafe_visitor(asserts, point); // only look at the written lvalues for the write visitor. if (PEdgeAssign *assign = edge->IfAssign()) write_visitor.Visit(assign->GetLeftSide()); if (PEdgeCall *call = edge->IfCall()) { if (Exp *returned = call->GetReturnValue()) write_visitor.Visit(returned); } edge->DoVisit(&read_visitor); // disable integer overflow visitor for now. // edge->DoVisit(&integer_visitor); edge->DoVisit(&gcsafe_visitor); } if (cfg->GetId()->Kind() == B_Function) { BlockModset *modset = GetBlockModset(cfg->GetId()); if (modset->CanGC()) { AssertInfo info; info.kind = ASK_CanGC; info.cls = ASC_Check; info.point = cfg->GetExitPoint(); String *name = cfg->GetId()->BaseVar()->GetName(); Variable *var = Variable::Make(NULL, VK_Glob, name, 0, name); Exp *varexp = Exp::MakeVar(var); Exp *gcsafe = Exp::MakeGCSafe(varexp, false); info.bit = Bit::MakeVar(gcsafe); asserts.PushBack(info); } } MarkRedundantAssertions(mcfg, asserts); // move the finished assertion list into the summary. for (size_t ind = 0; ind < asserts.Size(); ind++) { const AssertInfo &info = asserts[ind]; sum->AddAssert(info.kind, info.cls, info.point, info.bit); } } // infer delta and termination invariants for all summaries. for (size_t ind = 0; ind < summary_list.Size(); ind++) InferInvariants(summary_list[ind], arithmetic_list); BodyAnnotCache.Release(function->GetName()); }