Closed Bug 14044 Opened 25 years ago Closed 22 years ago

jsdtoa.c doesn't check for out-of-memory

Categories

(Core :: JavaScript Engine, defect, P4)

defect

Tracking

()

VERIFIED FIXED
Future

People

(Reporter: waldemar, Assigned: waldemar)

References

Details

(Keywords: js1.5, Whiteboard: QA note: the fix for this is on trunk only (as of 2002-8-12). Note bug 156253)

Attachments

(2 files, 5 obsolete files)

David Gay's code in jsdtoa.c assumes that malloc will never fail.  It will
corrupt memory and/or crash when malloc does fail.  This is a very rare
situation but should be checked and handled properly.

    Waldemar
Status: NEW → ASSIGNED
Attached file Smaller test case (obsolete) —
Please ignore the attachment; I attached it to the wrong bug report.
Setting all Javacript bugs to rginda QA Contact.
QA Contact: cbegle → rginda
Priority: P3 → P4
Target Milestone: --- → Future
Updating QA contact -
QA Contact: rginda → pschwartau
waldemar@netscape.com :
You are assigned on this bug.
Can you add a comment that you are working on it or can you close it ?
(Last comment : 1999-09-17 16:12 )
Attached patch Possible patch. (obsolete) — Splinter Review
Malloc is only used on two places in jsdtoa.c, one is in Balloc() and the other
is in JS_dtobasestr(), the second where it is checked for null returns. This
patch makes Balloc() check for a null return from malloc() and if so avoid
writing to the pointer, returning null. Is it legal for Balloc() to return
null? This patch is untested, how should one test it?
cc'ing reviewers for this patch -
Comment on attachment 73866 [details] [diff] [review]
Possible patch.

r=beard
Attachment #73866 - Flags: review+
To address the question in comment 6:  Nope, it's not currently valid for Balloc
to return null.  This will result in numerous crashes all over jsdtoa.c.  It
looks like in addition to what this patch fixes, we need to fix return values
all over the code, and then check to make sure we haven't leaked anything.

My "malloc failure" generator that I've been using in a number of other bugs
recently is appropriate to test here, provided that we have a JS test that
excersizes all of the allocations here.  (Hopefully, all of the "Number" tests
in the JS testsuite do that.)

I'd also like to run such a test under Purify and PureCoverage to make sure
we've hit it all.

I can take this on (I have all the tools necessary to make it happen, and memory
failure is something that I seem to have boxed myself into lately), but I can't
guarantee speediness.

--scole
I think, though, that I'll wait for the fixes in bug 120992 and bug 85267 to get
checked in, to save myself from merge heck.  (Looks like only slight reviewing
is necessary there, though.)

--scole
Attachment #1737 - Attachment is obsolete: true
Attached patch Proposed Patch (obsolete) — Splinter Review
This big patch checks the return values of each routine in the dtoa suite that
may succumb to out-of-memory errors.  It also slightly changes the API for
JS_strtod: the "err" return parameter may now contain ENOMEM, in addtion to
ERANGE, so callers to this function check for that as well.

This patch contains my diagnostic code as well (turned off via #ifdef
ENABLE_OOM_TESTING); I'm not sure whether it's best to leave it in or to remove
it for checkin.  Opionions welcomed.

This patch has undergone about 3 days of coverage testing; there are still some
paths I haven't been able to make run, but there are very few of them.	(I have
run the portions of the JS testsuite dealing with Number objects and Type
conversion through.)

--scole
Attachment #73866 - Attachment is obsolete: true
Nominating for JS 1.5.
Keywords: js1.5
Need r=, sr= to get this patch in for JS 1.5 -
Comment on attachment 86082 [details] [diff] [review]
Proposed Patch

>+static int allocationNum;               /* which allocation is next? */
>+static int desiredFailure = -1;         /* which allocation should fail? */
>+#ifdef ENABLE_OOM_TESTING
>+    if (desiredFailure == allocationNum++)

Nit: mightn't (++allocationNum == desiredFailure) be a little better in
compiled code, and maybe in clarity?  Then the default value for desiredFailure
could be 0, not -1.

