3

While testing this related bug, I noticed that trying to make a link to a URL (technically, an IRI) using raw Markdown link syntax crashed the Markdown editor hard, permanently disabling Markdown preview until the page is reloaded(!).

Steps to reproduce:

  1. Paste the following string into the Markdown editor (outside a code block):

    [](https://en.wikipedia.org/wiki/😃)
    
  2. Observe that the preview pane freezes, and no longer updates (even if you remove the link).

The cause of this crash is the same as for the other bug, i.e. trying to URL-encode individual halves of a UTF-16 surrogate pair, although it occurs in a different part of the code. Specifically, the crash happens in the sanitizeTag() function, in the following code:

return prefix + url.replace(/[^-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)*[\]$]/g, function (c) {
    anyChange = true;
    if (c == "'") // this is the only character that isn't in our whitelist and that is returned unchanged by encodeURIComponent()
        return "%27";
    else
        return encodeURIComponent(c);

});

Note that, even if the regexp is fixed to correctly match UTF-16 surrogate pairs as single characters, a crash might still be triggered by pasting in actual mismatched surrogates. While these are not valid Unicode, we probably should handle them more gracefully than by crashing the editor.

Also, I have not yet tested whether a similar problem also occurs in the server-side Markdown parsing code. If it does, that would be a much more serious issue.

1

Since crashing the editor is kind of a bad thing (even if it's only on the client), I would recommend a two-part fix for this bug:

  1. Fix the regexp so that it doesn't try to split surrogate pairs apart, e.g. like this:

    return prefix + url.replace(/[^-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)*[\]$]+/g, function (c) {
        anyChange = true;
        return encodeURIComponent(c).replace(/'/g, "%27");
    });
    

    (Note the + added to the end of the regexp.)

  2. To defend against actual malformed input, catch any errors that might be thrown and treat them as sanitization failures (i.e. return an empty string):

    try {
        var encoded = tag.replace(/^(<a href="|<img src=")([^"]*)/i, function (wholematch, prefix, url) {
            return prefix + url.replace(/[^-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)*[\]$]+/g, function (c) {
                anyChange = true;
                return encodeURIComponent(c).replace(/'/g, "%27");
            });
        });
    } catch (e) {
        // encodeURIComponent() can throw a URIError on malformed Unicode input
        console.log(e);
        return "";
    }
    
0

For science, let me see what happens if I submit an answer containing a URL with emoji in it. Of course, the editor preview pane has crashed by now, but I should still be able to submit this.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .