示例#1
0
 /// <summary>
 /// Creates a null-check exception specification.
 /// </summary>
 /// <param name="parameterIndex">
 /// The index of the instruction parameter that is null checked.
 /// </param>
 /// <param name="nullCheckSpec">
 /// The exception specification of the exception thrown
 /// if and when a null check fails.
 /// </param>
 public NullCheckExceptionSpecification(
     int parameterIndex,
     ExceptionSpecification nullCheckSpec)
 {
     this.ParameterIndex = parameterIndex;
     this.NullCheckSpec  = nullCheckSpec;
 }
示例#2
0
        /// <summary>
        /// Creates CIL prototype exception specification rules.
        /// </summary>
        /// <param name="corlibTypeResolver">
        /// A type resolver for the core library (corlib.dll) that
        /// defines well-known exception types.
        /// </param>
        /// <returns>Prototype exception specification rules.</returns>
        public static RuleBasedPrototypeExceptionSpecs Create(
            ReadOnlyTypeResolver corlibTypeResolver)
        {
            var result = new RuleBasedPrototypeExceptionSpecs(
                RuleBasedPrototypeExceptionSpecs.Default);

            // We know the type of exception thrown by null checks:
            // it's System.NullReferenceException.
            var nullRefException = corlibTypeResolver.ResolveTypes(
                new SimpleName(nameof(NullReferenceException))
                .Qualify(nameof(System)))
                                   .Single();

            // Resolve other well-known exception types.
            var outOfRangeException = corlibTypeResolver.ResolveTypes(
                new SimpleName(nameof(IndexOutOfRangeException))
                .Qualify(nameof(System)))
                                      .Single();

            var arrayTypeMismatchException = corlibTypeResolver.ResolveTypes(
                new SimpleName(nameof(ArrayTypeMismatchException))
                .Qualify(nameof(System)))
                                             .Single();

            // Refine null check exception types.
            result.Register <GetFieldPointerPrototype>(
                new NullCheckExceptionSpecification(0, nullRefException));
            result.Register <NewDelegatePrototype>(
                proto => proto.Lookup == MethodLookup.Virtual
                    ? new NullCheckExceptionSpecification(0, nullRefException)
                    : ExceptionSpecification.NoThrow);
            result.Register <UnboxPrototype>(
                new NullCheckExceptionSpecification(0, nullRefException));

            // Array intrinsics are worth refining, too.
            result.Register(
                ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.GetElementPointer),
                ExceptionSpecification.Union(
                    new NullCheckExceptionSpecification(0, nullRefException),
                    ExceptionSpecification.Exactly(outOfRangeException),
                    ExceptionSpecification.Exactly(arrayTypeMismatchException)));
            result.Register(
                ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.LoadElement),
                ExceptionSpecification.Union(
                    new NullCheckExceptionSpecification(0, nullRefException),
                    ExceptionSpecification.Exactly(outOfRangeException)));
            result.Register(
                ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.StoreElement),
                ExceptionSpecification.Union(
                    new NullCheckExceptionSpecification(0, nullRefException),
                    ExceptionSpecification.Exactly(outOfRangeException),
                    ExceptionSpecification.Exactly(arrayTypeMismatchException)));
            result.Register(
                ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.GetLength),
                new NullCheckExceptionSpecification(0, nullRefException));

            return(result);
        }
 private ExceptionSpecification Reify(
     ExceptionSpecification prototypeSpec,
     Instruction instruction,
     FlowGraph graph)
 {
     if (prototypeSpec is ExceptionSpecification.Union)
     {
         var unionSpec   = (ExceptionSpecification.Union)prototypeSpec;
         var newOperands = new List <ExceptionSpecification>();
         foreach (var operand in unionSpec.Operands)
         {
             var newOp = Reify(operand, instruction, graph);
             if (newOp == ExceptionSpecification.ThrowAny)
             {
                 return(newOp);
             }
             else if (newOp.CanThrowSomething)
             {
                 newOperands.Add(newOp);
             }
         }
         return(ExceptionSpecification.Union.Create(newOperands.ToArray()));
     }
     else if (prototypeSpec is NullCheckExceptionSpecification)
     {
         var nullCheck   = (NullCheckExceptionSpecification)prototypeSpec;
         var arg         = instruction.Arguments[nullCheck.ParameterIndex];
         var nullability = graph.GetAnalysisResult <ValueNullability>();
         if (nullability.IsNonNull(arg))
         {
             return(ExceptionSpecification.NoThrow);
         }
         else
         {
             var innerSpec = Reify(nullCheck.NullCheckSpec, instruction, graph);
             if (!innerSpec.CanThrowSomething)
             {
                 return(ExceptionSpecification.NoThrow);
             }
             else
             {
                 return(new NullCheckExceptionSpecification(nullCheck.ParameterIndex, innerSpec));
             }
         }
     }
     else
     {
         return(prototypeSpec);
     }
 }