>+    {

Nit: prevailing style in the engine, if not in jsdtoa.c (;-), puts this on the
same line as the if.

0123456789012345678901234567890123456789012345678901234567890123456789012345678
9
>-/* Return b*m + a.  Deallocate the old b.  Both a and m must be between 0 and 65535 inclusive. */
>+/* Return b*m + a.  Deallocate the old b.  Both a and m must be between
>+ * 0 and 65535 inclusive.  NOTE: old b is deallocated on memory
>+ * failure. */

Uber-nit: column 80 is cool, but this seems to wrap before column 74.  Might
fit better with the closing */ indented one space on its own line, too.

>+#ifdef ENABLE_OOM_TESTING
>+    if (desiredFailure == allocationNum++)
>+    {
>+        // Faux allocation, because I'm not getting all of the failure
>+        // paths without it.

Whoop, C++ comment alert!  This is C code.

>@@ -691,6 +793,10 @@
> #ifdef JS_THREADSAFE
>             Bigint *wasted_effort = NULL;
>             p51 = mult(p5, p5);
>+            if (!p51) {
>+                Bfree(b);
>+                return NULL;
>+            }
>             PR_Lock(p5s_lock);
>             if (!p5->next) {
>                 p5->next = p51;
>@@ -704,8 +810,14 @@
>                 Bfree(wasted_effort);
>             }
> #else
>-            p51 = p5->next = mult(p5,p5);
>+            p51 = mult(p5,p5);
>+            if (!p51)
>+            {

Nit: More discordant if-then brace style.

>@@ -2763,9 +2999,21 @@
>             /* We have a fraction. */
>             int32 e, bbits, s2, done;
>             Bigint *b, *s, *mlo, *mhi;
>+
>+            b = s = mlo = mhi = NULL;
>             
>             *p++ = '.';
>             b = d2b(df, &e, &bbits);
>+            if (!b)
>+            {

Same nit.

>+++ jsnum.c	2002/06/03 19:11:51
>@@ -829,7 +829,7 @@
> 
>     /* Use cbuf to avoid malloc */
>     if (length >= sizeof cbuf) {
>-        cstr = (char *) malloc(length + 1);
>+        cstr = (char *) JS_malloc(cx, length + 1);
>         if (!cstr)
>            return JS_FALSE;
>     } else {
>@@ -853,6 +853,13 @@
>     } else {
> 	int err;
> 	d = JS_strtod(cstr, &estr, &err);
>+        if (err == ENOMEM)
>+        {

Please do follow brace-on-if-line style here, jsnum.c is part of the "house",
not a previous house's foundation (as jsdtoa.c arguably is, if it has any
single owner).

>@@ -973,7 +980,7 @@
>              */
> 	    size_t i;
> 	    size_t length = s1 - start;
>-	    char *cstr = (char *) malloc(length + 1);
>+	    char *cstr = (char *) JS_malloc(cx, length + 1);
> 	    char *estr;
>             int err=0;
> 

Free free to expand tabs per the Emacs modeline as you can.

Thanks for doing this, it looks good to me.  I got a little tired of checking
after a while, so an r= from khanson (perhaps reviewing from bottom up in the
file :-) would help.  sr=brendan@mozilla.org with nits picked.

/be
Attachment #86082 - Flags: superreview+
Blocks: 149801
Attached patch Nits Cleaned. (obsolete) — Splinter Review
Nits picked.  Also de-tabbed all of js_strtod and js_strtointeger.  And since
GetNextBinaryDigit was sitting there right between, it got de-tabbed too.  (A
-uw patch is coming next...)

--scole
Attachment #86082 - Attachment is obsolete: true
The "ignore whitespace" patch, for reviewing ease.

--scole
ENOMEM not defined in Mac version
Oh, isn't that nice.   Kenton, I don't have access to a Mac development
environment.  Can you scan for where ERANGE is defined (somewhere in the system
includes, probably) and see if there's an appropriate "no memory" error we can
use for the Mac?

Alternately, we can just define ENOMEM to be (ERANGE+1) since all we really care
is that ENOMEM != ERANGE and ENOMEM != 0.  (Though it would probably be more
appropriate to re-enumerate and make custom dtoa errors instead of using errno
values.)

Does anyone have any opinions about the "right" way to fix this?  (While I'm
waiting for comments, I'll work on a patch that removes the dependency on ENOMEM
and switches to JS_ERANGE and JS_ENOMEM instead, though today's a busy day and
it might take a while.)

--scole
scole, I too am curious about the best way to handle the ENOMEM reference.  I
simply moved the #define ENOMEM outside the conditional compile in file ceerno.
 No need to do an interim patch.
file cerrno
The more I think about it, the more I like JS_ENOMEM and JS_ERANGE.  I only used
ENOMEM because the code that was there passed back the ERANGE error, and ENOMEM
is the same sort of style.  But if it introduces platform-dependence to the
code, then it's not really a winning solution.  (Since *this patch* generates
the ENOMEM condition and not something in the underlying OS, there's no reason
for a platform-dependent solution to this problem.)

My proposed patch (yet to be worked on) translates the ERANGE error that exists
now (and presumably works for all platforms) to JS_ERANGE, and then just uses
the new JS_ENOMEM when an out-of-memory error needs to be generated.  No
platform dependencies there at all --- which means that we won't be plagued by
some odd embedding's compiler support in the future either.  (I hate compiler
configuration bugs...)

[Though maybe these should be JS_DTOA_ERANGE and JS_DTOA_ENOMEM...]

--scole
Ok, here's a version of the fix that removes ENOMEM and ERANGE and replaces
them with JS_DTOA_ERANGE and JS_DTOA_ENOMEM, and eliminates the dependency on
<errno.h>.

--scole
Attachment #87530 - Attachment is obsolete: true
scole, how about a -wu diff?  I'll sr= it this weekend.  Thanks,

/be
Attached patch -wu styleSplinter Review
And what am *I* doing Saturday night?  Making patches.	What a life.  :-P

Here's your -wu patch, Brendan.

--scole
Attachment #87531 - Attachment is obsolete: true
Comment on attachment 88484 [details] [diff] [review]
New patch: No ENOMEM.

sr=brendan@mozilla.org contingent on khanson's r= stamp of approval.  Kenton,
can you please review and if all is well, check this into the trunk and drive
it into the 1.0 branch?  Thanks,

/be
Attachment #88484 - Flags: superreview+
I hate to be picky, but...  Does this patch really merit committal on the 1.0
branch?  It doesn't seem to meet any of the 1.0 criteria.  This patch is a boon
to Spidermonkey embedders, not mozilla-the-browser...

--scole
Comment on attachment 88484 [details] [diff] [review]
New patch: No ENOMEM.

r=khanson
Attachment #88484 - Flags: review+
checked into trunk.  I will seek approval for branch.
verified on a 2nd tinderbox
http://tegu.mozilla.org/graph/query.cgi?testname=startup&tbox=luna&autoscale=1&days=7&avg=1&showpoint=2002:06:24:01:08:42,3182

(on both graphs, the green diamond is the build which first had this checkin)
Tp and Txul don't seem to be affected
Well, I hate to admit it, but I'm not surprised by the timing tests.  I knew
this was going to hurt performance, though it's kind of lousy that it's this
noticable.

I think it'd take a pretty significant redesign of the dtoa code to get the
performance back up *and* get memory safety as well.

--scole
The latest patch is on the trunk but not the branch.  It didn't receive driver
approval because of the large size of the change and the fact that no known
crash has been caused by this deficiency.  So, I agree with Steve Cole,
complexity and degradation of speed are reasons for not including the patch,
while code correctness (possibly a security issue) are reasons for including the
patch.  I would favor inclusion, but its not my call.

I just added bug 156253 to address the speed issues of this patch.

--scole
So if this patch isn't going to get on the branch but is already on the trunk,
can we mark it FIXED?  (And a related question: Is JS 1.5 supposed to match
mozilla1.0.1 or mozilla1.1?  Or are they separate?  In other words, will JS1.5
get rolled from the trunk or from one of the mozilla branches?)

--scole
I would still like to see js1.5 wrap up soon: RC5 at the end of July, Final
release at the end of August?

I think that the js engine should not differ materially until 1.5 releases
between trunk and branch.  We can probably get all the fixes in, although we may
need to wait till 1.2/1.0.2 to get drivers' approval.

So it seems best to me that we fix bug 156253 on branch and trunk, soon.  scole,
do you agree?  What do others think of my release plan sketch-question, above?

/be
[My responses to Brendan's question in comment 35 are in bug 156253.  --scole]
Whiteboard: QA note: the fix for this is on trunk only (as of 2002-8-12). Note bug 156253
Does this bug serve any useful purpose any longer?  Maybe it can be closed.

/be
All right...  This bug was being left open during the "push for 1.0" stage 
because bugs at that time weren't getting marked FIXED until they got checked 
in on the 1.0 branch.  This fix never went there, but has been present in the 
1.1 and 1.2 builds.

So I'm going to mark this FIXED now.
Status: ASSIGNED → RESOLVED
Closed: 22 years ago
Resolution: --- → FIXED
Marking Verified -

For the record, recall this point from Comment #29:
> this seems to have increased mozilla startup (Ts) by about 10ms

And this response from Comment #33:
> I just added bug 156253 to address the speed issues of this patch.
Status: RESOLVED → VERIFIED
Flags: testcase-
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: