Beispiel #1
0
        private IEnumerable <string> GetOutputComments(CompileResult ogDebugCompile, CompileResult ogRelCompile)
        {
            if (ogDebugCompile.RoslynException != null)
            {
                yield return($"// Roslyn throws '{ogDebugCompile.RoslynException.GetType()}' when compiling in debug");

                yield break;
            }
            if (ogRelCompile.RoslynException != null)
            {
                yield return($"// Roslyn throws '{ogRelCompile.RoslynException.GetType()}' when compiling in release");

                yield break;
            }

            if (ogDebugCompile.CompileErrors.Length > 0 || ogRelCompile.CompileErrors.Length > 0)
            {
                CSharpCompilationOptions compileOpts =
                    ogDebugCompile.CompileErrors.Length >= 0 ? Compiler.DebugOptions : Compiler.ReleaseOptions;

                CompileResult result = Compiler.Compile(Reduced.NormalizeWhitespace(), compileOpts);
                yield return($"// Roslyn gives '{result.CompileErrors[0]}'");

                yield break;
            }

            ProgramPairResults results = CompileAndRun(Reduced);

            yield return($"// Debug: {FormatResult(results.DebugResult, results.DebugFirstUnmatch)}");

            yield return($"// Release: {FormatResult(results.ReleaseResult, results.ReleaseFirstUnmatch)}");

            string FormatResult(ProgramResult result, ChecksumSite unmatch)
            {
                if (results.DebugResult.ExceptionType != null ||
                    results.ReleaseResult.ExceptionType != null)
                {
                    if (result.ExceptionType != null)
                    {
                        return($"Throws '{result.ExceptionType}'");
                    }

                    return("Runs successfully");
                }

                if (results.DebugResult.ChecksumSites.Count != results.ReleaseResult.ChecksumSites.Count)
                {
                    return($"Prints {result.ChecksumSites.Count} line(s)");
                }

                if (unmatch != null)
                {
                    return($"Outputs {unmatch.Value}");
                }

                return("");
            }
        }
Beispiel #2
0
        private static void RemoveFixedPrograms(FuzzlynOptions options, string dir)
        {
            string[]     files      = Directory.GetFiles(dir, "*.cs");
            List <ulong> toRereduce = new List <ulong>();

            for (int i = 0; i < files.Length; i++)
            {
                Console.Title = $"Processing {i + 1}/{files.Length}";

                string          contents = File.ReadAllText(files[i]);
                MatchCollection matches  = Regex.Matches(contents, "// Seed: ([0-9]+)");
                if (matches.Count != 1)
                {
                    continue;
                }

                ulong seed = ulong.Parse(matches[0].Groups[1].Value);
                options.Seed = seed;
                var cg = new CodeGenerator(options);
                CompilationUnitSyntax original = cg.GenerateProgram(false);

                CompileResult debug   = Compiler.Compile(original, Compiler.DebugOptions);
                CompileResult release = Compiler.Compile(original, Compiler.ReleaseOptions);

                if (debug.CompileErrors.Length > 0 || release.CompileErrors.Length > 0)
                {
                    continue;
                }

                if (debug.RoslynException != null || release.RoslynException != null)
                {
                    continue;
                }

                ProgramPairResults execResults = ProgramExecutor.RunPair(new ProgramPair(debug.Assembly, release.Assembly));
                if (execResults.DebugResult.Checksum != execResults.ReleaseResult.Checksum ||
                    execResults.DebugResult.ExceptionType != execResults.ReleaseResult.ExceptionType)
                {
                    // Execute the reduced form to see if we get interesting behavior.
                    // Otherwise we may need to rereduce it.
                    if (!IsReducedVersionInteresting(execResults, contents))
                    {
                        toRereduce.Add(seed);
                        Console.WriteLine("Marking {0} for rereduction", Path.GetFileName(files[i]));
                    }

                    continue;
                }

                Console.WriteLine("Removing {0}", Path.GetFileName(files[i]));
                File.Delete(files[i]);
            }

            const string rereduceFile = "Rereduce_required.txt";

            File.WriteAllText(rereduceFile, string.Join(Environment.NewLine, toRereduce));
            Console.WriteLine("Wrote {0} seeds to be rereduced to '{1}'", toRereduce.Count, Path.GetFullPath(rereduceFile));
        }
