From 61c40f408fd327e1157bda264422b10f715d6533 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 21 Jun 2026 01:34:38 +0000 Subject: [PATCH 1/3] Initial plan From d2ec36f419e7356f788e7736f2c36c266607ff86 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 21 Jun 2026 01:47:28 +0000 Subject: [PATCH 2/3] Fix thread-safety in SyntaxHighlighter: serialize TokenizeLine under grammarLock --- .../Rendering/SyntaxHighlighter.cs | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/MarpToPptx.Pptx/Rendering/SyntaxHighlighter.cs b/src/MarpToPptx.Pptx/Rendering/SyntaxHighlighter.cs index 14a96b4..049ca1c 100644 --- a/src/MarpToPptx.Pptx/Rendering/SyntaxHighlighter.cs +++ b/src/MarpToPptx.Pptx/Rendering/SyntaxHighlighter.cs @@ -37,10 +37,11 @@ public static class SyntaxHighlighter // Lazy so the registry is only initialised when syntax highlighting is first needed. private static readonly Lazy _state = new(CreateState); - // TextMateSharp's Registry/SyncRegistry is not thread-safe: concurrent - // LoadGrammar calls for the same scope can race on Dictionary.Add and - // throw "An item with the same key has already been added". Serialize - // grammar loading through this lock. + // TextMateSharp's Registry/SyncRegistry and Grammar instances are not + // thread-safe. Concurrent LoadGrammar calls for the same scope can race + // on Dictionary.Add, and concurrent TokenizeLine calls on the same Grammar + // instance can corrupt its lazy-compiled pattern cache. Serialize all + // registry and grammar operations through this lock. private static readonly object _grammarLock = new(); /// Returns true when has grammar support. @@ -75,14 +76,13 @@ public static IReadOnlyList> Tokenize(string languag var scopeName = state.Options.GetScopeByLanguageId(canonicalId); if (scopeName is not null) { - IGrammar? grammar; lock (_grammarLock) { - grammar = state.Registry.LoadGrammar(scopeName); - } - if (grammar is not null) - { - return TokenizeWithGrammar(code, grammar, state.Theme); + var grammar = state.Registry.LoadGrammar(scopeName); + if (grammar is not null) + { + return TokenizeWithGrammar(code, grammar, state.Theme); + } } } } @@ -99,6 +99,11 @@ private static IReadOnlyList> TokenizeWithGrammar(st foreach (var line in lines) { var lineResult = grammar.TokenizeLine(new LineText(line), ruleStack, TimeSpan.FromSeconds(5)); + if (lineResult is null) + { + result.Add([new TokenizedRun(line, null)]); + continue; + } ruleStack = lineResult.RuleStack; result.Add(BuildRuns(line, lineResult.Tokens, theme)); } From d87dd43e9cfdc0a498e552cd35ac01124358c0c0 Mon Sep 17 00:00:00 2001 From: Jon Galloway Date: Sun, 21 Jun 2026 00:19:30 -0700 Subject: [PATCH 3/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/MarpToPptx.Pptx/Rendering/SyntaxHighlighter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/MarpToPptx.Pptx/Rendering/SyntaxHighlighter.cs b/src/MarpToPptx.Pptx/Rendering/SyntaxHighlighter.cs index 049ca1c..0b0bd6f 100644 --- a/src/MarpToPptx.Pptx/Rendering/SyntaxHighlighter.cs +++ b/src/MarpToPptx.Pptx/Rendering/SyntaxHighlighter.cs @@ -101,6 +101,7 @@ private static IReadOnlyList> TokenizeWithGrammar(st var lineResult = grammar.TokenizeLine(new LineText(line), ruleStack, TimeSpan.FromSeconds(5)); if (lineResult is null) { + ruleStack = null; result.Add([new TokenizedRun(line, null)]); continue; }