示例#4
0
 /// <summary>
 /// Registers a function that assigns a fixed exception specification
 /// to a particular type of intrinsic.
 /// </summary>
 /// <param name="intrinsicName">
 /// The name of the intrinsic to assign the exception
 /// specifications to.
 /// </param>
 /// <param name="exceptionSpec">
 /// The exception specification for all intrinsic prototypes with
 /// name <paramref name="intrinsicName"/>.
 /// </param>
 public void Register(string intrinsicName, ExceptionSpecification exceptionSpec)
 {
     store.Register(intrinsicName, exceptionSpec);
 }
示例#5
0
 /// <summary>
 /// Maps a particular type of instruction prototype
 /// to an exception specification.
 /// </summary>
 /// <param name="exceptionSpec">
 /// The exception specification to register.
 /// </param>
 /// <typeparam name="T">
 /// The type of instruction prototypes to which
 /// <paramref name="exceptionSpec"/> is applicable.
 /// </typeparam>
 public void Register <T>(ExceptionSpecification exceptionSpec)
     where T : InstructionPrototype
 {
     store.Register <T>(exceptionSpec);
 }
 /// <summary>
 /// Maps a particular type of instruction prototype
 /// to an exception specification.
 /// </summary>
 /// <param name="exceptionSpec">
 /// The exception specification to register.
 /// </param>
 /// <typeparam name="T">
 /// The type of instruction prototypes to which
 /// <paramref name="exceptionSpec"/> is applicable.
 /// </typeparam>
 public void Register <T>(ExceptionSpecification exceptionSpec)
     where T : InstructionPrototype
 {
     instructionSpecs[typeof(T)] = proto => exceptionSpec;
 }
 /// <summary>
 /// Creates a null-check exception specification.
 /// </summary>
 /// <param name="parameterIndex">
 /// The index of the instruction parameter that is null checked.
 /// </param>
 /// <param name="exceptionType">
 /// The type of exception that is thrown if and when
 /// a null check fails.
 /// </param>
 public NullCheckExceptionSpecification(
     int parameterIndex,
     IType exceptionType)
     : this(parameterIndex, ExceptionSpecification.Exactly(exceptionType))
 {
 }
        static RuleBasedPrototypeExceptionSpecs()
        {
            Default = new RuleBasedPrototypeExceptionSpecs();

            // Instruction prototypes that never throw.
            Default.Register <AllocaArrayPrototype>(ExceptionSpecification.NoThrow);
            Default.Register <AllocaPrototype>(ExceptionSpecification.NoThrow);
            Default.Register <BoxPrototype>(ExceptionSpecification.NoThrow);
            Default.Register <ConstantPrototype>(ExceptionSpecification.NoThrow);
            Default.Register <CopyPrototype>(ExceptionSpecification.NoThrow);
            Default.Register <DynamicCastPrototype>(ExceptionSpecification.NoThrow);
            Default.Register <GetStaticFieldPointerPrototype>(ExceptionSpecification.NoThrow);
            Default.Register <LoadPrototype>(ExceptionSpecification.NoThrow);
            Default.Register <ReinterpretCastPrototype>(ExceptionSpecification.NoThrow);
            Default.Register <StorePrototype>(ExceptionSpecification.NoThrow);

            // Instruction prototypes that may throw because of implicit null checks.
            Default.Register <GetFieldPointerPrototype>(
                new NullCheckExceptionSpecification(0, ExceptionSpecification.ThrowAny));
            Default.Register <NewDelegatePrototype>(
                proto => proto.Lookup == MethodLookup.Virtual
                    ? new NullCheckExceptionSpecification(0, ExceptionSpecification.ThrowAny)
                    : ExceptionSpecification.NoThrow);
            Default.Register <UnboxPrototype>(
                new NullCheckExceptionSpecification(0, ExceptionSpecification.ThrowAny));

            // Call-like instruction prototypes.
            // TODO: use the callee's exception specification.
            Default.Register <CallPrototype>(ExceptionSpecification.ThrowAny);
            Default.Register <NewObjectPrototype>(ExceptionSpecification.ThrowAny);
            Default.Register <IndirectCallPrototype>(ExceptionSpecification.ThrowAny);

            // Arithmetic intrinsics never throw.
            foreach (var name in ArithmeticIntrinsics.Operators.All)
            {
                Default.Register(
                    ArithmeticIntrinsics.GetArithmeticIntrinsicName(name),
                    ExceptionSpecification.NoThrow);
            }

            // Array intrinsics are a little more complicated.
            // TODO: model bounds checks somehow.
            Default.Register(
                ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.GetElementPointer),
                ExceptionSpecification.ThrowAny);
            Default.Register(
                ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.LoadElement),
                ExceptionSpecification.ThrowAny);
            Default.Register(
                ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.StoreElement),
                ExceptionSpecification.ThrowAny);
            Default.Register(
                ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.GetLength),
                new NullCheckExceptionSpecification(0, ExceptionSpecification.ThrowAny));
            Default.Register(
                ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.NewArray),
                ExceptionSpecification.NoThrow);

            // Exception intrinsics.
            Default.Register(
                ExceptionIntrinsics.Namespace.GetIntrinsicName(ExceptionIntrinsics.Operators.Capture),
                ExceptionSpecification.NoThrow);
            Default.Register(
                ExceptionIntrinsics.Namespace.GetIntrinsicName(ExceptionIntrinsics.Operators.GetCapturedException),
                ExceptionSpecification.NoThrow);
            Default.Register(
                ExceptionIntrinsics.Namespace.GetIntrinsicName(ExceptionIntrinsics.Operators.Rethrow),
                ExceptionSpecification.ThrowAny);
            Default.Register(
                ExceptionIntrinsics.Namespace.GetIntrinsicName(ExceptionIntrinsics.Operators.Throw),
                proto => ExceptionSpecification.Exactly(proto.ParameterTypes[0]));

            // Object intrinsics.
            // TODO: model exception thrown by type check.
            Default.Register(
                ObjectIntrinsics.Namespace.GetIntrinsicName(ObjectIntrinsics.Operators.UnboxAny),
                ExceptionSpecification.ThrowAny);
        }
 /// <summary>
 /// Registers a function that assigns a fixed exception specification
 /// to a particular type of intrinsic.
 /// </summary>
 /// <param name="intrinsicName">
 /// The name of the intrinsic to assign the exception
 /// specifications to.
 /// </param>
 /// <param name="exceptionSpec">
 /// The exception specification for all intrinsic prototypes with
 /// name <paramref name="intrinsicName"/>.
 /// </param>
 public void Register(string intrinsicName, ExceptionSpecification exceptionSpec)
 {
     Register(intrinsicName, proto => exceptionSpec);
 }
 /// <summary>
 /// Creates an exception specification attribute.
 /// </summary>
 /// <param name="specification">An exception specification.</param>
 public ExceptionSpecificationAttribute(ExceptionSpecification specification)
 {
     this.Specification = specification;
 }