Bug 33075

Summary: WebCore::RenderInline::mapLocalToContainer RecursionSOV (f6a51883f6be6a6c0fca30ae47a1b115)
Product: WebKit Reporter: Berend-Jan Wever <skylined>
Component: HTML EditingAssignee: Nobody <webkit-unassigned>
Status: RESOLVED FIXED    
Severity: Normal CC: eric, mitz, simon.fraser
Priority: P1    
Version: 528+ (Nightly build)   
Hardware: PC   
OS: Windows Vista   

Description Berend-Jan Wever 2009-12-31 00:42:23 PST
execCommand can be used to trigger infinite recursion. I'm having the repro reduced to workable size and will add it when it's done. The problem is obvious from the source code though; below is the vulnerable function, which calls itself on the last line. Once the repro is reduced, I should be able to show you how to trigger it.

void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const
{
    if (repaintContainer == this)
        return;

    if (RenderView *v = view()) {
        if (v->layoutStateEnabled() && !repaintContainer) {
            LayoutState* layoutState = v->layoutState();
            IntSize offset = layoutState->m_offset;
            if (style()->position() == RelativePosition && layer())
                offset += layer()->relativePositionOffset();
            transformState.move(offset);
            return;
        }
    }

    bool containerSkipped;
    RenderObject* o = container(repaintContainer, &containerSkipped);
    if (!o)
        return;

    IntSize containerOffset = offsetFromContainer(o);

    bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
    if (useTransforms && shouldUseTransformFromContainer(o)) {
        TransformationMatrix t;
        getTransformFromContainer(o, containerOffset, t);
        transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
    } else
        transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);

    if (containerSkipped) {
        // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
        // to just subtract the delta between the repaintContainer and o.
        IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
        transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
        return;
    }

    o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
}

Id:          WebCore::RenderInline::mapLocalToContainer RecursionSOV (f6a51883f6be6a6c0fca30ae47a1b115)
Description: Recursive function call in WebCore::RenderInline::mapLocalToContainer
Stack:
  WebCore::RenderInline::mapLocalToContainer
  WebCore::RenderInline::mapLocalToContainer
  <snip>
  WebCore::RenderInline::mapLocalToContainer
  WebCore::RenderObject::mapLocalToContainer
  WebCore::RenderObject::localToAbsolute
  WebCore::VisiblePosition::xOffsetForVerticalNavigation
  WebCore::SelectionController::modify
  WebCore::TypingCommand::forwardDeleteKeyPressed
  WebCore::TypingCommand::doApply
  WebCore::EditCommand::apply
  WebCore::TypingCommand::forwardDeleteKeyPressed
  WebCore::executeForwardDelete
  WebCore::Editor::Command::execute
  WebCore::Document::execCommand
  WebCore::DocumentInternal::execCommandCallback
  v8::internal::Builtin_HandleApiCall
  v8::internal::Invoke
  v8::internal::Execution::Call
  v8::Script::Run
  WebCore::V8Proxy::runScript
  WebCore::V8Proxy::evaluate
  WebCore::ScriptController::evaluate
  WebCore::ScriptController::executeScript
  WebCore::ScriptController::executeScript
  WebCore::ScriptController::executeIfJavaScriptURL
  WebCore::FrameLoader::changeLocation
  WebCore::RedirectScheduler::timerFired
  WebCore::Timer<...>::fired
  WebCore::ThreadTimers::sharedTimerFiredInternal
  MessageLoop::RunTask
  MessageLoop::DoWork
  base::MessagePumpDefault::Run
  MessageLoop::RunInternal
  MessageLoop::Run
  RendererMain

Event details

Processes	
   0    id: f14 create  name: chrome.exe
.  1    id: 61c child   name: chrome.exe
Current process:
0n1564 C:\chromium-latest\chrome.exe
       Session: 0  User: VM3-XP32SP3-CJ\SkyLined  Command Line: "C:\chromium-latest\chrome.exe" --type=renderer --no-sandbox --js-flags=--expose-gc --lang=en-US --force-fieldtest=DnsImpact/_max_2s_queue_prefetch/GlobalSdch/_global_enable_sdch/SocketLateBinding/_enable_late_binding/ --channel=3860.01052700.306296198
Threads	
. 12  Id: 61c.a84 Suspend: 1 Teb: 7ffdf000 Unfrozen "Main Thread"
  13  Id: 61c.fa0 Suspend: 1 Teb: 7ffde000 Unfrozen
  14  Id: 61c.c18 Suspend: 1 Teb: 7ffdd000 Unfrozen "Chrome_ChildIOThread"
  15  Id: 61c.964 Suspend: 1 Teb: 7ffdc000 Unfrozen
ExceptionAddress	02114d49 (chrome_1c30000!WebCore::RenderInline::mapLocalToContainer+0x00000009)
ExceptionCode	c00000fd (Stack overflow)
ExceptionFlags	00000000
NumberParameters	2
Parameter[0]	00000001
Parameter[1]	00032fd8
Comment 1 Berend-Jan Wever 2009-12-31 00:45:49 PST
PS. The code snippet is from http://svn.webkit.org/repository/webkit/trunk/WebCore/rendering/RenderInline.cpp
Comment 2 Berend-Jan Wever 2010-01-05 02:16:01 PST
I can't seem to get a decent repro, sorry.
Comment 3 Berend-Jan Wever 2010-05-20 06:54:41 PDT
http://code.google.com/p/chromium/issues/detail?id=44638

Contains a working repro. However, it only crashes Chrome 4.1 and not 6.0, so I assume that this has been fixed.