Skip to content

Commit

Permalink
Add a COMPlus variable to throw runtime exception on JIT asserts (dot…
Browse files Browse the repository at this point in the history
…net#60631)

Add COMPlus_JitThrowOnAssertionFailure: if nonzero, the runtime will
throw an InvalidProgramException with the assertion message if a JIT
assert is hit during compilation. Previously this would bring down the
process. Use this from the Fuzzlyn pipeline scripts to reduce examples
that hit JIT asserts automatically, since this can now be done much more
efficiently.
  • Loading branch information
jakobbotsch authored Oct 24, 2021
1 parent 63d9790 commit 3e94696
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 7 deletions.
1 change: 1 addition & 0 deletions src/coreclr/inc/clrconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ CONFIG_DWORD_INFO(INTERNAL_JitDebuggable, W("JitDebuggable"), 0, "")
#endif
RETAIL_CONFIG_DWORD_INFO(INTERNAL_JitEnableNoWayAssert, W("JitEnableNoWayAssert"), INTERNAL_JitEnableNoWayAssert_Default, "")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_JitFramed, W("JitFramed"), 0, "Forces EBP frames")
CONFIG_DWORD_INFO(INTERNAL_JitThrowOnAssertionFailure, W("JitThrowOnAssertionFailure"), 0, "Throw managed exception on assertion failures during JIT instead of crashing the process")
CONFIG_DWORD_INFO(INTERNAL_JitGCStress, W("JitGCStress"), 0, "GC stress mode for jit")
CONFIG_DWORD_INFO(INTERNAL_JitHeartbeat, W("JitHeartbeat"), 0, "")
CONFIG_DWORD_INFO(INTERNAL_JitHelperLogging, W("JitHelperLogging"), 0, "")
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/scripts/azdo_pipelines_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ def run_command(command_to_run, _cwd=None, _exit_on_fail=False, _output_file=Non
if proc.poll() is not None:
break
if output:
output_str = output.strip().decode("utf-8") + "\n"
output_str = output.strip().decode("utf-8")
print(output_str)
of.write(output_str)
of.write(output_str + "\n")
else:
command_stdout, command_stderr = proc.communicate()
if len(command_stdout) > 0:
Expand Down
32 changes: 32 additions & 0 deletions src/coreclr/scripts/fuzzlyn_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@
import argparse
import json
import os
import re
import shutil
import threading
from azdo_pipelines_util import run_command, TempDir
from coreclr_arguments import *
from os import path

jit_assert_regex = re.compile(r"Assertion failed '(.*)' in '.*' during '(.*)'")

parser = argparse.ArgumentParser(description="description")

parser.add_argument("-run_configuration", help="RunConfiguration")
Expand Down Expand Up @@ -79,6 +82,22 @@ def setup_args(args):

return coreclr_args

def extract_jit_assertion_error(text):
""" Extract a JIT assertion error
Args:
text (string): The text that might contain an assertion
Returns:
The assertion as a string, or None if no assertion error is in the text.
"""

issue_match = re.search(jit_assert_regex, text)
if issue_match is not None:
assert_string = " ".join(issue_match.groups())
return assert_string.strip()

return None

class ReduceExamples(threading.Thread):
def __init__(self, examples_file, examples_dir, fuzzlyn_path, host_path, exit_evt):
super(ReduceExamples, self).__init__()
Expand All @@ -87,6 +106,7 @@ def __init__(self, examples_file, examples_dir, fuzzlyn_path, host_path, exit_ev
self.fuzzlyn_path = fuzzlyn_path
self.host_path = host_path
self.exit_evt = exit_evt
self.reduced_jit_asserts = set()

def run(self):
num_reduced = 0
Expand All @@ -103,7 +123,16 @@ def run(self):
# We will still report crashes, just not with a reduced example.
if evt["Kind"] == "ExampleFound":
ex = evt["Example"]
ex_assert_err = None

reduce_this = False
if ex["Kind"] == "BadResult":
reduce_this = True
elif ex["Kind"] == "HitsJitAssert":
ex_assert_err = extract_jit_assertion_error(ex["Message"])
reduce_this = ex_assert_err is not None and ex_assert_err not in self.reduced_jit_asserts

if reduce_this:
print("Reducing {}".format(ex['Seed']))
output_path = path.join(self.examples_dir, str(ex["Seed"]) + ".cs")
cmd = [self.fuzzlyn_path,
Expand All @@ -118,6 +147,9 @@ def run(self):
print("Skipping reduction of remaining examples (reached limit of 5)")
return

if ex_assert_err is not None:
self.reduced_jit_asserts.add(ex_assert_err)


def main(main_args):
"""Main entrypoint
Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/scripts/fuzzlyn_summarize.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ def seed_from_internal_zip_path(path):
continue

unreduced_examples.append(example)
if example['Kind'] == "Crash":
assertion_error = extract_assertion_error(example['CrashError'])
if example['Kind'] == "Crash" or example['Kind'] == "HitsJitAssert":
assertion_error = extract_assertion_error(example['Message'])
if assertion_error:
crashes_by_assert[assertion_error].append(example)
else:
Expand Down Expand Up @@ -206,7 +206,7 @@ def seed_from_internal_zip_path(path):
if len(examples) > 1:
f.write("Example occurence:\n")
f.write("```scala\n")
f.write(examples[0]['CrashError'].strip() + "\n")
f.write(examples[0]['Message'].strip() + "\n")
f.write("```\n")
f.write("Affected seeds{}:\n".format(" (10 shown)" if len(examples) > 10 else ""))
f.write("\n".join("* `" + str(ex['Seed']) + "`" for ex in sorted(examples[:10], key=lambda ex: ex['Seed'])))
Expand All @@ -216,9 +216,9 @@ def seed_from_internal_zip_path(path):
f.write("# {} uncategorized/unreduced examples remain\n".format(len(remaining)))
for ex in remaining:
f.write("* `{}`: {}\n".format(ex['Seed'], ex['Kind']))
if ex['CrashError'] and len(ex['CrashError'].strip()) > 0:
if ex['Message'] and len(ex['Message'].strip()) > 0:
f.write("```scala\n")
f.write(ex['CrashError'].strip() + "\n")
f.write(ex['Message'].strip() + "\n")
f.write("```\n")

f.write("\n")
Expand Down
11 changes: 11 additions & 0 deletions src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10514,6 +10514,17 @@ int CEEInfo::doAssert(const char* szFile, int iLine, const char* szExpr)

#ifdef _DEBUG
BEGIN_DEBUG_ONLY_CODE;
if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitThrowOnAssertionFailure) != 0)
{
SString output;
output.Printf(
W("JIT assert failed:\n")
W("%hs\n")
W(" File: %hs Line: %d\n"),
szExpr, szFile, iLine);
COMPlusThrowNonLocalized(kInvalidProgramException, output.GetUnicode());
}

result = _DbgBreakCheck(szFile, iLine, szExpr);
END_DEBUG_ONLY_CODE;
#else // !_DEBUG
Expand Down

0 comments on commit 3e94696

Please sign in to comment.