Beispiel #3
0
        /// <summary>
        /// Checks if a reduced version (on disk) is interesting by running it and checking for exceptions
        /// and output. Output is captured by redirecting stdout during executiong.
        private static bool IsReducedVersionInteresting(ProgramPairResults fullResults, string code)
        {
            CompilationUnitSyntax comp = ParseCompilationUnit(code);

            var debug   = Execute(Compiler.DebugOptions);
            var release = Execute(Compiler.ReleaseOptions);

            if (fullResults.DebugResult.ExceptionType != fullResults.ReleaseResult.ExceptionType)
            {
                return(debug.exceptionType == fullResults.DebugResult.ExceptionType &&
                       release.exceptionType == fullResults.ReleaseResult.ExceptionType);
            }

            return(debug.stdout != release.stdout);

            (string stdout, string exceptionType) Execute(CSharpCompilationOptions opts)
            {
                CompileResult result = Compiler.Compile(comp, opts);

                Trace.Assert(result.Assembly != null);

                Assembly   asm            = Assembly.Load(result.Assembly);
                MethodInfo mainMethodInfo = asm.GetType("Program").GetMethod("Main");
                Action     entryPoint     = (Action)Delegate.CreateDelegate(typeof(Action), mainMethodInfo);

                Exception  ex      = null;
                TextWriter origOut = Console.Out;

                MemoryStream ms = new MemoryStream();
                StreamWriter sw = new StreamWriter(ms, Encoding.UTF8);

                try
                {
                    Console.SetOut(sw);
                    entryPoint();
                }
                catch (Exception caughtEx)
                {
                    ex = caughtEx;
                }
                finally
                {
                    Console.SetOut(origOut);
                    sw.Close();
                }

                string stdout = Encoding.UTF8.GetString(ms.ToArray());

                return(stdout, ex?.GetType().FullName);
            }
        }
Beispiel #4
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 #5
0
        private IEnumerable <string> GetOutputComments(CompileResult ogDebugCompile, CompileResult ogRelCompile)
        {
            if (ogDebugCompile.RoslynException != null)
            {
                yield return($"// Roslyn throws '{ogDebugCompile.RoslynException.GetType()}' when compiling in debug");

                yield break;
            }
            if (ogRelCompile.RoslynException != null)
            {
                yield return($"// Roslyn throws '{ogRelCompile.RoslynException.GetType()}' when compiling in release");

                yield break;
            }

            ProgramPairResults results = CompileAndRun(Reduced);

            yield return($"// Debug: {FormatResult(results.DebugResult, results.DebugFirstUnmatch)}");

            yield return($"// Release: {FormatResult(results.ReleaseResult, results.ReleaseFirstUnmatch)}");

            string FormatResult(ProgramResult result, ChecksumSite unmatch)
            {
                if (results.DebugResult.ExceptionType != null ||
                    results.ReleaseResult.ExceptionType != null)
                {
                    if (result.ExceptionType != null)
                    {
                        return($"Throws '{result.ExceptionType}'");
                    }

                    return("Runs successfully");
                }

                if (results.DebugResult.ChecksumSites.Count != results.ReleaseResult.ChecksumSites.Count)
                {
                    return($"Prints {result.ChecksumSites.Count} line(s)");
                }

                if (unmatch != null)
                {
                    return($"Outputs {unmatch.Value}");
                }

                return("");
            }
        }
