void InjectPropertySetterGuard(MethodDefinition setMethod, Document doc, PropertyDefinition property) { var valueParameter = property.SetMethod.GetPropertySetterValueParameter(); if (!valueParameter.MayNotBeNull()) { return; } var guardInstructions = new List <Instruction>(); var errorMessage = string.Format(CultureInfo.InvariantCulture, CannotSetTheValueOfPropertyToNull, property.FullName); var entry = setMethod.Body.Instructions.First(); if (isDebug) { InstructionPatterns.LoadArgumentOntoStack(guardInstructions, valueParameter); InstructionPatterns.CallDebugAssertInstructions(guardInstructions, errorMessage); } InstructionPatterns.LoadArgumentOntoStack(guardInstructions, valueParameter); InstructionPatterns.IfNull(guardInstructions, entry, i => { InstructionPatterns.LoadArgumentNullException(i, valueParameter.Name, errorMessage); // Throw the top item off the stack i.Add(Instruction.Create(OpCodes.Throw)); }); setMethod.HideLineFromDebugger(guardInstructions[0], doc); setMethod.Body.Instructions.Prepend(guardInstructions); }
void AddReturnNullGuard(MethodDefinition methodDefinition, Document doc, int ret, TypeReference returnType, string errorMessage, params Instruction[] finalInstructions) { var returnInstruction = methodDefinition.Body.Instructions[ret]; var guardInstructions = new List <Instruction>(); if (isDebug) { InstructionPatterns.DuplicateReturnValue(guardInstructions, returnType); InstructionPatterns.CallDebugAssertInstructions(guardInstructions, errorMessage); } InstructionPatterns.DuplicateReturnValue(guardInstructions, returnType); InstructionPatterns.IfNull(guardInstructions, returnInstruction, i => { // Clean up the stack (important if finalInstructions doesn't throw, e.g. for async methods): i.Add(Instruction.Create(OpCodes.Pop)); InstructionPatterns.LoadInvalidOperationException(i, errorMessage); i.AddRange(finalInstructions); }); methodDefinition.HideLineFromDebugger(guardInstructions[0], doc); methodDefinition.Body.InsertAtMethodReturnPoint(ret, guardInstructions); }
void AddReturnNullGuard(Collection <Instruction> instructions, SequencePoint seqPoint, int ret, TypeReference returnType, string errorMessage, params Instruction[] finalInstructions) { var returnInstruction = instructions[ret]; var guardInstructions = new List <Instruction>(); if (isDebug) { InstructionPatterns.DuplicateReturnValue(guardInstructions, returnType); InstructionPatterns.CallDebugAssertInstructions(guardInstructions, errorMessage); } InstructionPatterns.DuplicateReturnValue(guardInstructions, returnType); InstructionPatterns.IfNull(guardInstructions, returnInstruction, i => { // Clean up the stack since we're about to throw up. i.Add(Instruction.Create(OpCodes.Pop)); InstructionPatterns.LoadInvalidOperationException(i, errorMessage); i.AddRange(finalInstructions); }); guardInstructions[0].HideLineFromDebugger(seqPoint); instructions.Insert(ret, guardInstructions); }
private void InjectPropertySetterGuard(MethodBody setBody, ParameterDefinition valueParameter, string errorMessage) { if (!valueParameter.MayNotBeNull()) { return; } var guardInstructions = new List <Instruction>(); var entry = setBody.Instructions.First(); if (isDebug) { InstructionPatterns.LoadArgumentOntoStack(guardInstructions, valueParameter); InstructionPatterns.CallDebugAssertInstructions(guardInstructions, errorMessage); } InstructionPatterns.LoadArgumentOntoStack(guardInstructions, valueParameter); InstructionPatterns.IfNull(guardInstructions, entry, i => { InstructionPatterns.LoadArgumentNullException(i, valueParameter.Name, errorMessage); // Throw the top item off the stack i.Add(Instruction.Create(OpCodes.Throw)); }); setBody.Instructions.Prepend(guardInstructions); }
private void InjectMethodReturnGuard(ValidationFlags localValidationFlags, MethodDefinition method, MethodBody body) { var guardInstructions = new List <Instruction>(); var returnPoints = body.Instructions .Select((o, ix) => new { o, ix }) .Where(a => a.o.OpCode == OpCodes.Ret) .Select(a => a.ix) .OrderByDescending(ix => ix); foreach (var ret in returnPoints) { var returnInstruction = body.Instructions[ret]; if (localValidationFlags.HasFlag(ValidationFlags.ReturnValues) && !method.MethodReturnType.AllowsNull() && method.ReturnType.IsRefType() && method.ReturnType.FullName != typeof(void).FullName) { AddReturnNullGuard(body.Instructions, ret, method.ReturnType, String.Format(CultureInfo.InvariantCulture, STR_ReturnValueOfMethodIsNull, method.FullName), Instruction.Create(OpCodes.Throw)); } if (localValidationFlags.HasFlag(ValidationFlags.Arguments)) { foreach (var parameter in method.Parameters.Reverse()) { // This is no longer the return instruction location, but it is where we want to jump to. returnInstruction = body.Instructions[ret]; if (localValidationFlags.HasFlag(ValidationFlags.OutValues) && parameter.IsOut && parameter.ParameterType.IsRefType()) { guardInstructions.Clear(); if (isDebug) { InstructionPatterns.LoadArgumentOntoStack(guardInstructions, parameter); InstructionPatterns.CallDebugAssertInstructions(guardInstructions, String.Format(CultureInfo.InvariantCulture, STR_OutParameterIsNull, parameter.Name)); } InstructionPatterns.LoadArgumentOntoStack(guardInstructions, parameter); InstructionPatterns.IfNull(guardInstructions, returnInstruction, i => { InstructionPatterns.LoadInvalidOperationException(i, String.Format(CultureInfo.InvariantCulture, STR_OutParameterIsNull, parameter.Name)); // Throw the top item off the stack i.Add(Instruction.Create(OpCodes.Throw)); }); body.Instructions.Insert(ret, guardInstructions); } } } } }
void InjectMethodArgumentGuards(MethodDefinition method, MethodBody body, SequencePoint seqPoint) { var guardInstructions = new List <Instruction>(); foreach (var parameter in method.Parameters.Reverse()) { if (!parameter.MayNotBeNull()) { continue; } if (method.IsSetter && parameter.Equals(method.GetPropertySetterValueParameter())) { continue; } if (CheckForExistingGuard(body.Instructions, parameter)) { continue; } var entry = body.Instructions.First(); var errorMessage = string.Format(CultureInfo.InvariantCulture, IsNull, parameter.Name); guardInstructions.Clear(); if (isDebug) { InstructionPatterns.LoadArgumentOntoStack(guardInstructions, parameter); InstructionPatterns.CallDebugAssertInstructions(guardInstructions, errorMessage); } InstructionPatterns.LoadArgumentOntoStack(guardInstructions, parameter); InstructionPatterns.IfNull(guardInstructions, entry, i => { InstructionPatterns.LoadArgumentNullException(i, parameter.Name, errorMessage); // Throw the top item off the stack i.Add(Instruction.Create(OpCodes.Throw)); }); guardInstructions[0].HideLineFromDebugger(seqPoint); body.Instructions.Prepend(guardInstructions); } }
void InjectPropertyGetterGuard(MethodDefinition getMethod, Document doc, PropertyReference property) { var guardInstructions = new List <Instruction>(); var returnPoints = getMethod.Body.Instructions .Select((o, i) => new { o, i }) .Where(a => a.o.OpCode == OpCodes.Ret) .Select(a => a.i) .OrderByDescending(i => i); foreach (var ret in returnPoints) { var returnInstruction = getMethod.Body.Instructions[ret]; var errorMessage = string.Format(CultureInfo.InvariantCulture, ReturnValueOfPropertyIsNull, property.FullName); guardInstructions.Clear(); if (isDebug) { InstructionPatterns.DuplicateReturnValue(guardInstructions, property.PropertyType); InstructionPatterns.CallDebugAssertInstructions(guardInstructions, errorMessage); } InstructionPatterns.DuplicateReturnValue(guardInstructions, property.PropertyType); InstructionPatterns.IfNull(guardInstructions, returnInstruction, i => { // Clean up the stack since we're about to throw up. i.Add(Instruction.Create(OpCodes.Pop)); InstructionPatterns.LoadInvalidOperationException(i, errorMessage); // Throw the top item off the stack i.Add(Instruction.Create(OpCodes.Throw)); }); getMethod.HideLineFromDebugger(guardInstructions[0], doc); getMethod.Body.InsertAtMethodReturnPoint(ret, guardInstructions); } }
private void InjectMethodArgumentGuards(MethodDefinition method, MethodBody body) { var guardInstructions = new List <Instruction>(); foreach (var parameter in method.Parameters.Reverse()) { if (!parameter.MayNotBeNull()) { continue; } if (CheckForExistingGuard(body.Instructions, parameter)) { continue; } var entry = body.Instructions.First(); guardInstructions.Clear(); if (isDebug) { InstructionPatterns.LoadArgumentOntoStack(guardInstructions, parameter); InstructionPatterns.CallDebugAssertInstructions(guardInstructions, String.Format(CultureInfo.InvariantCulture, STR_IsNull, parameter.Name)); } InstructionPatterns.LoadArgumentOntoStack(guardInstructions, parameter); InstructionPatterns.IfNull(guardInstructions, entry, i => { InstructionPatterns.LoadArgumentNullException(i, parameter.Name, String.Format(CultureInfo.InvariantCulture, STR_IsNull, parameter.Name)); // Throw the top item off the stack i.Add(Instruction.Create(OpCodes.Throw)); }); body.Instructions.Prepend(guardInstructions); } }
private void InjectPropertyGetterGuard(MethodBody getBody, TypeReference propertyType, string errorMessage) { var guardInstructions = new List <Instruction>(); var returnPoints = getBody.Instructions .Select((o, i) => new { o, i }) .Where(a => a.o.OpCode == OpCodes.Ret) .Select(a => a.i) .OrderByDescending(i => i); foreach (var ret in returnPoints) { var returnInstruction = getBody.Instructions[ret]; guardInstructions.Clear(); if (isDebug) { InstructionPatterns.DuplicateReturnValue(guardInstructions, propertyType); InstructionPatterns.CallDebugAssertInstructions(guardInstructions, errorMessage); } InstructionPatterns.DuplicateReturnValue(guardInstructions, propertyType); InstructionPatterns.IfNull(guardInstructions, returnInstruction, i => { // Clean up the stack since we're about to throw up. i.Add(Instruction.Create(OpCodes.Pop)); InstructionPatterns.LoadInvalidOperationException(i, errorMessage); // Throw the top item off the stack i.Add(Instruction.Create(OpCodes.Throw)); }); getBody.Instructions.Insert(ret, guardInstructions); } }
void InjectMethodReturnGuard(ValidationFlags localValidationFlags, MethodDefinition method, MethodBody body, Document doc) { var guardInstructions = new List <Instruction>(); var returnPoints = body.Instructions .Select((o, ix) => new { o, ix }) .Where(a => a.o.OpCode == OpCodes.Ret) .Select(a => a.ix) .OrderByDescending(ix => ix); foreach (var ret in returnPoints) { if (localValidationFlags.HasFlag(ValidationFlags.ReturnValues) && !method.AllowsNullReturnValue() && method.ReturnType.IsRefType() && method.ReturnType.FullName != typeof(void).FullName && !method.IsGetter) { var errorMessage = string.Format(ReturnValueOfMethodIsNull, method.FullName); AddReturnNullGuard(method, doc, ret, method.ReturnType, errorMessage, Instruction.Create(OpCodes.Throw)); } if (localValidationFlags.HasFlag(ValidationFlags.Arguments)) { foreach (var parameter in method.Parameters.Reverse()) { // This is no longer the return instruction location, but it is where we want to jump to. var returnInstruction = body.Instructions[ret]; if (localValidationFlags.HasFlag(ValidationFlags.OutValues) && parameter.IsOut && parameter.ParameterType.IsRefType() && !parameter.AllowsNull()) { var errorMessage = $"[NullGuard] Out parameter '{parameter.Name}' is null."; guardInstructions.Clear(); if (isDebug) { InstructionPatterns.LoadArgumentOntoStack(guardInstructions, parameter); InstructionPatterns.CallDebugAssertInstructions(guardInstructions, errorMessage); } InstructionPatterns.LoadArgumentOntoStack(guardInstructions, parameter); InstructionPatterns.IfNull(guardInstructions, returnInstruction, i => { InstructionPatterns.LoadInvalidOperationException(i, errorMessage); // Throw the top item off the stack i.Add(Instruction.Create(OpCodes.Throw)); }); method.HideLineFromDebugger(guardInstructions[0], doc); body.InsertAtMethodReturnPoint(ret, guardInstructions); } } } } }