// this function generates code for the "state change" private void createCodeStateChange(ref BasicBlock outStateChangeBasicBlock, ref SwitchBranchTarget outStateChangeExitBranch, GraphRandomStateGenerator randomStateGenerator, BasicBlockGraphNodeLink link, LocalDefinition intStateLocal) { // create a basic block to change the current global state BasicBlock stateChangeBasicBlock = new BasicBlock(); stateChangeBasicBlock.startIdx = 0; stateChangeBasicBlock.endIdx = 0; // create graph transformer metadata for the basic block GraphTransformerStateChangeBasicBlock metadataChange = new GraphTransformerStateChangeBasicBlock(); metadataChange.correspondingGraphNodes.Add(link); stateChangeBasicBlock.transformationMetadata.Add(metadataChange); // generate code for setting the new global state List<IOperation> tempOperations = randomStateGenerator.generateCodeSetRandomState(intStateLocal); stateChangeBasicBlock.operations.AddRange(tempOperations); // create switch statement for the "state switch" stateChangeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, intStateLocal)); uint[] switchSize = new uint[this.graph.graphValidPathCount]; stateChangeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Switch, switchSize)); // create exit branch for the new state basic block SwitchBranchTarget stateChangeExitBranch = new SwitchBranchTarget(); stateChangeExitBranch.sourceBasicBlock = stateChangeBasicBlock; stateChangeBasicBlock.exitBranch = stateChangeExitBranch; // create the dead code for this "state switch" BasicBlock deadCodeBasicBlock = new BasicBlock(); deadCodeBasicBlock.startIdx = 0; deadCodeBasicBlock.endIdx = 0; // set the dead code basic block as "not taken" target for the conditional branch of the checking basic block deadCodeBasicBlock.entryBranches.Add(stateChangeExitBranch); stateChangeExitBranch.notTakenTarget = deadCodeBasicBlock; // TODO at the moment always the not taken branch of the switch statement is the dead code basic block // generate dead code for the dead code basic block GraphTransformerDeadCodeBasicBlock deadCodeMetadata = new GraphTransformerDeadCodeBasicBlock(); deadCodeBasicBlock.transformationMetadata.Add(deadCodeMetadata); outStateChangeBasicBlock = stateChangeBasicBlock; outStateChangeExitBranch = stateChangeExitBranch; }
// this function generates code for an opaque predicate that evaluates to "true" // => the "taken" branch of the conditional branch have to be taken for the correct code path private void createCodeTruePredicate(ref BasicBlock outStartBasicBlock, ref ConditionalBranchTarget outConditionalBranch, BasicBlockGraphNodeLink link, LocalDefinition currentNodeLocal) { // create a basic block that checks the opaque predicate (this check evaluates to "true") BasicBlock startBasicBlock = new BasicBlock(); startBasicBlock.startIdx = 0; startBasicBlock.endIdx = 0; // add graph transformer metadata to the basic block GraphTransformerPredicateBasicBlock metadata = new GraphTransformerPredicateBasicBlock(); metadata.predicateType = GraphOpaquePredicate.True; metadata.correspondingGraphNodes.Add(link); startBasicBlock.transformationMetadata.Add(metadata); // search for the valid and invalid interfaces list of the current valid path id List<ITypeReference> validInterfaces = null; List<ITypeReference> invalidInterfaces = null; foreach (PathElement pathElement in link.graphNode.pathElements) { if (pathElement.validPathId == link.validPathId) { validInterfaces = pathElement.validInterfaces; invalidInterfaces = pathElement.invalidInterfaces; } } if (validInterfaces == null || invalidInterfaces == null) { throw new ArgumentException("No valid/invalid interface list was found."); } emitPredicateCode(startBasicBlock, currentNodeLocal, validInterfaces, invalidInterfaces); // create the conditional branch for the checking basic block (taken => correct code; not taken => dead code) ConditionalBranchTarget startBasicBlockExitBranch = new ConditionalBranchTarget(); startBasicBlockExitBranch.sourceBasicBlock = startBasicBlock; startBasicBlock.exitBranch = startBasicBlockExitBranch; // create the dead code for this opaque predicate BasicBlock deadCodeBasicBlock = new BasicBlock(); deadCodeBasicBlock.startIdx = 0; deadCodeBasicBlock.endIdx = 0; // set the dead code basic block as "not taken" target for the conditional branch of the checking basic block deadCodeBasicBlock.entryBranches.Add(startBasicBlockExitBranch); startBasicBlockExitBranch.notTakenTarget = deadCodeBasicBlock; // generate dead code for the dead code basic block GraphTransformerDeadCodeBasicBlock deadCodeMetadata = new GraphTransformerDeadCodeBasicBlock(); deadCodeBasicBlock.transformationMetadata.Add(deadCodeMetadata); // set the created basic block and conditional jumps as output outStartBasicBlock = startBasicBlock; outConditionalBranch = startBasicBlockExitBranch; }
// this function generates code for the "state switch" private void createCodeStateSwitch(ref BasicBlock outStateBasicBlock, ref SwitchBranchTarget outStateExitBranch, LocalDefinition intStateLocal, List<BasicBlockGraphNodeLink> links) { BasicBlock stateBasicBlock = new BasicBlock(); stateBasicBlock.startIdx = 0; stateBasicBlock.endIdx = 0; // create graph transformer metadata for the basic block GraphTransformerStateBasicBlock stateMetadata = new GraphTransformerStateBasicBlock(); foreach (BasicBlockGraphNodeLink link in links) { stateMetadata.correspondingGraphNodes.Add(link); } stateBasicBlock.transformationMetadata.Add(stateMetadata); // create switch statement for the "state switch" stateBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, intStateLocal)); uint[] switchSize = new uint[this.graph.graphValidPathCount]; stateBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Switch, switchSize)); // create exit branch for the new state basic block SwitchBranchTarget stateExitBranch = new SwitchBranchTarget(); stateExitBranch.sourceBasicBlock = stateBasicBlock; stateBasicBlock.exitBranch = stateExitBranch; // create the dead code for this "state switch" BasicBlock deadCodeBasicBlock = new BasicBlock(); deadCodeBasicBlock.startIdx = 0; deadCodeBasicBlock.endIdx = 0; // set the dead code basic block as "not taken" target for the conditional branch of the checking basic block deadCodeBasicBlock.entryBranches.Add(stateExitBranch); stateExitBranch.notTakenTarget = deadCodeBasicBlock; // TODO at the moment always the not taken branch of the switch statement is the dead code basic block // generate dead code for the dead code basic block GraphTransformerDeadCodeBasicBlock deadCodeMetadata = new GraphTransformerDeadCodeBasicBlock(); deadCodeBasicBlock.transformationMetadata.Add(deadCodeMetadata); // set new created basic blocks and exit branch as output outStateBasicBlock = stateBasicBlock; outStateExitBranch = stateExitBranch; }
// this function generates code for an opaque predicate that evaluates to "false" // => the "not taken" branch of the conditional branch have to be taken for the correct code path private void createCodeFalsePredicate(ref BasicBlock outStartBasicBlock, ref ConditionalBranchTarget outConditionalBranch, BasicBlockGraphNodeLink link, LocalDefinition currentNodeLocal) { // create a basic block that checks the opaque predicate (this check evaluates to "false") BasicBlock startBasicBlock = new BasicBlock(); startBasicBlock.startIdx = 0; startBasicBlock.endIdx = 0; // add graph transformer metadata to the basic block GraphTransformerPredicateBasicBlock metadata = new GraphTransformerPredicateBasicBlock(); metadata.predicateType = GraphOpaquePredicate.False; metadata.correspondingGraphNodes.Add(link); startBasicBlock.transformationMetadata.Add(metadata); // search for the valid and invalid interfaces list of the current valid path id List<ITypeReference> validInterfaces = null; List<ITypeReference> invalidInterfaces = null; foreach (PathElement pathElement in link.graphNode.pathElements) { if (pathElement.validPathId == link.validPathId) { validInterfaces = pathElement.validInterfaces; invalidInterfaces = pathElement.invalidInterfaces; } } if(validInterfaces == null || invalidInterfaces == null) { throw new ArgumentException("No valid/invalid interface list was found."); } // add a random check to the code // important: for this predicate the dead code is reached by the "taken" branch and the correct code is reached by the "not taken" branch int randPosition; ITypeReference interfaceToCheck = null; switch (this.prng.Next(8)) { case 0: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(validInterfaces.Count()); interfaceToCheck = validInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brfalse, 0)); break; case 1: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(validInterfaces.Count()); interfaceToCheck = validInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4_0)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brtrue, 0)); break; case 2: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(validInterfaces.Count()); interfaceToCheck = validInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4_1)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brfalse, 0)); break; case 3: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(validInterfaces.Count()); interfaceToCheck = validInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brtrue, 0)); break; case 4: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(invalidInterfaces.Count()); interfaceToCheck = invalidInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brtrue, 0)); break; case 5: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(invalidInterfaces.Count()); interfaceToCheck = invalidInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4_0)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brfalse, 0)); break; case 6: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(invalidInterfaces.Count()); interfaceToCheck = invalidInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4_1)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brtrue, 0)); break; case 7: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(invalidInterfaces.Count()); interfaceToCheck = invalidInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brfalse, 0)); break; default: throw new ArgumentException("This case should never be reached."); } // create the conditional branch for the checking basic block (not taken => correct code; taken => dead code) ConditionalBranchTarget startBasicBlockExitBranch = new ConditionalBranchTarget(); startBasicBlockExitBranch.sourceBasicBlock = startBasicBlock; startBasicBlock.exitBranch = startBasicBlockExitBranch; // create the dead code for this opaque predicate BasicBlock deadCodeBasicBlock = new BasicBlock(); deadCodeBasicBlock.startIdx = 0; deadCodeBasicBlock.endIdx = 0; // set the dead code basic block as "taken" target for the conditional branch of the checking basic block deadCodeBasicBlock.entryBranches.Add(startBasicBlockExitBranch); startBasicBlockExitBranch.takenTarget = deadCodeBasicBlock; // generate dead code for the dead code basic block GraphTransformerDeadCodeBasicBlock deadCodeMetadata = new GraphTransformerDeadCodeBasicBlock(); deadCodeBasicBlock.transformationMetadata.Add(deadCodeMetadata); // set the created basic block and conditional jumps as output outStartBasicBlock = startBasicBlock; outConditionalBranch = startBasicBlockExitBranch; }