Beispiel #1
0
        private ProgramPairResults CompileAndRun(CompilationUnitSyntax prog)
        {
            CompileResult progDebug   = Compiler.Compile(prog, Compiler.DebugOptions);
            CompileResult progRelease = Compiler.Compile(prog, Compiler.ReleaseOptions);

            if (progDebug.Assembly == null || progRelease.Assembly == null)
            {
                return(null);
            }

            ProgramPair        pair    = new ProgramPair(progDebug.Assembly, progRelease.Assembly);
            ProgramPairResults results = ProgramExecutor.RunPair(pair);

            return(results);
        }
Beispiel #2
0
    public RunSeparatelyResults RunPair(ProgramPair pair, TimeSpan timeout)
    {
        ReceiveResult result =
            RequestAndReceive(new Request
        {
            Kind = RequestKind.RunPair,
            Pair = pair,
        }, timeout);

        if (result.Ended)
        {
            return(new RunSeparatelyResults(RunSeparatelyResultsKind.Crash, null, result.Stderr));
        }

        if (result.Timeout)
        {
            return(new RunSeparatelyResults(RunSeparatelyResultsKind.Timeout, null, null));
        }

        return(new RunSeparatelyResults(RunSeparatelyResultsKind.Success, result.Response.RunPairResult, null));
    }
Beispiel #3
0
    private static ProgramPairResults RunPairAsync(AssemblyLoadContext alc, ProgramPair pair)
    {
        ProgramResult debugResult   = RunAndGetResultAsync(pair.Debug);
        ProgramResult releaseResult = RunAndGetResultAsync(pair.Release);
        ChecksumSite  unmatch1      = null;
        ChecksumSite  unmatch2      = null;

        if (debugResult.Checksum != releaseResult.Checksum && pair.TrackOutput)
        {
            int index;
            int count = Math.Min(debugResult.ChecksumSites.Count, releaseResult.ChecksumSites.Count);
            for (index = 0; index < count; index++)
            {
                ChecksumSite val1 = debugResult.ChecksumSites[index];
                ChecksumSite val2 = releaseResult.ChecksumSites[index];
                if (val1 != val2)
                {
                    break;
                }
            }

            if (index < debugResult.ChecksumSites.Count)
            {
                unmatch1 = debugResult.ChecksumSites[index];
            }
            if (index < releaseResult.ChecksumSites.Count)
            {
                unmatch2 = releaseResult.ChecksumSites[index];
            }
        }

        return(new ProgramPairResults(debugResult, releaseResult, unmatch1, unmatch2));

        ProgramResult RunAndGetResultAsync(byte[] bytes)
        {
            Assembly          asm            = alc.LoadFromStream(new MemoryStream(bytes));
            MethodInfo        mainMethodInfo = asm.GetType("Program").GetMethod("Main");
            Action <IRuntime> entryPoint     = (Action <IRuntime>)Delegate.CreateDelegate(typeof(Action <IRuntime>), mainMethodInfo);
            var runtime = new Runtime();

            List <ChecksumSite> TakeChecksumSites()
            {
                // A reference to the runtime stays in the loaded assembly and there may be a lot of checksum sites
                // so during reduction this can use a lot of memory.
                List <ChecksumSite> checksumSites = runtime.ChecksumSites;

                runtime.ChecksumSites = null;
                return(checksumSites);
            }

            if (pair.TrackOutput)
            {
                runtime.ChecksumSites = new List <ChecksumSite>();
            }

            int threadID = Environment.CurrentManagedThreadId;
            List <Exception> exceptions = null;

            void FirstChanceExceptionHandler(object sender, FirstChanceExceptionEventArgs args)
            {
                if (Environment.CurrentManagedThreadId == threadID)
                {
                    (exceptions ??= new List <Exception>()).Add(args.Exception);
                }
            }

            AppDomain.CurrentDomain.FirstChanceException += FirstChanceExceptionHandler;
            try
            {
                entryPoint(runtime);
            }
            catch
            {
                // We consider the innermost exception the root cause and only report it.
                // Otherwise we may be confusing the viewer about what the problem is.
                // Consider for example (adapted from a real example):
                // try
                // {
                //   value = -1;
                //   FunctionThatJitAssertsInDebug();
                //   value = 1;
                // }
                // finally
                // {
                //   int.MinValue / value;
                // }
                // We are interested in the JIT assert that was hit, and not the OverflowException
                // thrown because value = 1 did not get to run.
                Exception ex = exceptions[0];

                if (ex is InvalidProgramException && ex.Message.Contains("JIT assert failed"))
                {
                    return(new ProgramResult
                    {
                        Kind = ProgramResultKind.HitsJitAssert,
                        Checksum = runtime.FinishHashCode(),
                        ChecksumSites = TakeChecksumSites(),
                        JitAssertError = ex.Message,
                    });
                }

                return(new ProgramResult
                {
                    Kind = ProgramResultKind.ThrowsException,
                    Checksum = runtime.FinishHashCode(),
                    ChecksumSites = TakeChecksumSites(),
                    ExceptionType = ex.GetType().FullName,
                    ExceptionText = ex.ToString(),
                    ExceptionStackTrace = ex.StackTrace,
                });
            }
            finally
            {
                AppDomain.CurrentDomain.FirstChanceException -= FirstChanceExceptionHandler;
            }

            return(new ProgramResult
            {
                Kind = ProgramResultKind.RunsSuccessfully,
                Checksum = runtime.FinishHashCode(),
                ChecksumSites = TakeChecksumSites(),
            });
        }
    }
