Thankfully this was a lot easier than tracing hiwire keys. 

I located one actual leak: if an error is thrown during `to_js` it would forget to free `proxies`. Other than that, I fixed a few "dumb leaks" in `api.js` where we leak the methods like `eval_code` or `find_imports`. So the code was already in surprisingly good shape in this way.

It's still possible that we leak some Python objects somehow, but this is as good as we can do for systematic checks short of compiling Python itself with `TRACE_MALLOC`.
Eliminate pyproxy leaks. Thankfully this was a lot easier than tracing hiwire keys. 

I located one actual leak: if an error is thrown during `to_js` it would forget to free `proxies`. Other than that, I fixed a few "dumb leaks" in `api.js` where we leak the methods like `eval_code` or `find_imports`. So the code was already in surprisingly good shape in this way.

It's still possible that we leak some Python objects somehow, but this is as good as we can do for systematic checks short of compiling Python itself with `TRACE_MALLOC`.
From 0eb0ea9aeb5a5cfdceb35547dd1a97d73914338b Mon Sep 17 00:00:00 2001
From: Michael Droettboom <mdboom@gmail.com>
Date: Sun, 5 Jul 2020 19:56:47 +0200
Subject: [PATCH] testing


diff --git a/Lib/platform.py b/Lib/platform.py
index 6fbb7b08c5..d46425659d 100755
--- a/Lib/platform.py
+++ b/Lib/platform.py
@@ -604,7 +604,7 @@ def _syscmd_uname(option, default=''):
 
     """ Interface to the system's uname command.
     """
-    if sys.platform in ('dos', 'win32', 'win16'):
+    if sys.platform in ('dos', 'win32', 'win16', 'emscripten'):
         # XXX Others too ?
         return default
 
@@ -626,7 +626,7 @@ def _syscmd_file(target, default=''):
         default in case the command should fail.
 
     """
-    if sys.platform in ('dos', 'win32', 'win16'):
+    if sys.platform in ('dos', 'win32', 'win16', 'emscripten'):
         # XXX Others too ?
         return default
 
diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py
index 76ad3359f2..b135966032 100644
--- a/Lib/test/libregrtest/main.py
+++ b/Lib/test/libregrtest/main.py
@@ -635,7 +635,9 @@ class Regrtest:
         except SystemExit as exc:
             # bpo-38203: Python can hang at exit in Py_Finalize(), especially
             # on threading._shutdown() call: put a timeout
-            faulthandler.dump_traceback_later(EXIT_TIMEOUT, exit=True)
+
+            # Skipping, pyodide doesn't support threading.
+            # faulthandler.dump_traceback_later(EXIT_TIMEOUT, exit=True)
 
             sys.exit(exc.code)
 
diff --git a/Lib/test/support/script_helper.py b/Lib/test/support/script_helper.py
index 83519988e3..1410fe5c61 100644
--- a/Lib/test/support/script_helper.py
+++ b/Lib/test/support/script_helper.py
@@ -9,6 +9,7 @@ import os.path
 import subprocess
 import py_compile
 import zipfile
+import unittest
 
 from importlib.util import source_from_cache
 from test.support import make_legacy_pyc, strip_python_stderr
@@ -34,6 +35,8 @@ def interpreter_requires_environment():
     situation.  PYTHONPATH or PYTHONUSERSITE are other common environment
     variables that might impact whether or not the interpreter can start.
     """
+    raise unittest.SkipTest('no subprocess')
+
     global __cached_interp_requires_environment
     if __cached_interp_requires_environment is None:
         # If PYTHONHOME is set, assume that we need it
