Reviewed by Maciej.

        - fixed http://bugzilla.opendarwin.org/show_bug.cgi?id=4367
          Crash when executing setTimeout / Date / document.write Javascript (bugtraq)

        Test cases added:
        * layout-tests/fast/dom/document-write-infinite-recursion.html: Added.
        * layout-tests/fast/dom/document-write-infinite-recursion-expected.txt: Added.

        * khtml/xml/dom_docimpl.cpp:
        (DocumentImpl::implicitClose): Simplify a bit to make more readable. Remove the
        code to delete the tokenizer an extra time -- that can end up deleting the newly
        created tokenizer that's still needed for the newly opened page.
        (DocumentImpl::write): Added an assertion to catch the badness that caused
        infinite recursion so it's easier to recognize next time.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@10513 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/fast/dom/document-write-infinite-recursion-expected.txt b/LayoutTests/fast/dom/document-write-infinite-recursion-expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/LayoutTests/fast/dom/document-write-infinite-recursion-expected.txt
diff --git a/LayoutTests/fast/dom/document-write-infinite-recursion.html b/LayoutTests/fast/dom/document-write-infinite-recursion.html
new file mode 100644
index 0000000..3039f91
--- /dev/null
+++ b/LayoutTests/fast/dom/document-write-infinite-recursion.html
@@ -0,0 +1,27 @@
+<script>
+
+function a()
+{
+    if (window.layoutTestController) {
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+    }
+    setTimeout("b()", 0);
+    document.write("a"); 
+}
+
+function b()
+{
+    setTimeout("c()", 0);
+    document.write("b"); 
+}
+
+function c()
+{
+    document.write("If you can see this, then the browser survived; older versions of WebKit would have crashed due to infinite recursion."); 
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+
+</script>
+<body onload="a()">
diff --git a/WebCore/ChangeLog-2005-12-19 b/WebCore/ChangeLog-2005-12-19
index 9f036249..a56756e 100644
--- a/WebCore/ChangeLog-2005-12-19
+++ b/WebCore/ChangeLog-2005-12-19
@@ -1,5 +1,23 @@
 2005-09-10  Darin Adler  <darin@apple.com>
 
+        Reviewed by Maciej.
+
+        - fixed http://bugzilla.opendarwin.org/show_bug.cgi?id=4367
+          Crash when executing setTimeout / Date / document.write Javascript (bugtraq)
+
+        Test cases added:
+        * layout-tests/fast/dom/document-write-infinite-recursion.html: Added.
+        * layout-tests/fast/dom/document-write-infinite-recursion-expected.txt: Added.
+
+        * khtml/xml/dom_docimpl.cpp:
+        (DocumentImpl::implicitClose): Simplify a bit to make more readable. Remove the
+        code to delete the tokenizer an extra time -- that can end up deleting the newly
+        created tokenizer that's still needed for the newly opened page.
+        (DocumentImpl::write): Added an assertion to catch the badness that caused
+        infinite recursion so it's easier to recognize next time.
+
+2005-09-10  Darin Adler  <darin@apple.com>
+
         - add expected success result for newly-enabled test
 
         * layout-tests/dom/html/level2/html/HTMLIFrameElement11-expected.txt: Added.
@@ -794,22 +812,6 @@
         * layout-tests/dom/html/level2/core/createDocument08-expected.txt: Updated to expect success.
         * layout-tests/dom/html/level2/core/createDocumentType04-expected.txt: Ditto.
 
-2005-09-05  Darin Adler  <darin@apple.com>
-
-        Reviewed by John Sullivan.
-
-        - fixed http://bugzilla.opendarwin.org/show_bug.cgi?id=4493
-          add qualifiedName checking for empty string
-
-        * khtml/xml/dom_docimpl.cpp:
-        (qualifiedNameIsValid): Added.
-        (qualifiedNameIsMalformed): Added.
-        (DOMImplementationImpl::createDocumentType): Added checks and exceptions using above functions.
-        (DOMImplementationImpl::createDocument): Ditto.
-
-        * layout-tests/dom/html/level2/core/createDocument08-expected.txt: Updated to expect success.
-        * layout-tests/dom/html/level2/core/createDocumentType04-expected.txt: Ditto.
-
 2005-09-05  John Sullivan  <sullivan@apple.com>
 
         Reviewed by Dave Hyatt.
diff --git a/WebCore/khtml/xml/dom_docimpl.cpp b/WebCore/khtml/xml/dom_docimpl.cpp
index adfc06e..f00d7d6 100644
--- a/WebCore/khtml/xml/dom_docimpl.cpp
+++ b/WebCore/khtml/xml/dom_docimpl.cpp
@@ -1322,97 +1322,75 @@
         return;
     }
 
-    // First fire the onload.
-    
     bool wasLocationChangePending = part() && part()->isScheduledLocationChangePending();
     bool doload = !parsing() && m_tokenizer && !m_processingLoadEvent && !wasLocationChangePending;
     
