Changeset 94274 in webkit


Ignore:
Timestamp:
Aug 31, 2011 11:11:07 PM (13 years ago)
Author:
rniwa@webkit.org
Message:

Crash when inserting text with a trailing newline into a textarea via JS
https://bugs.webkit.org/show_bug.cgi?id=66241

Reviewed by Darin Adler and Kent Tamura.

Source/WebCore:

The crash was caused by updateFromElement biting on the editing code.

When there is a style rule that applies on text nodes inside the shadow DOM, DOM modifications made
by the editing code may trigger style recalculation on input or textarea elements in the midst of editing
commands. In response to this style recalculation, HTMLInputElement::updateFromElement and
HTMLTextAreaElement::updateFromElement call setInnerTextValue to re-create the text nodes in the
shadow DOM. The editing code blows up because setInnerTextValue detaches old text nodes referenced by
Positions and VisiblePositions held by the editing commands in progress.

Fixed the crash by stop calling setInnerTextValue in updateFromElement. Instead, WebKit now creates
the text nodes when attributes, descendent nodes, etc... of input or textarea element changes.

Tests: fast/forms/update-from-element-during-editing-crash-1.html

fast/forms/update-from-element-during-editing-crash-2.html

  • html/HTMLInputElement.cpp:

(WebCore::HTMLInputElement::updateType): Force calling setInnerTextValue when input type changes.
(WebCore::HTMLInputElement::updateInnerTextValue): Extracted from RenderTextControlSingleLine's
updateElement.
(WebCore::HTMLInputElement::parseMappedAttribute): Calls updateInnerTextValue; force calling
setInnerTextValue when -webkit-speech attribute changes. In the theory, we should be able to call it less
frequently but there are too many cases to consider at the moment.
(WebCore::HTMLInputElement::setValue): Calls updateInnerTextValue when the value actually changed.
Note we need to call it before we set or restore selection.

  • html/HTMLInputElement.h:
  • html/HTMLTextAreaElement.cpp:

(WebCore::HTMLTextAreaElement::childrenChanged): Calls updateInnerTextValue when textarea's descendants
nodes are changed by parser or scripts.
(WebCore::HTMLTextAreaElement::setValueCommon): Calls updateInnerTextValue when the value changes.

  • html/HTMLTextFormControlElement.h:
  • html/NumberInputType.cpp:

(WebCore::NumberInputType::willBlur): Calls updateInnerTextValue because input[type=number] forces
the value to be valid on blur.

  • rendering/RenderTextControlMultiLine.cpp: Removed RenderTextControlMultiLine::updateFromElement.
  • rendering/RenderTextControlMultiLine.h: Ditto.
  • rendering/RenderTextControlSingleLine.cpp:

(WebCore::RenderTextControlSingleLine::updateFromElement):

LayoutTests:

Add regressions tests to ensure WebKit doesn't crash even when style recalc happens
in the midst of editing commands.

  • fast/forms/update-from-element-during-editing-crash-1-expected.txt: Added.
  • fast/forms/update-from-element-during-editing-crash-1.html: Added.
  • fast/forms/update-from-element-during-editing-crash-2-expected.txt: Added.
  • fast/forms/update-from-element-during-editing-crash-2.html: Added.