@@ -172,6 +175,8 @@ def spawn_python(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw):
     kw is extra keyword args to pass to subprocess.Popen. Returns a Popen
     object.
     """
+    raise unittest.SkipTest("no subprocess")
+
     cmd_line = [sys.executable]
     if not interpreter_requires_environment():
         cmd_line.append('-E')
diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py
index ab8677199f..8eefd57776 100644
--- a/Lib/test/test_cgi.py
+++ b/Lib/test/test_cgi.py
@@ -188,6 +188,7 @@ Content-Length: 3
                         self.assertEqual(fs.getvalue(key), expect_val[0])
 
     def test_log(self):
+        raise unittest.SkipTest('known pyodide failure')
         cgi.log("Testing")
 
         cgi.logfp = StringIO()
diff --git a/Lib/test/test_fcntl.py b/Lib/test/test_fcntl.py
index c394f6945a..2ec020bd08 100644
--- a/Lib/test/test_fcntl.py
+++ b/Lib/test/test_fcntl.py
@@ -155,6 +155,7 @@ class TestFcntl(unittest.TestCase):
 
     @unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError")
     def test_lockf_exclusive(self):
+        raise unittest.SkipTest('threading not supported')
         self.f = open(TESTFN, 'wb+')
         cmd = fcntl.LOCK_EX | fcntl.LOCK_NB
         fcntl.lockf(self.f, cmd)
@@ -166,6 +167,7 @@ class TestFcntl(unittest.TestCase):
 
     @unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError")
     def test_lockf_share(self):
+        raise unittest.SkipTest('threading not supported')
         self.f = open(TESTFN, 'wb+')
         cmd = fcntl.LOCK_SH | fcntl.LOCK_NB
         fcntl.lockf(self.f, cmd)
diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py
index 646828621a..b9663082b9 100644
--- a/Lib/test/test_gzip.py
+++ b/Lib/test/test_gzip.py
@@ -731,6 +731,7 @@ class TestCommandLine(unittest.TestCase):
     data = b'This is a simple test with gzip'
 
     def test_decompress_stdin_stdout(self):
+        raise unittest.SkipTest('no subprocess')
         with io.BytesIO() as bytes_io:
             with gzip.GzipFile(fileobj=bytes_io, mode='wb') as gzip_file:
                 gzip_file.write(self.data)
@@ -767,6 +768,7 @@ class TestCommandLine(unittest.TestCase):
 
     @create_and_remove_directory(TEMPDIR)
     def test_compress_stdin_outfile(self):
+        raise unittest.SkipTest('no subprocess')
         args = sys.executable, '-m', 'gzip'
         with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc:
             out, err = proc.communicate(self.data)
diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py
index eaa6197bec..95ff99d15c 100644
--- a/Lib/test/test_itertools.py
+++ b/Lib/test/test_itertools.py
@@ -1511,6 +1511,7 @@ class TestBasicOps(unittest.TestCase):
             next(a)
 
     def test_tee_concurrent(self):
+        raise unittest.SkipTest('threading not supported')
         start = threading.Event()
         finish = threading.Event()
         class I:
-- 
2.25.1


From 0eb0ea9aeb5a5cfdceb35547dd1a97d73914338b Mon Sep 17 00:00:00 2001
From: Michael Droettboom <mdboom@gmail.com>
Date: Sun, 5 Jul 2020 19:56:47 +0200
Subject: [PATCH] testing


diff --git a/Lib/platform.py b/Lib/platform.py
index 6fbb7b08c5..d46425659d 100755
--- a/Lib/platform.py
+++ b/Lib/platform.py
@@ -604,7 +604,7 @@ def _syscmd_uname(option, default=''):
 
     """ Interface to the system's uname command.
     """
-    if sys.platform in ('dos', 'win32', 'win16'):
+    if sys.platform in ('dos', 'win32', 'win16', 'emscripten'):
         # XXX Others too ?
         return default
 
@@ -626,7 +626,7 @@ def _syscmd_file(target, default=''):
         default in case the command should fail.
 
     """
-    if sys.platform in ('dos', 'win32', 'win16'):
+    if sys.platform in ('dos', 'win32', 'win16', 'emscripten'):
         # XXX Others too ?
         return default
 
diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py
index 76ad3359f2..b135966032 100644
--- a/Lib/test/libregrtest/main.py
+++ b/Lib/test/libregrtest/main.py
@@ -635,7 +635,9 @@ class Regrtest:
         except SystemExit as exc:
             # bpo-38203: Python can hang at exit in Py_Finalize(), especially
             # on threading._shutdown() call: put a timeout
