Example #1
0
        public InductiveSequentialization(CivlTypeChecker civlTypeChecker, AtomicAction inputAction, AtomicAction outputAction,
                                          AtomicAction invariantAction, Dictionary <AtomicAction, AtomicAction> elim)
        {
            this.civlTypeChecker = civlTypeChecker;
            this.inputAction     = inputAction;
            this.outputAction    = outputAction;
            this.invariantAction = invariantAction;
            this.elim            = elim;

            // TODO: check frame computation
            // We could compute a tighter frame per check. For example, base/conclusion checkers
            // don't have to take the eliminated actions into account.
            var frameVars = new List <AtomicAction> {
                invariantAction, outputAction, inputAction
            }
            .Union(elim.Select(kv => kv.Value))
            .SelectMany(a => a.gateUsedGlobalVars.Union(a.modifiedGlobalVars)).Distinct();

            this.frame    = new HashSet <Variable>(frameVars);
            this.modifies = frame.Select(Expr.Ident).ToList();

            newPAs = Expr.Ident(civlTypeChecker.LocalVariable("newPAs", civlTypeChecker.pendingAsyncMultisetType));
            if (HasChoice)
            {
                choice = Expr.Ident(invariantAction.impl.OutParams.Last());
            }
            else
            {
                choice = Expr.Ident(civlTypeChecker.LocalVariable("choice", civlTypeChecker.pendingAsyncType));
            }
        }
 private LocalVariable OldGlobalLocal(Variable v)
 {
     return(civlTypeChecker.LocalVariable($"global_old_{v.Name}", v.TypedIdent.Type));
 }
Example #3
0
 private static LocalVariable OldGlobalLocal(CivlTypeChecker civlTypeChecker, Variable v)
 {
     return(civlTypeChecker.LocalVariable($"old_{v.Name}", v.TypedIdent.Type));
 }
Example #4
0
        public ActionRefinementInstrumentation(
            CivlTypeChecker civlTypeChecker,
            Implementation impl,
            Implementation originalImpl,
            Dictionary <Variable, Variable> oldGlobalMap)
        {
            this.civlTypeChecker = civlTypeChecker;
            this.tok             = impl.tok;
            this.oldGlobalMap    = new Dictionary <Variable, Variable>();
            ActionProc actionProc = civlTypeChecker.procToYieldingProc[originalImpl.Proc] as ActionProc;

            this.layerNum = actionProc.upperLayer;
            foreach (Variable v in civlTypeChecker.GlobalVariables)
            {
                var layerRange = civlTypeChecker.GlobalVariableLayerRange(v);
                if (layerRange.lowerLayerNum <= layerNum && layerNum < layerRange.upperLayerNum)
                {
                    this.oldGlobalMap[v] = oldGlobalMap[v];
                }
            }

            this.newLocalVars = new List <Variable>();
            pc = civlTypeChecker.LocalVariable("pc", Type.Bool);
            newLocalVars.Add(pc);
            ok = civlTypeChecker.LocalVariable("ok", Type.Bool);
            newLocalVars.Add(ok);

            this.transitionRelationCache = new Dictionary <AtomicAction, Expr>();

            oldOutputMap = new Dictionary <Variable, Variable>();
            foreach (Variable f in impl.OutParams)
            {
                LocalVariable copy = Old(f);
                newLocalVars.Add(copy);
                oldOutputMap[f] = copy;
            }

            Dictionary <Variable, Expr> foroldMap = new Dictionary <Variable, Expr>();

            foreach (Variable g in civlTypeChecker.GlobalVariables)
            {
                foroldMap[g] = Expr.Ident(oldGlobalMap[g]);
            }

            // The parameters of an atomic action come from the implementation that denotes the atomic action specification.
            // To use the transition relation computed below in the context of the yielding procedure of the refinement check,
            // we need to substitute the parameters.
            AtomicAction   atomicAction           = actionProc.refinedAction;
            Implementation atomicActionImpl       = atomicAction.impl;
            Dictionary <Variable, Expr> alwaysMap = new Dictionary <Variable, Expr>();

            for (int i = 0, j = 0; i < impl.InParams.Count; i++)
            {
                if (civlTypeChecker.FormalRemainsInAction(actionProc, actionProc.proc.InParams[i]))
                {
                    alwaysMap[atomicActionImpl.InParams[j]] = Expr.Ident(impl.InParams[i]);
                    j++;
                }
            }

            for (int i = 0, j = 0; i < impl.OutParams.Count; i++)
            {
                if (civlTypeChecker.FormalRemainsInAction(actionProc, actionProc.proc.OutParams[i]))
                {
                    alwaysMap[atomicActionImpl.OutParams[j]] = Expr.Ident(impl.OutParams[i]);
                    j++;
                }
            }

            if (atomicAction.HasPendingAsyncs)
            {
                Variable collectedPAs = civlTypeChecker.implToPendingAsyncCollector[originalImpl];
                alwaysMap[atomicActionImpl.OutParams.Last()] = Expr.Ident(collectedPAs);
                LocalVariable copy = Old(collectedPAs);
                newLocalVars.Add(copy);
                oldOutputMap[collectedPAs] = copy;
            }

            Substitution always = Substituter.SubstitutionFromHashtable(alwaysMap);
            Substitution forold = Substituter.SubstitutionFromHashtable(foroldMap);
            Expr         transitionRelationExpr = GetTransitionRelation(atomicAction);

            transitionRelation = Substituter.ApplyReplacingOldExprs(always, forold, transitionRelationExpr);
            Expr gateExpr = Expr.And(atomicAction.gate.Select(g => g.Expr));

            gateExpr.Type = Type.Bool;
            gate          = Substituter.Apply(always, gateExpr);
        }