Beispiel #6
0
        private static void RemoveFixedPrograms(FuzzlynOptions options, string dir)
        {
            const string rereduceFile = "Rereduce_required.txt";

            string[] files = Directory.GetFiles(dir, "*.cs").OrderBy(p => p.ToLowerInvariant()).ToArray();
            for (int i = 0; i < files.Length; i++)
            {
                Console.Title = $"Processing {i + 1}/{files.Length}";

                string          contents = File.ReadAllText(files[i]);
                MatchCollection matches  = Regex.Matches(contents, "// Seed: ([0-9]+)");
                if (matches.Count != 1)
                {
                    continue;
                }

                ulong seed = ulong.Parse(matches[0].Groups[1].Value);
                Console.Write("Processing {0}: ", seed);

                options.Seed = seed;
                var cg = new CodeGenerator(options);
                CompilationUnitSyntax original = cg.GenerateProgram();

                CompileResult debug   = Compiler.Compile(original, Compiler.DebugOptions);
                CompileResult release = Compiler.Compile(original, Compiler.ReleaseOptions);

                if (debug.CompileErrors.Length > 0 || release.CompileErrors.Length > 0)
                {
                    Console.WriteLine("Compiler error");
                    continue;
                }

                if (debug.RoslynException != null || release.RoslynException != null)
                {
                    Console.WriteLine("Compiler exception");
                    continue;
                }

                ProgramPairResults execResults = ProgramExecutor.RunSeparately(
                    new List <ProgramPair> {
                    new ProgramPair(false, debug.Assembly, release.Assembly)
                })
                                                 ?.Single();

                if (execResults == null)
                {
                    Console.WriteLine("Crashed sub-process, still interesting");
                    continue;
                }

                if (execResults.DebugResult.Checksum != execResults.ReleaseResult.Checksum ||
                    execResults.DebugResult.ExceptionType != execResults.ReleaseResult.ExceptionType)
                {
                    // Execute the reduced form to see if we get interesting behavior.
                    // Otherwise we may need to rereduce it.
                    // HOAX: Currently IsReducedVersionInteresting runs the programs
                    // in our own process, so we are conservative and do not run programs
                    // that may crash us (it is possible that the unreduced example does not
                    // crash, but that the reduced does.
                    if (contents.Contains("Crashes the runtime") || IsReducedVersionInteresting(execResults, contents))
                    {
                        Console.WriteLine("Still interesting");
                    }
                    else
                    {
                        File.AppendAllText(rereduceFile, seed + Environment.NewLine);
                        Console.WriteLine("Marked for rereduction");
                    }

                    continue;
                }

                Console.WriteLine("Deleted, no longer interesting");
                File.Delete(files[i]);
            }
        }
Beispiel #7
0
 public RunSeparatelyResults(RunSeparatelyResultsKind kind, ProgramPairResults results, string crashError)
 {
     Kind       = kind;
     Results    = results;
     CrashError = crashError;
 }
Beispiel #8
0
    public static void Main(string[] args)
    {
        const int stackSize = 64 * 1024 * 1024;
        Thread    thread    = new(() =>
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                // Prevent post-mortem debuggers from launching here. We get
                // runtime crashes sometimes and the parent Fuzzlyn process will
                // handle it.
                SetErrorMode(ErrorModes.SEM_NOGPFAULTERRORBOX);
            }

            Func <string> readLine;
            if (args.Length > 0)
            {
                string[] lines = File.ReadAllLines(args[0]);
                int index = 0;
                readLine = () => index >= lines.Length ? null : lines[index++];
            }
            else
            {
                readLine = Console.ReadLine;
            }

            AssemblyLoadContext currentAlc = new ServerAssemblyLoadContext();
            int currentRunsInAlc = 0;
            while (true)
            {
                string line = readLine();
                if (line == null)
                {
                    return;
                }

                Request req = JsonSerializer.Deserialize <Request>(line);
                Response resp;
                switch (req.Kind)
                {
                case RequestKind.RunPair:
                    ProgramPairResults results = RunPairAsync(currentAlc, req.Pair);
                    currentRunsInAlc++;
                    resp = new Response
                    {
                        RunPairResult = results
                    };
                    break;

                case RequestKind.Shutdown:
                    resp = new Response();
                    break;

                default:
                    return;
                }

                Console.WriteLine(JsonSerializer.Serialize(resp));
                if (req.Kind == RequestKind.Shutdown)
                {
                    return;
                }

                if (currentRunsInAlc > 100)
                {
                    currentAlc.Unload();
                    currentAlc = new ServerAssemblyLoadContext();
                    currentRunsInAlc = 0;
                }
            }
        }, stackSize);

        thread.Start();
        thread.Join();
    }
Beispiel #9
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);
        }