Wrote some crashtest for running against markdown files from pub.dev
diff --git a/pkgs/markdown/dart_test.yaml b/pkgs/markdown/dart_test.yaml
new file mode 100644
index 0000000..423fa52
--- /dev/null
+++ b/pkgs/markdown/dart_test.yaml
@@ -0,0 +1,6 @@
+tags:
+  crashtest:
+    skip: 'Only run crashtest tests manually with `dart test -P crashtest`'
+    presets:
+      crashtest:
+        skip: false # Don't skip when running in -P crashtest
diff --git a/pkgs/markdown/pubspec.yaml b/pkgs/markdown/pubspec.yaml
index 4a69ba5..660a558 100644
--- a/pkgs/markdown/pubspec.yaml
+++ b/pkgs/markdown/pubspec.yaml
@@ -21,9 +21,12 @@
   build_web_compilers: ^3.0.0
   collection: ^1.15.0
   html: ^0.15.0
+  http: ^0.13.5
   io: ^1.0.0
   js: ^0.6.3
   lints: ^2.0.0
   path: ^1.8.0
+  pool: ^1.5.1
+  tar: ^0.5.5+1
   test: ^1.16.0
   yaml: ^3.0.0
diff --git a/pkgs/markdown/test/crash_test.dart b/pkgs/markdown/test/crash_test.dart
new file mode 100644
index 0000000..b85cc97
--- /dev/null
+++ b/pkgs/markdown/test/crash_test.dart
@@ -0,0 +1,122 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:http/http.dart' as http;
+import 'package:http/retry.dart' as http;
+import 'package:markdown/markdown.dart';
+import 'package:pool/pool.dart';
+import 'package:tar/tar.dart';
+import 'package:test/test.dart';
+
+void main() async {
+  // This test is a really dumb and very slow crash-test.
+  // It downloads the latest package version for each package on pub.dev
+  // and tries to parse all `*.md` files in the package, counting the number
+  // of times where the parser throws.
+  //
+  // Needless to say, this test is very slow and running it eats a lot of CPU.
+  // But it's a fairly good way to try a lot of real-world markdown text to see
+  // if any of the poorly formatted markdown causes the parser to crash.
+  test(
+    'crash test',
+    () async {
+      final c = http.RetryClient(http.Client());
+      Future<dynamic> _getJson(String url) async {
+        final u = Uri.tryParse(url);
+        if (u == null) {
+          return null;
+        }
+        try {
+          final data = await c.read(u);
+          try {
+            return jsonDecode(data);
+          } on FormatException {
+            return null;
+          }
+        } on http.ClientException {
+          return null;
+        } on IOException {
+          return null;
+        }
+      }
+
+      final packages =
+          ((await _getJson('https://pub.dev/api/package-names'))['packages']
+                  as List)
+              .cast<String>();
+      print('Found ${packages.length} packages to scan');
+
+      final errors = <String>[];
+      final pool = Pool(50);
+      var count = 0;
+      var skipped = 0;
+      var lastStatus = DateTime.now();
+      await Future.wait(packages.map((package) async {
+        await pool.withResource(() async {
+          final versionsResponse =
+              await _getJson('https://pub.dev/api/packages/$package');
+          final archiveUrl = Uri.tryParse(
+            versionsResponse['latest']?['archive_url'] as String? ?? '',
+          );
+          if (archiveUrl == null) {
+            skipped++;
+            return;
+          }
+          late List<int> archive;
+          try {
+            archive = gzip.decode(await c.readBytes(archiveUrl));
+          } on http.ClientException {
+            skipped++;
+            return;
+          } on IOException {
+            skipped++;
+            return;
+          }
+          try {
+            await TarReader.forEach(Stream.value(archive), (entry) async {
+              if (entry.name.endsWith('.md')) {
+                late String str;
+                try {
+                  final bytes = await http.ByteStream(entry.contents).toBytes();
+                  str = utf8.decode(bytes);
+                } on FormatException {
+                  return; // ignore invalid utf8
+                }
+                try {
+                  markdownToHtml(str, extensionSet: ExtensionSet.gitHubWeb);
+                } catch (err, st) {
+                  errors
+                      .add('package:$package/${entry.name}, throws: $err\n$st');
+                }
+              }
+            });
+          } on FormatException {
+            skipped++;
+            return;
+          }
+        });
+        count++;
+        if (DateTime.now().difference(lastStatus) > Duration(seconds: 30)) {
+          lastStatus = DateTime.now();
+          print('Scanned $count / ${packages.length} (skipped $skipped),'
+              ' found ${errors.length} issues');
+        }
+      }));
+
+      await pool.close();
+      c.close();
+
+      if (errors.isNotEmpty) {
+        print('Found issues:');
+        errors.forEach(print);
+        fail('Found ${errors.length} cases where markdownToHtml threw!');
+      }
+    },
+    timeout: Timeout(Duration(hours: 1)),
+    tags: 'crashtest', // skipped by default, see: dart_test.yaml
+  );
+}