protected override bool ParseCilInstructionInternal(Instruction instruction, ProgramState state) { var fieldReference = instruction.Operand as FieldReference; // An object expression for an instance field and a class expression for a static // field. Expression fieldParentExpression; // The expression to set the field to. Expression expressionToStore; switch (instruction.OpCode.Code) { case Code.Stfld: (expressionToStore, _) = state.Pop(); (fieldParentExpression, _) = state.Pop(); break; case Code.Stsfld: (expressionToStore, _) = state.Pop(); fieldParentExpression = new LvarExpression( new GlobalVariable(fieldReference.DeclaringType.GetCompatibleFullName())); break; default: return(false); } var fieldStore = new Store(CreateFieldExpression(fieldParentExpression, fieldReference), expressionToStore, Typ.FromTypeReferenceNoPointer(fieldReference.DeclaringType), state.CurrentLocation); var node = AddMethodBodyInstructionsToCfg(state, fieldStore); state.PushInstruction(instruction.Next, node); return(true); }
/// <summary> /// Creates a field expression given an expression for the field's parent as well as the /// field reference. /// </summary> /// <param name="fieldParentExpression">An expression for the parent of the field; /// represents a class for a static field, and an instance of the class for an instance /// field.</param> /// <param name="fieldReference">A <see cref="FieldReference"/> which describes the field /// for which the expression is being created.</param> /// <returns>The <see cref="LfieldExpression"/> for the given field.</returns> protected static LfieldExpression CreateFieldExpression(Expression fieldParentExpression, FieldReference fieldReference) { return(new LfieldExpression(fieldParentExpression, new FieldIdentifier(fieldReference.GetCompatibleFullName(), Typ.FromTypeReferenceNoPointer( fieldReference.FieldType)), Typ.FromTypeReferenceNoPointer( fieldReference.DeclaringType))); }
protected override bool ParseCilInstructionInternal(Instruction instruction, ProgramState state) { switch (instruction.OpCode.Code) { // Note that if unbox is applied on an object which is interprocedurally returned, // the object on the stack will not be a boxedValueType and unbox will fail. This // is a result of being unable to statically verify the type of the boxed object. case Code.Unbox: case Code.Unbox_Any: (_, var objType) = state.Pop(); if (objType is BoxedValueType boxedValueType) { var value = boxedValueType.BoxedVal; var valueType = boxedValueType.BoxedValType; if (instruction.OpCode.Code == Code.Unbox) { state.PushExpr(value, new Address(Tptr.PtrKind.Pk_pointer, valueType, value)); } else if (instruction.OpCode.Code == Code.Unbox_Any) { state.PushExpr(value, valueType); } } else { var type = instruction.Operand as TypeReference; if (type != null) { var silType = Typ.FromTypeReferenceNoPointer(type); var defaultBoxedValue = GetDefaultBoxedValue(silType); if (defaultBoxedValue != null) { state.PushExpr(defaultBoxedValue, silType); } else { return(false); } } else { return(false); } } state.PushInstruction(instruction.Next); return(true); default: return(false); } }
private void InitializeStruct(VarExpression fieldParentVariable, TypeDefinition parentTypeDefinition, List <SilInstruction> structFieldInitializationInstructions, ProgramState state, HashSet <TypeDefinition> parentTypeDefinitions) { foreach (var fieldReference in parentTypeDefinition.Fields) { var fieldExpression = CreateFieldExpression(fieldParentVariable, fieldReference); var defaultValue = GetDefaultValue(fieldReference.FieldType); // Struct field; the default value must be recursively filled. if (fieldReference.FieldType is TypeDefinition fieldTypeDefinition && fieldTypeDefinition.BaseType != null && fieldTypeDefinition.BaseType.FullName == "System.ValueType") { if (parentTypeDefinitions.Contains(fieldTypeDefinition)) { throw new Exception("Unable to handle cyclical struct type " + $"{fieldTypeDefinition.FullName}"); } // Allocates the struct field and stores it into the parent. (var structFieldMemoryAllocationCall, var structFieldVariable) = CreateMemoryAllocationCall(fieldTypeDefinition, state); structFieldInitializationInstructions.Add(structFieldMemoryAllocationCall); structFieldInitializationInstructions.Add( new Store(fieldExpression, structFieldVariable, Typ.FromTypeReferenceNoPointer(fieldReference.DeclaringType), state.CurrentLocation)); // Add the field to the parent definitions before recursing; remove after // recursive call returns. parentTypeDefinitions.Add(fieldTypeDefinition); // Recursively initializes the struct field. InitializeStruct(structFieldVariable, fieldTypeDefinition, structFieldInitializationInstructions, state, parentTypeDefinitions); parentTypeDefinitions.Remove(fieldTypeDefinition); }
protected override bool ParseCilInstructionInternal(Instruction instruction, ProgramState state) { switch (instruction.OpCode.Code) { case Code.Isinst: (var objectExpression, var objectType) = state.Pop(); var typeToCheck = instruction.Operand as TypeReference; var returnIdentifier = state.GetIdentifier(Identifier.IdentKind.Normal); var returnType = new Tint(Tint.IntKind.IBool, true); var builtinFunctionExpression = new ConstExpression( ProcedureName.BuiltIn__instanceof); var sizeofExpression = new SizeofExpression( Typ.FromTypeReferenceNoPointer(typeToCheck), SizeofExpression.SizeofExpressionKind.instof); var args = new List <Call.CallArg> { new Call.CallArg(objectExpression, objectType), new Call.CallArg(sizeofExpression, new Tvoid()) }; var callInstruction = new Call( returnIdentifier, returnType, builtinFunctionExpression, args, new Call.CallFlags(), state.CurrentLocation); var newNode = AddMethodBodyInstructionsToCfg(state, callInstruction); state.PushExpr(new VarExpression(returnIdentifier), returnType); state.PushInstruction(instruction.Next, newNode); return(true); default: return(false); } }
protected override bool ParseCilInstructionInternal(Instruction instruction, ProgramState state) { var field = instruction.Operand as FieldReference; // An object expression for an instance field and a class expression for a static // field. Expression fieldOwnerExpression; Typ fieldType; switch (instruction.OpCode.Code) { case Code.Ldfld: case Code.Ldflda: (var objectExpression, var objectExpressionType) = state.Pop(); // Handles the case in which the address of the owning object is on the stack. if (objectExpressionType is Address address) { // The value at the address is the parent expression, matching how the // field is initialized. var addressValueIdentifier = state.GetIdentifier( Identifier.IdentKind.Normal); state.PreviousNode.Instructions.Add( new Load(addressValueIdentifier, address.Value, Typ.FromTypeReferenceNoPointer(field.DeclaringType), state.CurrentLocation)); fieldOwnerExpression = new VarExpression(addressValueIdentifier); } // The expression represents the object itself. else { fieldOwnerExpression = objectExpression; } break; case Code.Ldsfld: case Code.Ldsflda: fieldOwnerExpression = new LvarExpression( new GlobalVariable(field.DeclaringType.GetCompatibleFullName())); break; default: return(false); } // An identifier to store the field expression. var fieldIdentifier = state.GetIdentifier(Identifier.IdentKind.Normal); fieldType = Typ.FromTypeReferenceNoPointer(field.FieldType); var fieldExpression = CreateFieldExpression(fieldOwnerExpression, field); if (instruction.OpCode.Code == Code.Ldfld || instruction.OpCode.Code == Code.Ldsfld) { state.PreviousNode.Instructions.Add(new Load(fieldIdentifier, fieldExpression, Typ.FromTypeReferenceNoPointer( field.DeclaringType), state.CurrentLocation)); state.AppendToPreviousNode = true; state.PushExpr(new VarExpression(fieldIdentifier), fieldType); } // Instruction is either Ldflda or Ldsflda. else { var fieldAddressVariableType = new Address(Tptr.PtrKind.Pk_pointer, Typ.FromTypeReferenceNoPointer( field.FieldType), fieldExpression, referenceKind: Address.ReferenceKind.Field); state.PushExpr(fieldExpression, fieldAddressVariableType); } state.PushInstruction(instruction.Next); return(true); }
protected static (CfgNode, CfgNode) CreateExceptionTypeCheckBranchNodes( ProgramState state, ExceptionHandler handler, Identifier exceptionIdentifier) { var handlerStartLocation = GetHandlerStartLocation(state, handler); var exceptionExpression = new VarExpression(exceptionIdentifier); var isInstIdentifier = state.GetIdentifier(Identifier.IdentKind.Normal); var isInstArgs = new List <Call.CallArg> { new Call.CallArg(exceptionExpression, Typ.FromTypeReference(handler.CatchType)), new Call.CallArg( new SizeofExpression( Typ.FromTypeReferenceNoPointer(handler.CatchType), SizeofExpression.SizeofExpressionKind.exact), new Tvoid()) }; // We don't mark the function output as an isinst output, as there is no load or store // of it. var isInstCall = new Call(isInstIdentifier, new Tint(Tint.IntKind.IBool), new ConstExpression(ProcedureName.BuiltIn__instanceof), isInstArgs, new Call.CallFlags(), handlerStartLocation); var isInstOutputExpression = new VarExpression(isInstIdentifier); var pruneTrueInstruction = new Prune(isInstOutputExpression, true, Prune.IfKind.Ik_switch, handlerStartLocation); var pruneFalseInstruction = new Prune(new UnopExpression(UnopExpression.UnopKind.LNot, isInstOutputExpression, null), false, Prune.IfKind.Ik_switch, handlerStartLocation); var setCatchVarInstruction = new Store(GetHandlerCatchVar(state, handler), exceptionExpression, Typ.FromTypeReference(state.Method.ReturnType), handlerStartLocation); var pruneTrueNode = new PruneNode(handlerStartLocation, true, PruneNode.PruneNodeKind.ExceptionHandler, Prune.IfKind.Ik_switch, state.ProcDesc); var pruneFalseNode = new PruneNode(handlerStartLocation, false, PruneNode.PruneNodeKind.ExceptionHandler, Prune.IfKind.Ik_switch, state.ProcDesc); pruneTrueNode.Instructions.AddRange(new List <SilInstruction> { isInstCall, pruneTrueInstruction, setCatchVarInstruction }); pruneFalseNode.Instructions.AddRange(new List <SilInstruction> { isInstCall, pruneFalseInstruction }); pruneTrueNode.BlockEndOffset = state.MethodExceptionHandlers .GetBlockEndOffsetFromOffset( state.CurrentInstruction.Offset); pruneFalseNode.BlockEndOffset = state.MethodExceptionHandlers .GetBlockEndOffsetFromOffset( state.CurrentInstruction.Offset); state.Cfg.RegisterNode(pruneTrueNode); state.Cfg.RegisterNode(pruneFalseNode); return(pruneTrueNode, pruneFalseNode); }