From 865f3fa0d096cb2823c922b859a713ef9ac8d6b1 Mon Sep 17 00:00:00 2001 From: Witold Filipczyk <witekfl@poczta.onet.pl> Date: Sat, 19 Nov 2022 19:24:15 +0100 Subject: [PATCH] [ecmascript] Rewritten document.write spidermonkey segfaults on test/ecmascript/document_write.html quickjs and mujs do not. --- src/ecmascript/ecmascript.cpp | 40 ++++++++++++++++++++++++ src/ecmascript/ecmascript.h | 3 ++ src/ecmascript/mujs/document.cpp | 39 ++--------------------- src/ecmascript/quickjs/document.cpp | 39 ++--------------------- src/ecmascript/spidermonkey/document.cpp | 38 ++-------------------- test/ecmascript/document_write.html | 8 +++-- 6 files changed, 58 insertions(+), 109 deletions(-) diff --git a/src/ecmascript/ecmascript.cpp b/src/ecmascript/ecmascript.cpp index 22d9d1565..102b640eb 100644 --- a/src/ecmascript/ecmascript.cpp +++ b/src/ecmascript/ecmascript.cpp @@ -302,6 +302,7 @@ ecmascript_get_interpreter(struct view_state *vs) } (void)init_string(&interpreter->code); + (void)init_string(&interpreter->writecode); return interpreter; } @@ -322,6 +323,7 @@ ecmascript_put_interpreter(struct ecmascript_interpreter *interpreter) #endif free_ecmascript_string_list(&interpreter->onload_snippets); done_string(&interpreter->code); + done_string(&interpreter->writecode); /* Is it superfluous? */ if (interpreter->vs->doc_view) { struct ecmascript_timeout *t; @@ -369,6 +371,44 @@ check_for_rerender(struct ecmascript_interpreter *interpreter, const char* text) struct session *ses = doc_view->session; struct cache_entry *cached = document->cached; + if (!strcmp(text, "eval")) { + if (interpreter->element_offset) { + if (interpreter->writecode.length) { + std::map<int, xmlpp::Element *> *mapa = (std::map<int, xmlpp::Element *> *)document->element_map; + + if (mapa) { + auto element = (*mapa).find(interpreter->element_offset); + + if (element != (*mapa).end()) { + xmlpp::Element *el = element->second; + xmlpp::ustring text = "<root>"; + text += interpreter->writecode.source; + text += "</root>"; + + xmlDoc* doc = htmlReadDoc((xmlChar*)text.c_str(), NULL, NULL, HTML_PARSE_RECOVER | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING); + // Encapsulate raw libxml document in a libxml++ wrapper + xmlpp::Document doc1(doc); + + auto root = doc1.get_root_node(); + auto root1 = root->find("//root")[0]; + auto children2 = root1->get_children(); + auto it2 = children2.begin(); + auto end2 = children2.end(); + for (; it2 != end2; ++it2) { + xmlAddPrevSibling(el->cobj(), (*it2)->cobj()); + } + xmlpp::Node::remove_node(el); + } + } + } + } else { + if (interpreter->writecode.length) { + add_fragment(cached, 0, interpreter->writecode.source, interpreter->writecode.length); + document->ecmascript_counter++; + } + } + } + //fprintf(stderr, "%s\n", text); if (document->dom) { diff --git a/src/ecmascript/ecmascript.h b/src/ecmascript/ecmascript.h index 02f2337c6..2c4d06fd5 100644 --- a/src/ecmascript/ecmascript.h +++ b/src/ecmascript/ecmascript.h @@ -66,6 +66,9 @@ struct ecmascript_interpreter { /* The code evaluated by setTimeout() */ struct string code; + /* document.write buffer */ + struct string writecode; + struct heartbeat *heartbeat; /* This is a cross-rerenderings accumulator of diff --git a/src/ecmascript/mujs/document.cpp b/src/ecmascript/mujs/document.cpp index b5995cab4..0274e8ab5 100644 --- a/src/ecmascript/mujs/document.cpp +++ b/src/ecmascript/mujs/document.cpp @@ -858,12 +858,6 @@ mjs_document_write_do(js_State *J, int newline) fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); - struct string code; - - if (!init_string(&code)) { - js_pushnull(J); - return; - } int argc = 1; if (argc >= 1) @@ -873,47 +867,20 @@ mjs_document_write_do(js_State *J, int newline) const char *str = js_tostring(J, i+1); if (str) { - add_to_string(&code, str); + add_to_string(&interpreter->writecode, str); } } if (newline) { - add_to_string(&code, "\n"); + add_to_string(&interpreter->writecode, "\n"); } } - //DBG("%s",code.source); - - /* XXX: I don't know about you, but I have *ENOUGH* of those 'Undefined - * function' errors, I want to see just the useful ones. So just - * lighting a led and going away, no muss, no fuss. --pasky */ - /* TODO: Perhaps we can introduce ecmascript.error_report_unsupported - * -> "Show information about the document using some valid, - * nevertheless unsupported methods/properties." --pasky too */ - - struct document_view *doc_view = interpreter->vs->doc_view; - struct document *document; - document = doc_view->document; - struct cache_entry *cached = doc_view->document->cached; - cached = doc_view->document->cached; - struct fragment *f = get_cache_fragment(cached); - - if (f && f->length) - { - if (false && document->ecmascript_counter==0) - { - add_fragment(cached,0,code.source,code.length); - } else { - add_fragment(cached,f->length,code.source,code.length); - } - document->ecmascript_counter++; - } + interpreter->changed = true; #ifdef CONFIG_LEDS set_led_value(interpreter->vs->doc_view->session->status.ecmascript_led, 'J'); #endif - - done_string(&code); js_pushundefined(J); } diff --git a/src/ecmascript/quickjs/document.cpp b/src/ecmascript/quickjs/document.cpp index d89a639ff..20172ca27 100644 --- a/src/ecmascript/quickjs/document.cpp +++ b/src/ecmascript/quickjs/document.cpp @@ -903,11 +903,6 @@ js_document_write_do(JSContext *ctx, JSValueConst this_val, int argc, JSValueCon fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); - struct string code; - - if (!init_string(&code)) { - return JS_EXCEPTION; - } if (argc >= 1) { @@ -921,48 +916,20 @@ js_document_write_do(JSContext *ctx, JSValueConst this_val, int argc, JSValueCon if (!str) { return JS_EXCEPTION; } - add_bytes_to_string(&code, str, len); + add_bytes_to_string(&interpreter->writecode, str, len); JS_FreeCString(ctx, str); } if (newline) { - add_to_string(&code, "\n"); + add_to_string(&interpreter->writecode, "\n"); } } - //DBG("%s",code.source); - - /* XXX: I don't know about you, but I have *ENOUGH* of those 'Undefined - * function' errors, I want to see just the useful ones. So just - * lighting a led and going away, no muss, no fuss. --pasky */ - /* TODO: Perhaps we can introduce ecmascript.error_report_unsupported - * -> "Show information about the document using some valid, - * nevertheless unsupported methods/properties." --pasky too */ - - struct document_view *doc_view = interpreter->vs->doc_view; - struct document *document; - document = doc_view->document; - struct cache_entry *cached = doc_view->document->cached; - cached = doc_view->document->cached; - struct fragment *f = get_cache_fragment(cached); - - if (f && f->length) - { - if (false && document->ecmascript_counter==0) - { - add_fragment(cached,0,code.source,code.length); - } else { - add_fragment(cached,f->length,code.source,code.length); - } - document->ecmascript_counter++; - } + interpreter->changed = true; #ifdef CONFIG_LEDS set_led_value(interpreter->vs->doc_view->session->status.ecmascript_led, 'J'); #endif - - done_string(&code); - return JS_FALSE; } diff --git a/src/ecmascript/spidermonkey/document.cpp b/src/ecmascript/spidermonkey/document.cpp index ec25a7856..9e8c79cc9 100644 --- a/src/ecmascript/spidermonkey/document.cpp +++ b/src/ecmascript/spidermonkey/document.cpp @@ -1305,56 +1305,24 @@ document_write_do(JSContext *ctx, unsigned int argc, JS::Value *rval, int newlin struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); JS::CallArgs args = JS::CallArgsFromVp(argc, rval); - struct string code; - - if (!init_string(&code)) { - return false; - } - if (argc >= 1) { for (unsigned int i = 0; i < argc; ++i) { - jshandle_value_to_char_string(&code, ctx, args[i]); + jshandle_value_to_char_string(&interpreter->writecode, ctx, args[i]); } if (newline) { - add_to_string(&code, "\n"); + add_to_string(&interpreter->writecode, "\n"); } } - //DBG("%s",code.source); - - /* XXX: I don't know about you, but I have *ENOUGH* of those 'Undefined - * function' errors, I want to see just the useful ones. So just - * lighting a led and going away, no muss, no fuss. --pasky */ - /* TODO: Perhaps we can introduce ecmascript.error_report_unsupported - * -> "Show information about the document using some valid, - * nevertheless unsupported methods/properties." --pasky too */ - - struct document_view *doc_view = interpreter->vs->doc_view; - struct document *document; - document = doc_view->document; - struct cache_entry *cached = doc_view->document->cached; - cached = doc_view->document->cached; - struct fragment *f = get_cache_fragment(cached); - - if (f && f->length) - { - if (false && document->ecmascript_counter==0) - { - add_fragment(cached,0,code.source,code.length); - } else { - add_fragment(cached,f->length,code.source,code.length); - } - document->ecmascript_counter++; - } + interpreter->changed = true; #ifdef CONFIG_LEDS set_led_value(interpreter->vs->doc_view->session->status.ecmascript_led, 'J'); #endif - done_string(&code); args.rval().setBoolean(false); return true; diff --git a/test/ecmascript/document_write.html b/test/ecmascript/document_write.html index f20bfcc0b..5b7fb3b5f 100644 --- a/test/ecmascript/document_write.html +++ b/test/ecmascript/document_write.html @@ -4,6 +4,9 @@ -| 16 colors |- </title> <script type="text/javascript"> +function onl() +{ + document.writeln('<html><head><title>-| 16 colors |-</title></head><pre>'); var colors=[ "white", @@ -53,8 +56,9 @@ document.writeln('<html><head><title>-| 16 colors |-</title></head><pre>'); document.writeln('<font color="red">and this is false: '+false+'</font>'); document.writeln('<font color="yellow">',"That's it as ... ","1+1=",2,'</font>'); document.writeln('</pre></body></html>'); - </script> +} +</script> </head> -<body> +<body onload="onl()"> </body> </html>