Beispiel #4
0
        public CompilationUnitSyntax Reduce()
        {
            CompileResult debug   = Compiler.Compile(Original, Compiler.DebugOptions);
            CompileResult release = Compiler.Compile(Original, Compiler.ReleaseOptions);

            Func <CompilationUnitSyntax, bool> isInteresting;

            if (debug.RoslynException != null || release.RoslynException != null)
            {
                CSharpCompilationOptions opts = debug.RoslynException != null ? Compiler.DebugOptions : Compiler.ReleaseOptions;
                isInteresting = program => Compiler.Compile(program, opts).RoslynException != null;
            }
            else if (debug.CompileErrors.Length > 0 || release.CompileErrors.Length > 0)
            {
                CSharpCompilationOptions opts = debug.CompileErrors.Length > 0 ? Compiler.DebugOptions : Compiler.ReleaseOptions;
                isInteresting = program =>
                {
                    CompileResult recompiled = Compiler.Compile(program, opts);
                    if (recompiled.CompileErrors.Length <= 0)
                    {
                        return(false);
                    }

                    return(recompiled.CompileErrors[0].Id == (debug.CompileErrors.Length > 0 ? debug.CompileErrors[0] : release.CompileErrors[0]).Id);
                };
            }
            else
            {
                var origPair = new ProgramPair(debug.Assembly, release.Assembly);
                ProgramPairResults origResults = ProgramExecutor.RunPair(origPair);
                if (origResults.DebugResult.Checksum == origResults.ReleaseResult.Checksum &&
                    origResults.DebugResult.ExceptionType == origResults.ReleaseResult.ExceptionType)
                {
                    throw new InvalidOperationException("Program has no errors");
                }

                isInteresting = prog =>
                {
                    ProgramPairResults results = CompileAndRun(prog);
                    if (results == null)
                    {
                        return(false);
                    }

                    // Do exceptions first because they will almost always change checksum
                    if (origResults.DebugResult.ExceptionType != origResults.ReleaseResult.ExceptionType)
                    {
                        // Must throw same exceptions in debug and release to be bad.
                        return(results.DebugResult.ExceptionType == origResults.DebugResult.ExceptionType &&
                               results.ReleaseResult.ExceptionType == origResults.ReleaseResult.ExceptionType);
                    }
                    else
                    {
                        if (results.DebugResult.ExceptionType != origResults.DebugResult.ExceptionType ||
                            results.ReleaseResult.ExceptionType != origResults.ReleaseResult.ExceptionType)
                        {
                            return(false);
                        }
                    }

                    return(results.DebugResult.Checksum != results.ReleaseResult.Checksum);
                };
            }

            // Save original comments as simplification may remove it by removing an unnecessary type.
            SyntaxTriviaList originalTrivia = Original.GetLeadingTrivia();

            Reduced = Original.WithLeadingTrivia();

            Reduced = CoarseSimplify(Reduced, isInteresting);
            List <SyntaxNode> simplifiedNodes = new List <SyntaxNode>();
            bool first = true;
            bool any   = true;

            while (any)
            {
                any = false;
                while (true)
                {
                    if (!SimplifyOne("Statements", Reduced.DescendantNodes().Where(n => n is StatementSyntax).ToList()))
                    {
                        break;
                    }
                    any = true;
                }

                while (true)
                {
                    if (!SimplifyOne("Expressions", Reduced.DescendantNodes().Where(n => n is ExpressionSyntax).ToList()))
                    {
                        break;
                    }
                    any = true;
                }

                while (true)
                {
                    List <SyntaxNode> members =
                        Reduced.DescendantNodesAndSelf().Where(n => n is MemberDeclarationSyntax || n is CompilationUnitSyntax).ToList();

                    if (!SimplifyOne("Members", members))
                    {
                        break;
                    }
                    any = true;
                }

                first = false;

                bool SimplifyOne(string name, List <SyntaxNode> list)
                {
                    for (int i = 0; i < 2000; i++)
                    {
                        Console.Title = $"Simplifying {name}. Iter: {i}";

                        SyntaxNode node = list[_rng.Next(list.Count)];
                        // Do not optimize checksum args and call itself.
                        // We still want to remove these statements, however, so we focus on the expression only.
                        InvocationExpressionSyntax invocParent = node.FirstAncestorOrSelf <InvocationExpressionSyntax>();
                        if (invocParent != null && IsChecksumCall(invocParent))
                        {
                            continue;
                        }

                        // If we fail at creating a new bad example, then we want to be able to restore the state
                        // so the reducer will not blow these up unnecessarily.
                        int origVarCounter = _varCounter;

                        simplifiedNodes.Clear();
                        SimplifyNode(node, !first, simplifiedNodes);

                        foreach (SyntaxNode candidateNode in simplifiedNodes)
                        {
                            CompilationUnitSyntax candidate = Reduced.ReplaceNode(node, candidateNode);
                            if (isInteresting(candidate))
                            {
                                Reduced = candidate;
                                return(true);
                            }
                        }

                        _varCounter = origVarCounter;
                    }

                    return(false);
                }
            }

            List <SyntaxTrivia> outputComments = GetOutputComments(debug, release).Select(Comment).ToList();

            SimplifyRuntime();
            double           oldSizeKiB = Original.NormalizeWhitespace().ToString().Length / 1024.0;
            double           newSizeKiB = Reduced.NormalizeWhitespace().ToString().Length / 1024.0;
            SyntaxTriviaList newTrivia  =
                originalTrivia.Add(Comment(FormattableString.Invariant($"// Reduced from {oldSizeKiB:F1} KiB to {newSizeKiB:F1} KiB")))
                .AddRange(outputComments);

            Reduced = Reduced.WithLeadingTrivia(newTrivia);

            return(Reduced);
        }