-            faulthandler.dump_traceback_later(EXIT_TIMEOUT, exit=True)
+
+            # Skipping, pyodide doesn't support threading.
+            # faulthandler.dump_traceback_later(EXIT_TIMEOUT, exit=True)
 
             sys.exit(exc.code)
 
diff --git a/Lib/test/support/script_helper.py b/Lib/test/support/script_helper.py
index 83519988e3..1410fe5c61 100644
--- a/Lib/test/support/script_helper.py
+++ b/Lib/test/support/script_helper.py
@@ -9,6 +9,7 @@ import os.path
 import subprocess
 import py_compile
 import zipfile
+import unittest
 
 from importlib.util import source_from_cache
 from test.support import make_legacy_pyc, strip_python_stderr
@@ -34,6 +35,8 @@ def interpreter_requires_environment():
     situation.  PYTHONPATH or PYTHONUSERSITE are other common environment
     variables that might impact whether or not the interpreter can start.
     """
+    raise unittest.SkipTest('no subprocess')
+
     global __cached_interp_requires_environment
     if __cached_interp_requires_environment is None:
         # If PYTHONHOME is set, assume that we need it
@@ -172,6 +175,8 @@ def spawn_python(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw):
     kw is extra keyword args to pass to subprocess.Popen. Returns a Popen
     object.
     """
+    raise unittest.SkipTest("no subprocess")
+
     cmd_line = [sys.executable]
     if not interpreter_requires_environment():
         cmd_line.append('-E')
diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py
index ab8677199f..8eefd57776 100644
--- a/Lib/test/test_cgi.py
+++ b/Lib/test/test_cgi.py
@@ -188,6 +188,7 @@ Content-Length: 3
                         self.assertEqual(fs.getvalue(key), expect_val[0])
 
     def test_log(self):
+        raise unittest.SkipTest('known pyodide failure')
         cgi.log("Testing")
 
         cgi.logfp = StringIO()
diff --git a/Lib/test/test_fcntl.py b/Lib/test/test_fcntl.py
index c394f6945a..2ec020bd08 100644
--- a/Lib/test/test_fcntl.py
+++ b/Lib/test/test_fcntl.py
@@ -155,6 +155,7 @@ class TestFcntl(unittest.TestCase):
 
     @unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError")
     def test_lockf_exclusive(self):
+        raise unittest.SkipTest('threading not supported')
         self.f = open(TESTFN, 'wb+')
         cmd = fcntl.LOCK_EX | fcntl.LOCK_NB
         fcntl.lockf(self.f, cmd)
@@ -166,6 +167,7 @@ class TestFcntl(unittest.TestCase):
 
     @unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError")
     def test_lockf_share(self):
+        raise unittest.SkipTest('threading not supported')
         self.f = open(TESTFN, 'wb+')
         cmd = fcntl.LOCK_SH | fcntl.LOCK_NB
         fcntl.lockf(self.f, cmd)
diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py
index 646828621a..b9663082b9 100644
--- a/Lib/test/test_gzip.py
+++ b/Lib/test/test_gzip.py
@@ -731,6 +731,7 @@ class TestCommandLine(unittest.TestCase):
     data = b'This is a simple test with gzip'
 
     def test_decompress_stdin_stdout(self):
+        raise unittest.SkipTest('no subprocess')
         with io.BytesIO() as bytes_io:
             with gzip.GzipFile(fileobj=bytes_io, mode='wb') as gzip_file:
                 gzip_file.write(self.data)
@@ -767,6 +768,7 @@ class TestCommandLine(unittest.TestCase):
 
     @create_and_remove_directory(TEMPDIR)
     def test_compress_stdin_outfile(self):
+        raise unittest.SkipTest('no subprocess')
         args = sys.executable, '-m', 'gzip'
         with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc:
             out, err = proc.communicate(self.data)
diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py
index eaa6197bec..95ff99d15c 100644
--- a/Lib/test/test_itertools.py
+++ b/Lib/test/test_itertools.py
@@ -1511,6 +1511,7 @@ class TestBasicOps(unittest.TestCase):
             next(a)
 
     def test_tee_concurrent(self):
+        raise unittest.SkipTest('threading not supported')
         start = threading.Event()
         finish = threading.Event()
         class I:
-- 
2.25.1