Example #5
0
    private static void AddChecker(CivlTypeChecker civlTypeChecker, Action action, List<Declaration> decls)
    {
      var linearTypeChecker = civlTypeChecker.linearTypeChecker;
      // Note: The implementation should be used as the variables in the
      //       gate are bound to implementation and not to the procedure.
      Implementation impl = action.impl;
      List<Variable> inputs = impl.InParams;
      List<Variable> outputs = impl.OutParams;

      List<Variable> locals = new List<Variable>(2);
      var paLocal1 = civlTypeChecker.LocalVariable("pa1", civlTypeChecker.pendingAsyncType);
      var paLocal2 = civlTypeChecker.LocalVariable("pa2", civlTypeChecker.pendingAsyncType);
      var pa1 = Expr.Ident(paLocal1);
      var pa2 = Expr.Ident(paLocal2);
      
      if (civlTypeChecker.pendingAsyncType != null)
      {
        locals.Add(paLocal1);
        locals.Add(paLocal2);
      }

      List<Requires> requires = action.gate.Select(a => new Requires(false, a.Expr)).ToList();
      List<LinearityCheck> linearityChecks = new List<LinearityCheck>();

      foreach (var domain in linearTypeChecker.linearDomains.Values)
      {
        // Linear in vars
        var inVars = inputs.Union(action.modifiedGlobalVars)
          .Where(x => linearTypeChecker.FindDomainName(x) == domain.domainName)
          .Where(x => InKinds.Contains(linearTypeChecker.FindLinearKind(x)))
          .Select(Expr.Ident)
          .ToList();
        
        // Linear out vars
        var outVars = inputs.Union(outputs).Union(action.modifiedGlobalVars)
          .Where(x => linearTypeChecker.FindDomainName(x) == domain.domainName)
          .Where(x => OutKinds.Contains(linearTypeChecker.FindLinearKind(x)))
          .Select(Expr.Ident)
          .ToList();

        // First kind
        // Permissions in linear output variables are a subset of permissions in linear input variables.
        if (outVars.Count > 0)
        {
          linearityChecks.Add(new LinearityCheck(
            null,
            OutPermsSubsetInPerms(domain, inVars, outVars),
            $"Potential linearity violation in outputs for domain {domain.domainName}.",
            "variables"));
        }

        if (action is AtomicAction atomicAction && atomicAction.HasPendingAsyncs)
        {
          var PAs = Expr.Ident(atomicAction.impl.OutParams.Last());
          
          foreach (var pendingAsync in atomicAction.pendingAsyncs)
          {
            var pendingAsyncLinearParams = PendingAsyncLinearParams(linearTypeChecker, domain, pendingAsync, pa1);

            if (pendingAsyncLinearParams.Count == 0) continue;

            // Second kind
            // Permissions in linear output variables + linear inputs of a single pending async
            // are a subset of permissions in linear input variables.
            var exactlyOnePA = Expr.And(
              ExprHelper.FunctionCall(pendingAsync.pendingAsyncCtor.membership, pa1),
              Expr.Eq(Expr.Select(PAs, pa1), Expr.Literal(1)));
            var outSubsetInExpr = OutPermsSubsetInPerms(domain, inVars, pendingAsyncLinearParams.Union(outVars));
            linearityChecks.Add(new LinearityCheck(
              exactlyOnePA,
              outSubsetInExpr,
              $"Potential linearity violation in outputs and pending async of {pendingAsync.proc.Name} for domain {domain.domainName}.",
              $"single_{pendingAsync.proc.Name}"));

            // Third kind
            // If there are two identical pending asyncs, then their input permissions mut be empty.
            var twoIdenticalPAs = Expr.And(
              ExprHelper.FunctionCall(pendingAsync.pendingAsyncCtor.membership, pa1),
              Expr.Ge(Expr.Select(PAs, pa1), Expr.Literal(2)));
            var emptyPerms = OutPermsSubsetInPerms(domain, Enumerable.Empty<Expr>(), pendingAsyncLinearParams);
            linearityChecks.Add(new LinearityCheck(
              twoIdenticalPAs,
              emptyPerms,
              $"Potential linearity violation in identical pending asyncs of {pendingAsync.proc.Name} for domain {domain.domainName}.",
              $"identical_{pendingAsync.proc.Name}"));
          }

          var pendingAsyncs = atomicAction.pendingAsyncs.ToList();
          for (int i = 0; i < pendingAsyncs.Count; i++)
          {
            var pendingAsync1 = pendingAsyncs[i];
            for (int j = i; j < pendingAsyncs.Count; j++)
            {
              var pendingAsync2 = pendingAsyncs[j];

              var pendingAsyncLinearParams1 = PendingAsyncLinearParams(linearTypeChecker, domain, pendingAsync1, pa1);
              var pendingAsyncLinearParams2 = PendingAsyncLinearParams(linearTypeChecker, domain, pendingAsync2, pa2);
              
              if (pendingAsyncLinearParams1.Count == 0 || pendingAsyncLinearParams2.Count == 0) continue;

              // Fourth kind
              // Input permissions of two non-identical pending asyncs (possibly of the same action)
              // are a subset of permissions in linear input variables.
              var membership = Expr.And(
                Expr.Neq(pa1, pa2),
                Expr.And(
                  ExprHelper.FunctionCall(pendingAsync1.pendingAsyncCtor.membership, pa1),
                  ExprHelper.FunctionCall(pendingAsync2.pendingAsyncCtor.membership, pa2)));

              var existing = Expr.And(
                Expr.Ge(Expr.Select(PAs, pa1), Expr.Literal(1)),
                Expr.Ge(Expr.Select(PAs, pa2), Expr.Literal(1)));

              var noDuplication = OutPermsSubsetInPerms(domain, inVars, pendingAsyncLinearParams1.Union(pendingAsyncLinearParams2));

              linearityChecks.Add(new LinearityCheck(
                Expr.And(membership, existing),
                noDuplication,
                $"Potential lnearity violation in pending asyncs of {pendingAsync1.proc.Name} and {pendingAsync2.proc.Name} for domain {domain.domainName}.",
                $"distinct_{pendingAsync1.proc.Name}_{pendingAsync2.proc.Name}"));
            }
          }
        }
      }

      if (linearityChecks.Count == 0) return;

      // Create checker blocks
      List<Block> checkerBlocks = new List<Block>(linearityChecks.Count);
      foreach (var lc in linearityChecks)
      {
        List<Cmd> cmds = new List<Cmd>(2);
        if (lc.assume != null)
        {
          cmds.Add(CmdHelper.AssumeCmd(lc.assume));
        }
        cmds.Add(new AssertCmd(action.proc.tok, lc.assert) { ErrorData = lc.message });
        var block = new Block(Token.NoToken, lc.name, cmds, CmdHelper.ReturnCmd);
        CivlUtil.ResolveAndTypecheck(block, ResolutionContext.State.Two);
        checkerBlocks.Add(block);
      }
      
      // Create init blocks
      List<Block> blocks = new List<Block>(linearityChecks.Count + 1);
      blocks.Add(
        new Block(
          Token.NoToken,
          "init",
          new List<Cmd> { CmdHelper.CallCmd(action.proc, inputs, outputs) },
          new GotoCmd(Token.NoToken, checkerBlocks)));
      blocks.AddRange(checkerBlocks);

      // Create the whole check procedure
      string checkerName = civlTypeChecker.AddNamePrefix($"LinearityChecker_{action.proc.Name}");
      Procedure linCheckerProc = new Procedure(Token.NoToken, checkerName, new List<TypeVariable>(),
        inputs, outputs, requires, action.proc.Modifies, new List<Ensures>());
      Implementation linCheckImpl = new Implementation(Token.NoToken, checkerName,
        new List<TypeVariable>(), inputs, outputs, locals, blocks);
      linCheckImpl.Proc = linCheckerProc;
      decls.Add(linCheckImpl);
      decls.Add(linCheckerProc);
    }