-    if (doload) {
-        m_processingLoadEvent = true;
+    if (!doload)
+        return;
 
-        // We have to clear the tokenizer, in case someone document.write()s from the
-        // onLoad event handler, as in Radar 3206524
-        delete m_tokenizer;
-        m_tokenizer = 0;
+    m_processingLoadEvent = true;
 
-        // Create a body element if we don't already have one.
-        // In the case of Radar 3758785, the window.onload was set in some javascript, but never fired because there was no body.  
-        // This behavior now matches Firefox and IE.
-        HTMLElementImpl *body = this->body();
-        if (!body && isHTMLDocument()) {
-            NodeImpl *de = documentElement();
-            if (de) {
-                body = new HTMLBodyElementImpl(docPtr());
-                int exceptionCode = 0;
-                de->appendChild(body, exceptionCode);
-                if (exceptionCode != 0)
-                    body = 0;
-            }
+    // We have to clear the tokenizer, in case someone document.write()s from the
+    // onLoad event handler, as in Radar 3206524.
+    delete m_tokenizer;
+    m_tokenizer = 0;
+
+    // Create a body element if we don't already have one.
+    // In the case of Radar 3758785, the window.onload was set in some javascript, but never fired because there was no body.  
+    // This behavior now matches Firefox and IE.
+    HTMLElementImpl *body = this->body();
+    if (!body && isHTMLDocument()) {
+        NodeImpl *de = documentElement();
+        if (de) {
+            body = new HTMLBodyElementImpl(docPtr());
+            int exceptionCode = 0;
+            de->appendChild(body, exceptionCode);
+            if (exceptionCode != 0)
+                body = 0;
         }
-
-        if (body) {
-            dispatchImageLoadEventsNow();
-            body->dispatchWindowEvent(loadEvent, false, false);
-#if APPLE_CHANGES
-            if (KHTMLPart *p = part())
-                KWQ(p)->handledOnloadEvents();
-#endif
-
-#ifdef INSTRUMENT_LAYOUT_SCHEDULING
-            if (!ownerElement())
-                printf("onload fired at %d\n", elapsedTime());
-#endif
-        }
-
-        m_processingLoadEvent = false;
     }
-    
+
+    if (body) {
+        dispatchImageLoadEventsNow();
+        body->dispatchWindowEvent(loadEvent, false, false);
+        if (KHTMLPart *p = part())
+            KWQ(p)->handledOnloadEvents();
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+        if (!ownerElement())
+            printf("onload fired at %d\n", elapsedTime());
+#endif
+    }
+
+    m_processingLoadEvent = false;
+
     // Make sure both the initial layout and reflow happen after the onload
     // fires. This will improve onload scores, and other browsers do it.
     // If they wanna cheat, we can too. -dwh
-    
-    bool isLocationChangePending = part() && part()->isScheduledLocationChangePending();
-    
-    if (doload && isLocationChangePending && m_startTime.elapsed() < cLayoutScheduleThreshold) {
-	// Just bail out. Before or during the onload we were shifted to another page.
-	// The old i-Bench suite does this. When this happens don't bother painting or laying out.        
-	delete m_tokenizer;
-	m_tokenizer = 0;
-	view()->unscheduleRelayout();
-	return;
-    }
-    
-    if (doload) {
-        // on an explicit document.close(), the tokenizer might still be waiting on scripts,
-        // and in that case we don't want to destroy it because that will prevent the
-        // scripts from getting processed.
-        // FIXME: this check may no longer be necessary, since now it should be impossible
-        // for parsing to be false while stil waiting for scripts
-        if (m_tokenizer && !m_tokenizer->isWaitingForScripts()) {
-            delete m_tokenizer;
-            m_tokenizer = 0;
-        }
 
-        if (m_view)
-            m_view->part()->checkEmitLoadEvent();
+    if (part() && part()->isScheduledLocationChangePending() && m_startTime.elapsed() < cLayoutScheduleThreshold) {
+        // Just bail out. Before or during the onload we were shifted to another page.
+        // The old i-Bench suite does this. When this happens don't bother painting or laying out.        
+        view()->unscheduleRelayout();
+        return;
     }
 
+    if (part())
+        part()->checkEmitLoadEvent();
+
     // Now do our painting/layout, but only if we aren't in a subframe or if we're in a subframe
     // that has been sized already.  Otherwise, our view size would be incorrect, so doing any 
     // layout/painting now would be pointless.
-    if (doload) {
-        if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->renderer()->needsLayout())) {
-            updateRendering();
-            
-            // Always do a layout after loading if needed.
-            if (view() && renderer() && (!renderer()->firstChild() || renderer()->needsLayout()))
-                view()->layout();
-        }
-#if APPLE_CHANGES
-        if (renderer() && KWQAccObjectCache::accessibilityEnabled())
-            getAccObjectCache()->postNotification(renderer(), "AXLoadComplete");
-#endif
+    if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->renderer()->needsLayout())) {
+        updateRendering();
+        
+        // Always do a layout after loading if needed.
+        if (view() && renderer() && (!renderer()->firstChild() || renderer()->needsLayout()))
+            view()->layout();
     }
+#if APPLE_CHANGES
+    if (renderer() && KWQAccObjectCache::accessibilityEnabled())
+        getAccObjectCache()->postNotification(renderer(), "AXLoadComplete");
+#endif
 }
 
 void DocumentImpl::setParsing(bool b)
@@ -1469,7 +1447,8 @@
     
     if (!m_tokenizer) {
         open();
-        write(QString::fromLatin1("<html>"));
+        assert(m_tokenizer);
+        write(QString("<html>"));
     }
     m_tokenizer->write(text, false);