bpo-37069: regrtest uses sys.unraisablehook (GH-13759)

regrtest now uses sys.unraisablehook() to mark a test as "environment
altered" (ENV_CHANGED) if it emits an "unraisable exception".
Moreover, regrtest logs a warning in this case.

Use "python3 -m test --fail-env-changed" to catch unraisable
exceptions in tests.
diff --git a/Lib/test/libregrtest/setup.py b/Lib/test/libregrtest/setup.py
index fb5ac35..36676bf 100644
--- a/Lib/test/libregrtest/setup.py
+++ b/Lib/test/libregrtest/setup.py
@@ -10,6 +10,8 @@
 except ImportError:
     gc = None
 
+from test.libregrtest.utils import setup_unraisable_hook
+
 
 def setup_tests(ns):
     try:
@@ -93,6 +95,8 @@
             pass
         sys.addaudithook(_test_audit_hook)
 
+    setup_unraisable_hook()
+
 
 def suppress_msvcrt_asserts(verbose):
     try:
diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py
index fb9971a..2691a2c 100644
--- a/Lib/test/libregrtest/utils.py
+++ b/Lib/test/libregrtest/utils.py
@@ -2,6 +2,7 @@
 import os.path
 import sys
 import textwrap
+from test import support
 
 
 def format_duration(seconds):
@@ -59,3 +60,19 @@
 
 def print_warning(msg):
     print(f"Warning -- {msg}", file=sys.stderr, flush=True)
+
+
+orig_unraisablehook = None
+
+
+def regrtest_unraisable_hook(unraisable):
+    global orig_unraisablehook
+    support.environment_altered = True
+    print_warning("Unraisable exception")
+    orig_unraisablehook(unraisable)
+
+
+def setup_unraisable_hook():
+    global orig_unraisablehook
+    orig_unraisablehook = sys.unraisablehook
+    sys.unraisablehook = regrtest_unraisable_hook