void GetMatchingHeapWrites(const EscapeAccess &heap_write, Vector<HeapWriteInfo> *writes) { BlockId *id = heap_write.where.id; BlockMemory *mcfg = GetBlockMemory(id); if (mcfg == NULL) { logout << "WARNING: Missing memory: '" << id << "'" << endl; return; } BlockCFG *cfg = mcfg->GetCFG(); // for incremental analysis, make sure the write CFG uses the right version. // as for checking callers, if the CFG has changed but the new one still // has a matching write, we will see an escape access for the new CFG. if (cfg->GetVersion() != heap_write.where.version) { if (checker_verbose.IsSpecified()) logout << "CHECK: Write is an older version: " << heap_write.where.id << ": " << heap_write.where.version << endl; mcfg->DecRef(); return; } PPoint point = heap_write.where.point; PPoint exit_point = mcfg->GetCFG()->GetExitPoint(); // find a point-relative lvalue written at the write point with // the sanitized representation from the heap_write trace. // TODO: we only match against direct assignments in the CFG for now, // ignoring structural copies (which are simple recursive writes). PEdge *edge = cfg->GetSingleOutgoingEdge(point); Exp *point_lval = NULL; if (PEdgeAssign *nedge = edge->IfAssign()) point_lval = nedge->GetLeftSide(); else if (PEdgeCall *nedge = edge->IfCall()) point_lval = nedge->GetReturnValue(); bool lval_matches = false; if (point_lval) { if (Exp *new_point_lval = Trace::SanitizeExp(point_lval)) { lval_matches = (new_point_lval == heap_write.target->GetValue()); new_point_lval->DecRef(); } } if (!lval_matches) { mcfg->DecRef(); return; } // it would be nice to remove Val() expressions from this list, but we can't // do that as lvalues in memory assignments can contain Val and we want to // see the effects of those assignments. TODO: fix. GuardExpVector lval_res; mcfg->TranslateExp(TRK_Point, point, point_lval, &lval_res); for (size_t ind = 0; ind < lval_res.Size(); ind++) { const GuardExp &lv = lval_res[ind]; HeapWriteInfo info; info.mcfg = mcfg; info.lval = lv.exp; info.base_lval = point_lval; // look for a condition where the lvalue is not written. GuardExpVector exit_vals; info.mcfg->GetValComplete(info.lval, NULL, exit_point, &exit_vals); for (size_t ind = 0; ind < exit_vals.Size(); ind++) { const GuardExp &val = exit_vals[ind]; // exclude cases where the lvalue refers to its value at block entry. if (ExpDrf *nval = val.exp->IfDrf()) { if (nval->GetTarget() == info.lval) info.exclude.PushBack(val.guard); } } if (!writes->Contains(info)) { info.mcfg->IncRef(writes); info.lval->IncRef(writes); info.base_lval->IncRef(writes); IncRefVector<Bit>(info.exclude, writes); writes->PushBack(info); } } mcfg->DecRef(); }
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); } } }