Example #1
0
        private ExpressionSyntax GenCall(FuzzType type, bool allowNew)
        {
            Debug.Assert(!(type is RefType), "Cannot GenCall to ref type -- use GenExistingLValue for that");

            FuncGenerator func;

            if (allowNew && Random.FlipCoin(Options.GenNewMethodProb))
            {
                type = type ?? Types.PickType(Options.ReturnTypeIsByRefProb);

                func = new FuncGenerator(_funcs, Random, Types, Statics, _genChecksumSiteId);
                func.Generate(type, true);
            }
            else
            {
                IEnumerable <FuncGenerator> funcs = _funcs.Skip(_funcIndex + 1);
                if (type != null)
                {
                    funcs = funcs.Where(f => f.ReturnType.IsCastableTo(type) || (f.ReturnType is RefType rt && rt.InnerType.IsCastableTo(type)));
                }

                List <FuncGenerator> list = funcs.ToList();
                if (list.Count == 0)
                {
                    return(null);
                }

                func = Random.NextElement(list);
                type = type ?? func.ReturnType;
            }

            ArgumentSyntax[]           args  = GenArgs(func, 0, out _);
            InvocationExpressionSyntax invoc =
                InvocationExpression(
                    IdentifierName(func.Name),
                    ArgumentList(
                        SeparatedList(args)));

            if (func.ReturnType == type || func.ReturnType is RefType retRt && retRt.InnerType == type)
            {
                return(invoc);
            }

            return(CastExpression(type.GenReferenceTo(), invoc));
        }
Example #2
0
        private ArgumentSyntax[] GenArgs(FuncGenerator funcToCall, int minRefEscapeScope, out int argsMinRefEscapeScope)
        {
            ArgumentSyntax[] args = new ArgumentSyntax[funcToCall.Parameters.Length];
            argsMinRefEscapeScope = int.MaxValue;

            for (int i = 0; i < args.Length; i++)
            {
                FuzzType paramType = funcToCall.Parameters[i].Type;
                if (paramType is RefType rt)
                {
                    LValueInfo lv = GenLValue(rt.InnerType, minRefEscapeScope);
                    argsMinRefEscapeScope = Math.Min(argsMinRefEscapeScope, lv.RefEscapeScope);
                    args[i] = Argument(lv.Expression).WithRefKindKeyword(Token(SyntaxKind.RefKeyword));
                }
                else
                {
                    args[i] = Argument(GenExpression(paramType));
                }
            }

            return(args);
        }
Example #3
0
        private ExpressionSyntax GenCall(FuzzType type, bool allowNew)
        {
            Debug.Assert(!(type is RefType), "Cannot GenCall to ref type -- use GenExistingLValue for that");

            FuncGenerator func;

            if (allowNew && Random.FlipCoin(Options.GenNewFunctionProb) && !Options.FuncGenRejection.Reject(_funcs.Count, Random.Rng))
            {
                type = type ?? Types.PickType(Options.ReturnTypeIsByRefProb);

                func = new FuncGenerator(_funcs, Random, Types, Statics, _genChecksumSiteId);
                func.Generate(type, true);
            }
            else
            {
                IEnumerable <FuncGenerator> funcs =
                    _funcs
                    .Skip(_funcIndex + 1)
                    .Where(candidate =>
                {
                    // Make sure we do not get too many leaf calls. Here we compute what the new transitive
                    // number of calls would be to each function, and if it's too much, reject this candidate.
                    // Note that we will never reject calling a leaf function directly, even if the +1 puts
                    // us over the cap. That is intentional. We only want to limit the exponential growth
                    // which happens when functions call functions multiple times, and those functions also
                    // call functions multiple times.
                    foreach (var(transFunc, transNumCall) in candidate._callCountMap)
                    {
                        _callCountMap.TryGetValue(transFunc, out long curNumCalls);
                        if (curNumCalls + transNumCall > Options.SingleFunctionMaxTotalCalls)
                        {
                            return(false);
                        }
                    }

                    return(true);
                });

                if (type != null)
                {
                    funcs = funcs.Where(f => f.ReturnType.IsCastableTo(type) || (f.ReturnType is RefType rt && rt.InnerType.IsCastableTo(type)));
                }

                List <FuncGenerator> list = funcs.ToList();
                if (list.Count == 0)
                {
                    return(null);
                }

                func = Random.NextElement(list);
                type = type ?? func.ReturnType;
            }

            // Update transitive call counts before generating args, so we decrease chance of
            // calling the same methods in the arg expressions.
            _callCountMap.TryGetValue(func._funcIndex, out long numCalls);
            _callCountMap[func._funcIndex] = numCalls + 1;

            foreach (var(transFunc, transNumCalls) in func._callCountMap)
            {
                _callCountMap.TryGetValue(transFunc, out long curNumCalls);
                _callCountMap[transFunc] = curNumCalls + transNumCalls;
            }

            ArgumentSyntax[]           args  = GenArgs(func, 0, out _);
            InvocationExpressionSyntax invoc =
                InvocationExpression(
                    IdentifierName(func.Name),
                    ArgumentList(
                        SeparatedList(args)));

            if (func.ReturnType == type || func.ReturnType is RefType retRt && retRt.InnerType == type)
            {
                return(invoc);
            }

            return(CastExpression(type.GenReferenceTo(), invoc));
        }
