Skip to content

Race condition for async parsing when hooks are present #3836

@jonatanschroeder

Description

@jonatanschroeder

Marked version:

16.4.1

Describe the bug

When multiple parsing operations happen in parallel, with one for regular block parsing and one inline, the indication if parsing is block or inline can bleed between the calls. In my tests this happens when a hook is present.

To Reproduce
Steps to reproduce the behavior:

import { Marked } from 'marked';

const marked = new Marked();
marked.use({ hooks: { postprocess: (html) => html.replaceAll('this', 'THIS') } });

console.log(
  await Promise.all([
    marked.parseInline('this is inline before block', { async: true }),
    marked.parse('this is block after inline', { async: true }),
  ]),
);

console.log(
  await Promise.all([
    marked.parse('this is block before inline', { async: true }),
    marked.parseInline('this is inline after block', { async: true }),
  ]),
);

In the code above, Promise.all will cause both instances in each group to run in "parallel" (notwithstanding the event loop), so the second parse operation will start before the previous one ended.

This results in:

[
  '<p>THIS is inline before block</p>\n',
  '<p>THIS is block after inline</p>\n'
]
[ 'THIS is block before inline', 'THIS is inline after block' ]

Note that the code had one inline and one block parsing in each group, but in both cases the inline/block parsing caused both instances to have the same inline/block setting.

Expected behavior

[ 'THIS is inline before block', '<p>THIS is block after inline</p>\n' ]
[ '<p>THIS is block before inline</p>\n', 'THIS is inline after block' ]

Metadata

Metadata

Assignees

No one assigned

    Labels

    L2 - annoyingSimilar to L1 - broken but there is a known workaround available for the issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions