Closed
Bug 351413
Opened 18 years ago
Closed 18 years ago
Unbounded recursion during let block cloning
Categories
(Core :: JavaScript Engine, defect)
Core
JavaScript Engine
Tracking
()
RESOLVED
FIXED
People
(Reporter: igor, Assigned: igor)
References
Details
(Keywords: fixed1.8.1, Whiteboard: [baking until 09/08])
Attachments
(3 files, 2 obsolete files)
1.97 KB,
text/plain
|
Details | |
3.70 KB,
patch
|
brendan
:
review+
|
Details | Diff | Splinter Review |
3.69 KB,
patch
|
mtschrep
:
approval1.8.1+
|
Details | Diff | Splinter Review |
js_GetScopeChain from js/src/jsinterp.c uses recursive helper function CloneBlockChain to clone let blocks. The function does not check for C recursion depth. Thus a C stack overflow is possible with nested let blocks.
Assignee | ||
Comment 1•18 years ago
|
||
The fix replaces the recursion by a loop that set the parent slot of the cloned child after cloning the parent. The only complexity comes from the need to GC protect the child during parent's cloning.
Assignee | ||
Comment 2•18 years ago
|
||
The test requires manual testing as it must know about maximum C stack depth. The reason for this is that the parser already recursive. Thus to trigger a stack overflow one has to call a function with nested let blocks from already low stack. So here is results from my Ubuntu Linux 6.06 laptop: ~/m/trunk/mozilla/js/src> ulimit -s 8192 ~/m/trunk/mozilla/js/src> ./Linux_All_OPT.OBJ/js -S $((8170 * 1024)) ~/s/test351413.js Maximum amount of let nesting that the C stack limit allows: 3987 Maximum callAfterConsumingCStack level: 12441 Segmentation fault Note that it is important to find a value to pass to -S that is sufficiently close to the real limit so recursion through block cloning would have a chance to reach the limit. On the other hand the value should not be too close to the limit to give some space for the interpreter. After the patch: ~/m/trunk/mozilla/js/src> ulimit -s 8192 ~/m/trunk/mozilla/js/src> ./Linux_All_OPT.OBJ/js -S $((8170 * 1024)) ~/s/test351413.js Maximum amount of let nesting that the C stack limit allows: 3987 Maximum callAfterConsumingCStack level: 12441 true
Comment 3•18 years ago
|
||
Comment on attachment 236805 [details] [diff] [review] Fix v1 Only nit-level thoughts, below. r=me with changes you agree with. >+ cursor = js_CloneBlockObject(cx, cursor, parent ? NULL : fp->scopeChain, >+ fp); This could just pass fp->scopeChain as the third argument, to save cycles and some small amount of code, since the NULL parent value will cause a default parent computation and assignment, and it will soon be overwritten by OBJ_SET_PARENT. >+ OBJ_SET_PARENT(cx, clonedChild, cursor); In single-threaded newborn settings, I have been using clonedChild->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(cursor); and the like. We know the clonedChild can't be reached by other threads, so we may as well save cycles and minor code space again. /be
Attachment #236805 -
Flags: review?(brendan) → review+
Assignee | ||
Comment 4•18 years ago
|
||
Patch to commit with nits addressed and comments added.
Attachment #236805 -
Attachment is obsolete: true
Comment 5•18 years ago
|
||
Comment on attachment 236850 [details] [diff] [review] Fix v1b >? x.diff >Index: js.c >=================================================================== >RCS file: /cvsroot/mozilla/js/src/js.c,v >retrieving revision 3.122 >diff -U7 -p -r3.122 js.c >--- js.c 22 Aug 2006 22:42:56 -0000 3.122 >+++ js.c 5 Sep 2006 20:37:23 -0000 >@@ -683,14 +683,15 @@ Print(JSContext *cx, JSObject *obj, uint > if (!str) > return JS_FALSE; > fprintf(gOutFile, "%s%s", i ? " " : "", JS_GetStringBytes(str)); > } > n++; > if (n) > fputc('\n', gOutFile); >+ fflush(gOutFile); > return JS_TRUE; > } > > static JSBool > Help(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); > > static JSBool Separate bug? This seems suboptimal, it's ok if there's no better way to set line buffering. >Index: jsinterp.c >=================================================================== >RCS file: /cvsroot/mozilla/js/src/jsinterp.c,v >retrieving revision 3.279 >diff -U7 -p -r3.279 jsinterp.c >--- jsinterp.c 3 Sep 2006 07:08:24 -0000 3.279 >+++ jsinterp.c 5 Sep 2006 20:37:24 -0000 >@@ -459,55 +459,75 @@ js_GetLocalVariable(JSContext *cx, JSObj > > JSBool > js_SetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp) > { > return JS_TRUE; > } > >-/* >- * Recursive helper to convert a compile-time block chain to a runtime block >- * scope chain prefix. Each cloned block object is safe from GC by virtue of >- * the object newborn root. This root cannot be displaced by arbitrary code >- * called from within js_NewObject, because we pass non-null proto and parent >- * arguments (so js_NewObject won't call js_GetClassPrototype). >- */ >-static JSObject * >-CloneBlockChain(JSContext *cx, JSStackFrame *fp, JSObject *obj) >-{ >- JSObject *parent; >- >- parent = OBJ_GET_PARENT(cx, obj); >- if (!parent) { >- parent = fp->scopeChain; >- } else { >- parent = CloneBlockChain(cx, fp, parent); >- if (!parent) >- return NULL; >- fp->scopeChain = parent; >- } >- return js_CloneBlockObject(cx, obj, parent, fp); >-} Recursion sure is pretty compared to the alternative :-P. Reminds me of a book I've been asked to write a chapter for, "Beautiful Code". My initial thought is that designs and Math may be beautiful, but real code that actually defends against errors, etc., is not. Thanks, r=me again. This is safe for 1.8.1 after a bit of baking on the trunk, so nominating now. We defend elsewhere against stack overflow D.O.S. attacks, either by stack address monitoring, or by converting to iterative algorithms, as here. /be
Attachment #236850 -
Flags: review+
Attachment #236850 -
Flags: approval1.8.1?
Assignee | ||
Comment 6•18 years ago
|
||
That js.c change was a debug hack that slipped into the patch. So here is the real patch.
Attachment #236850 -
Attachment is obsolete: true
Attachment #236869 -
Flags: approval1.8.1?
Attachment #236850 -
Flags: approval1.8.1?
Updated•18 years ago
|
Attachment #236869 -
Flags: review+
Assignee | ||
Comment 7•18 years ago
|
||
I committed the patch from comment 6 to the trunk: Checking in jsinterp.c; /cvsroot/mozilla/js/src/jsinterp.c,v <-- jsinterp.c new revision: 3.280; previous revision: 3.279 done
Status: ASSIGNED → RESOLVED
Closed: 18 years ago
Resolution: --- → FIXED
Assignee | ||
Comment 8•18 years ago
|
||
> Recursion sure is pretty compared to the alternative :-P. But that is unfair comparison! What the patch shows is that replacing O(n)-in-space algorithm by O(1)-in-space one brings complexity. Such complexity when expressed in C looks more messy indeed, but what is prettier, insertion sort or heap sort? > I've been asked to write a chapter for, "Beautiful Code". My initial thought > is that designs and Math may be beautiful, but real code that actually defends > against errors, etc., is not. If an initial "beautiful" design does not account for errors, then it not even a design IMO. Which also reminds me about "ugly is beautiful" from Wheels novel by Arthur Hailey. The idea is that a thing may look initially ugly but if it is absolutely functional while fulfilling its design goals then it becomes beauty.
Comment 9•18 years ago
|
||
(In reply to comment #8) > Such complexity > when expressed in C looks more messy indeed, but what is prettier, insertion > sort or heap sort? Heap, of course :-P. > If an initial "beautiful" design does not account for errors, then it not even > a design IMO. Which also reminds me about "ugly is beautiful" from Wheels novel > by Arthur Hailey. The idea is that a thing may look initially ugly but if it is > absolutely functional while fulfilling its design goals then it becomes beauty. I quite agree. Trick is to say this in a dozen pages in a way that convinces the unconverted who want to bask in Platonic truth and beauty. Thanks for the Haley reference (I haven't read that one). /be
Updated•18 years ago
|
Whiteboard: [baking until 09/08]
Updated•18 years ago
|
Flags: in-testsuite-
Assignee | ||
Comment 11•18 years ago
|
||
This is the initial patch plus the regression fix from bug 351606.
Attachment #237318 -
Flags: approval1.8.1?
Assignee | ||
Updated•18 years ago
|
Attachment #236869 -
Flags: approval1.8.1?
Comment 12•18 years ago
|
||
Comment on attachment 237318 [details] [diff] [review] Version for 1.8.1 with fix from bug 351606 a=schrep for drivers.
Attachment #237318 -
Flags: approval1.8.1? → approval1.8.1+
Assignee | ||
Comment 13•18 years ago
|
||
I committed the patch from comment 11 to MOZILLA_1_8_BRANCH Checking in jsinterp.c; /cvsroot/mozilla/js/src/jsinterp.c,v <-- jsinterp.c new revision: 3.181.2.56; previous revision: 3.181.2.55 done
Keywords: fixed1.8.1
You need to log in
before you can comment on or make changes to this bug.
Description
•