Example #4
0
        private LValueInfo GenExistingLValue(FuzzType type, int minRefEscapeScope)
        {
            Debug.Assert(type == null || !(type is RefType));

            LValueKind kind = (LValueKind)Options.ExistingLValueDist.Sample(Random.Rng);

            if (kind == LValueKind.RefReturningCall)
            {
                List <FuncGenerator> refReturningFuncs = new List <FuncGenerator>();
                foreach (FuncGenerator func in _funcs.Skip(_funcIndex + 1))
                {
                    if (!(func.ReturnType is RefType rt))
                    {
                        continue;
                    }

                    if (type == null || type == rt.InnerType)
                    {
                        refReturningFuncs.Add(func);
                    }
                }

                // If we don't have a ref-returning function, fall back to local/static by retrying.
                // The reason we don't always fall back to trying other options is that otherwise
                // we may stack overflow in cases like ref int M(ref int a), if we have no locals
                // or statics of type int. We would keep generating method calls in this case.
                // This is kind of a hack, although it is pretty natural to pick statics/locals for
                // lvalues, so it is not that big of a deal.
                if (refReturningFuncs.Count == 0)
                {
                    return(GenExistingLValue(type, minRefEscapeScope));
                }

                FuncGenerator funcToCall = Random.NextElement(refReturningFuncs);

                // When calling a func that returns a by-ref, we need to take into account that the C# compiler
                // performs 'escape-analysis' on by-refs. If we want to produce a non-local by-ref we are only
                // allowed to pass non-local by-refs. The following example illustrates the analysis performed
                // by the compiler:
                // ref int M(ref int b, ref int c) {
                //   int a = 2;
                //   return ref Max(ref a, ref b); // compiler error, returned by-ref could point to 'a' and escape
                //   return ref Max(ref b, ref c); // ok, returned ref cannot point to local
                // }
                // ref int Max(ref int a, ref int b) { ... }
                // This is the reason for the second arg passed to GenArgs. For example, if we want a call to return
                // a ref that may escape, we need a minimum ref escape scope of 1, since 0 could pass refs to locals,
                // and the result of that call would not be valid to return.
                ArgumentSyntax[]           args  = GenArgs(funcToCall, minRefEscapeScope, out int argsMinRefEscapeScope);
                InvocationExpressionSyntax invoc =
                    InvocationExpression(
                        IdentifierName(funcToCall.Name),
                        ArgumentList(
                            SeparatedList(
                                args)));

                return(new LValueInfo(invoc, ((RefType)funcToCall.ReturnType).InnerType, argsMinRefEscapeScope));
            }

            List <LValueInfo> lvalues = CollectVariablePaths(type, minRefEscapeScope, kind == LValueKind.Local, kind == LValueKind.Static);

            if (lvalues.Count == 0)
            {
                // We typically fall back to generating a static, so just try to find a static if we found no local.
                if (kind != LValueKind.Local)
                {
                    return(null);
                }

                lvalues = CollectVariablePaths(type, minRefEscapeScope, false, true);
                if (lvalues.Count == 0)
                {
                    return(null);
                }
            }

            return(Random.NextElement(lvalues));
        }
Example #5
0
        internal void GenerateMethods(Func <string> genChecksumSiteId)
        {
            FuncGenerator gen = new FuncGenerator(_funcs, Random, Types, Statics, genChecksumSiteId);

            gen.Generate(null, false);
        }