Location:
trunk
Files:
4 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r94272 r94274  
     12011-08-31  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Crash when inserting text with a trailing newline into a textarea via JS
     4        https://bugs.webkit.org/show_bug.cgi?id=66241
     5
     6        Reviewed by Darin Adler and Kent Tamura.
     7
     8        Add regressions tests to ensure WebKit doesn't crash even when style recalc happens
     9        in the midst of editing commands.
     10
     11        * fast/forms/update-from-element-during-editing-crash-1-expected.txt: Added.
     12        * fast/forms/update-from-element-during-editing-crash-1.html: Added.
     13        * fast/forms/update-from-element-during-editing-crash-2-expected.txt: Added.
     14        * fast/forms/update-from-element-during-editing-crash-2.html: Added.
     15
    1162011-08-31  David Levin  <levin@chromium.org>
    217
  • trunk/Source/WebCore/ChangeLog

    r94273 r94274  
     12011-08-31  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Crash when inserting text with a trailing newline into a textarea via JS
     4        https://bugs.webkit.org/show_bug.cgi?id=66241
     5
     6        Reviewed by Darin Adler and Kent Tamura.
     7
     8        The crash was caused by updateFromElement biting on the editing code.
     9
     10        When there is a style rule that applies on text nodes inside the shadow DOM, DOM modifications made
     11        by the editing code may trigger style recalculation on input or textarea elements in the midst of editing
     12        commands. In response to this style recalculation, HTMLInputElement::updateFromElement and
     13        HTMLTextAreaElement::updateFromElement call setInnerTextValue to re-create the text nodes in the
     14        shadow DOM. The editing code blows up because setInnerTextValue detaches old text nodes referenced by
     15        Positions and VisiblePositions held by the editing commands in progress.
     16
     17        Fixed the crash by stop calling setInnerTextValue in updateFromElement. Instead, WebKit now creates
     18        the text nodes when attributes, descendent nodes, etc... of input or textarea element changes.
     19
     20        Tests: fast/forms/update-from-element-during-editing-crash-1.html
     21               fast/forms/update-from-element-during-editing-crash-2.html
     22
     23        * html/HTMLInputElement.cpp:
     24        (WebCore::HTMLInputElement::updateType): Force calling setInnerTextValue when input type changes.
     25        (WebCore::HTMLInputElement::updateInnerTextValue): Extracted from RenderTextControlSingleLine's
     26        updateElement.
     27        (WebCore::HTMLInputElement::parseMappedAttribute): Calls updateInnerTextValue; force calling
     28        setInnerTextValue when -webkit-speech attribute changes. In the theory, we should be able to call it less
     29        frequently but there are too many cases to consider at the moment.
     30        (WebCore::HTMLInputElement::setValue): Calls updateInnerTextValue when the value actually changed.
     31        Note we need to call it before we set or restore selection.
     32        * html/HTMLInputElement.h:
     33        * html/HTMLTextAreaElement.cpp:
     34        (WebCore::HTMLTextAreaElement::childrenChanged): Calls updateInnerTextValue when textarea's descendants
     35        nodes are changed by parser or scripts.
     36        (WebCore::HTMLTextAreaElement::setValueCommon): Calls updateInnerTextValue when the value changes.
     37        * html/HTMLTextFormControlElement.h:
     38        * html/NumberInputType.cpp:
     39        (WebCore::NumberInputType::willBlur): Calls updateInnerTextValue because input[type=number] forces
     40        the value to be valid on blur.
     41        * rendering/RenderTextControlMultiLine.cpp: Removed RenderTextControlMultiLine::updateFromElement.
     42        * rendering/RenderTextControlMultiLine.h: Ditto.
     43        * rendering/RenderTextControlSingleLine.cpp:
     44        (WebCore::RenderTextControlSingleLine::updateFromElement):
     45
    1462011-08-31  Tom Zakrajsek  <tomz@codeaurora.org>
    247
  • trunk/Source/WebCore/html/HTMLInputElement.cpp

    r94252 r94274  
    5050#include "RenderTextControlSingleLine.h"
    5151#include "RenderTheme.h"
    52 #include "RuntimeEnabledFeatures.h"
    5352#include "SearchInputType.h"
    5453#include "ScriptEventListener.h"
     
    6059#include "ColorChooser.h"
    6160#include "ColorInputType.h"
     61#endif
     62
     63#if ENABLE(INPUT_SPEECH)
     64#include "RuntimeEnabledFeatures.h"
    6265#endif
    6366
     
    584587    else
    585588        updateValueIfNeeded();
     589
     590    setFormControlValueMatchesRenderer(false);
     591    updateInnerTextValue();
     592
    586593    m_wasModifiedByUser = false;
    587594
     
    614621    setNeedsValidityCheck();
    615622    notifyFormStateChanged();
     623}
     624
     625void HTMLInputElement::updateInnerTextValue()
     626{
     627    if (!isTextField())
     628        return;
     629
     630    if (!suggestedValue().isNull())
     631        setInnerTextValue(suggestedValue());
     632    else if (!formControlValueMatchesRenderer()) {
     633        // Update the renderer value if the formControlValueMatchesRenderer() flag is false.
     634        // It protects an unacceptable renderer value from being overwritten with the DOM value.
     635        setInnerTextValue(visibleValue());
     636    }
    616637}
    617638
     
    823844            m_inputType->createShadowSubtree();
    824845        }
     846        setFormControlValueMatchesRenderer(false);
    825847        setNeedsStyleRecalc();
    826848    } else if (attr->name() == onwebkitspeechchangeAttr)
     
    829851    else
    830852        HTMLTextFormControlElement::parseMappedAttribute(attr);
     853    updateInnerTextValue();
    831854}
    832855
     
    10771100
    10781101    setNeedsValidityCheck();
     1102
     1103    if (valueChanged)
     1104        updateInnerTextValue();
    10791105
    10801106    if (isTextField()) {
  • trunk/Source/WebCore/html/HTMLInputElement.h

    r94158 r94274  
    146146    String sanitizeValue(const String&) const;
    147147
     148    void updateInnerTextValue();
     149
    148150    // The value which is drawn by a renderer.
    149151    String visibleValue() const;
  • trunk/Source/WebCore/html/HTMLTextAreaElement.cpp

    r94252 r94274  
    3737#include "Frame.h"
    3838#include "HTMLNames.h"
    39 #include "RenderStyle.h"
    4039#include "RenderTextControlMultiLine.h"
    4140#include "ShadowRoot.h"
     
    102101    if (!m_isDirty)
    103102        setNonDirtyValue(defaultValue());
     103    setInnerTextValue(value());
    104104    HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
    105105}
     
    330330
    331331    m_value = normalizedValue;
     332    setInnerTextValue(m_value);
    332333    setLastChangeWasNotUserEdit();
    333334    updatePlaceholderVisibility(false);
  • trunk/Source/WebCore/html/HTMLTextFormControlElement.h

    r94252 r94274  
    104104
    105105    String valueWithHardLineBreaks() const;
     106
    106107private:
    107108    int computeSelectionStart() const;
  • trunk/Source/WebCore/html/NumberInputType.cpp

    r94252 r94274  
    281281    // We need to reset the renderer value explicitly because an unacceptable
    282282    // renderer value should be purged before style calculation.
    283     if (element()->renderer())
    284         element()->renderer()->updateFromElement();
     283    element()->updateInnerTextValue();
    285284}
    286285
  • trunk/Source/WebCore/rendering/RenderTextControlMultiLine.cpp

    r94047 r94274  
    8181}
    8282
    83 void RenderTextControlMultiLine::updateFromElement()
    84 {
    85     RenderTextControl::updateFromElement();
    86 
    87     textFormControlElement()->setInnerTextValue(static_cast<HTMLTextAreaElement*>(node())->value());
    88 }
    89 
    9083PassRefPtr<RenderStyle> RenderTextControlMultiLine::createInnerTextStyle(const RenderStyle* startStyle) const
    9184{
  • trunk/Source/WebCore/rendering/RenderTextControlMultiLine.h

    r93334 r94274  
    4242    virtual LayoutUnit baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
    4343
    44     virtual void updateFromElement();
    45 
    4644    virtual RenderStyle* textBaseStyle() const;
    4745    virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const;
  • trunk/Source/WebCore/rendering/RenderTextControlSingleLine.cpp

    r94149 r94274  
    477477        updateCancelButtonVisibility();
    478478
    479     if (!inputElement()->suggestedValue().isNull())
    480         textFormControlElement()->setInnerTextValue(inputElement()->suggestedValue());
    481     else {
    482         if (node()->hasTagName(inputTag)) {
    483             // For HTMLInputElement, update the renderer value if the formControlValueMatchesRenderer()
    484             // flag is false. It protects an unacceptable renderer value from
    485             // being overwritten with the DOM value.
    486             if (!inputElement()->formControlValueMatchesRenderer())
    487                 textFormControlElement()->setInnerTextValue(inputElement()->visibleValue());
    488         }
    489     }
    490 
    491479    if (m_searchPopupIsVisible)
    492480        m_searchPopup->popupMenu()->updateFromElement();
Note: See TracChangeset for help on using the changeset viewer.