Bug 210086 - Use-after-move of Vector<ManipulationToken> in TextManipulationController::observeParagraphs()
Summary: Use-after-move of Vector<ManipulationToken> in TextManipulationController::ob...
Alias: None
Product: WebKit
Classification: Unclassified
Component: HTML Editing (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: David Kilzer (:ddkilzer)
Keywords: InRadar
Depends on:
Reported: 2020-04-06 17:52 PDT by David Kilzer (:ddkilzer)
Modified: 2020-04-10 09:42 PDT (History)
6 users (show)

See Also:

Patch v1 (1.95 KB, patch)
2020-04-06 17:54 PDT, David Kilzer (:ddkilzer)
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description David Kilzer (:ddkilzer) 2020-04-06 17:52:06 PDT
Use-after-move of Vector<ManipulationToken> in TextManipulationController::observeParagraphs().

This is not a security issue since the move constructor and the move assignment operator for WTF::Vector both do a swap().

This is to fix a clang static analyzer warning.

void TextManipulationController::observeParagraphs(const Position& start, const Position& end)
    Vector<ManipulationToken> tokensInCurrentParagraph;
    for (; !iterator.atEnd(); iterator.advance()) {
        if (content.isReplacedContent) {
            tokensInCurrentParagraph.append(ManipulationToken { m_tokenIdentifier.generate(), "[]", true /* isExcluded */});
        while ((offsetOfNextNewLine = currentText.find('\n', startOfCurrentLine)) != notFound) {
            if (startOfCurrentLine < offsetOfNextNewLine) {
                tokensInCurrentParagraph.append(ManipulationToken { m_tokenIdentifier.generate(), stringUntilEndOfLine, exclusionRuleMatcher.isExcluded(content.node.get()) });

            if (!tokensInCurrentParagraph.isEmpty()) {
                addItem(ManipulationItemData { startOfCurrentParagraph, endOfCurrentParagraph, nullptr, nullQName(), WTFMove(tokensInCurrentParagraph) });
        if (remainingText.length())
            tokensInCurrentParagraph.append(ManipulationToken { m_tokenIdentifier.generate(), remainingText.toString(), exclusionRuleMatcher.isExcluded(content.node.get()) });

    if (!tokensInCurrentParagraph.isEmpty())
        addItem(ManipulationItemData { startOfCurrentParagraph, visibleEnd.deepEquivalent(), nullptr, nullQName(), WTFMove(tokensInCurrentParagraph) });
Comment 1 David Kilzer (:ddkilzer) 2020-04-06 17:54:27 PDT
Created attachment 395641 [details]
Patch v1
Comment 2 Radar WebKit Bug Importer 2020-04-06 17:54:56 PDT
Comment 3 Ryosuke Niwa 2020-04-06 18:07:50 PDT
Comment on attachment 395641 [details]
Patch v1

View in context: https://bugs.webkit.org/attachment.cgi?id=395641&action=review

> Source/WebCore/editing/TextManipulationController.cpp:307
> -                addItem(ManipulationItemData { startOfCurrentParagraph, endOfCurrentParagraph, nullptr, nullQName(), WTFMove(tokensInCurrentParagraph) });
> +                addItem(ManipulationItemData { startOfCurrentParagraph, endOfCurrentParagraph, nullptr, nullQName(), std::exchange(tokensInCurrentParagraph, { }) });

Huh, it's kind of annoying that we have to use std::exchange instead in this simple case...
Comment 4 EWS 2020-04-06 19:16:53 PDT
Committed r259620: <https://trac.webkit.org/changeset/259620>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 395641 [details].
Comment 5 Darin Adler 2020-04-10 09:42:24 PDT
(In reply to Ryosuke Niwa from comment #3)
> it's kind of annoying that we have to use std::exchange instead in this simple case...

Given how C++ defines the move operation, *any* time we want to do anything with the object afterward we should use std::exchange. If we use WTFMove or std::move, we should think of the object left behind as "can't look at this; can only destroy it or overwrite it with a new value".

Any existing habit of using WTFMove and counting on the thing being null afterward is not good for the long term. We need to either use std::exchange or something new define, something other than WTFMove or std::move.

The good news is:

    auto takenValue = std::exchange(m_oldValue, nullptr);

with enough inlining could compile to the same thing as:

    auto takeValue = WTFMove(m_oldValue);