Closed Bug 102725 Opened 23 years ago Closed 23 years ago

gcc -O2 problems converting numbers to strings

Categories

(Core :: JavaScript Engine, defect)

defect
Not set
normal

Tracking

()

VERIFIED FIXED

People

(Reporter: dbaron, Assigned: khanson)

Details

Attachments

(2 files, 1 obsolete file)

I've been seeing this problem with a Linux gcc 3.0.1 build with -O2, and waterson saw it on a Linux gcc 2.95.2 build with -O2. It prevents jrgm's performance tests from working on such builds. In some cases calling toString() on a number causes the first two digits to appears as a ':' instead. However, when toString is called a second time on the same number, the result is correct. (When I stick in a JS_GetStringBytes call to look at the number at the point when it's wrong the first time, it stays wrong the second time as well.) Expected results from testcase alerts (example; date dependent): 1002049323261 1002049323261 1002049323261 124 Actual results: :02049323261 1002049323261 1002049323261 124
Attached file testcase (deleted) —
Debugging the problem, it seemed like there were two garbage characters at the beginning of the buffer at the end of js_NumberToString before the real string began, but otherwise that string was correct. Yet the result in num_toString seemed correct when looking through the result of JS_GetStringChars, unless JS_GetStringBytes were called first. Or something like that... And it is worth noting that num_toString was only called once for the number for the three toString calls.
Reassigning to Kenton. Here is the text of David's testcase - var foo = (new Date()).getTime(); ++foo; var bar = foo.toString(); var baz = foo.toString(); var bax = foo.toString(); alert(bar); alert(baz); alert(bax); var ba = 124; alert(ba.toString());
Assignee: rogerl → khanson
This smells of memory ambiguity -- more of our (jsdouble*) can alias (uint32*) assumptions, which standard C and C99 do not help us implement (:-(). /be
Does -fno-strict-aliasing affect the problem? That would help confirm or deny brendan's suspicion.
This is probably a dupe of/related to bug 94375. See that bug for various compiler flags tested (although that was only with -O3, and didn't show on -O2. I've seen that problem on my gcc-2.96 -O2 builds, though)
Using -fno-strict-aliasing does fix the problem with gcc-2.96-81 (RH). My test was, with the standalone js build, the following: var foo = (new Date()).getTime(); foo.toString(); foo.toString();
David's testcase added to JS testsuite: mozilla/js/tests/js1_5/Regress/regress-102725.js Can be run in the interactive JS shell as follows: [//d/JS_TRUNK/mozilla/js/src/WINNT4.0_DBG.OBJ] ./js js> load('../../tests/js1_5/shell.js') js> load('../../tests/js1_5/Regress/regress-102725.js') BUGNUMBER: 102725 STATUS: Testing converting numbers to strings This denotes success. A failure would look something like: BUGNUMBER: 102725 STATUS: Testing converting numbers to strings FAILED!: [reported from test()] Section 1 of test - FAILED!: [reported from test()] Expected value '1002677799937XYZ', Actual value '1002677799937'
Compiling only jsdtoa.c with -fno-strict-aliasing is sufficient to fix the problem.
drepper, any ideas on this? could this be similar to the aliasing problem we uncovered in jsnum.h?
Has anybody looked which path the js_NumberToString takes? I'd expect js_NumberToString > JS_snprintf > cvt_l > fill_n In neither of these functions I've seen an unclean cast which could cause aliasing problems. If somebody could tell me which functions are actually called in case of the failing print I'll look at it more deeply. Sorry, don't have the time in the moment to do this myself.
How about this code at line 244 of jsdtoa.c ? #if defined (IEEE_8087) && !defined(__arm) && !defined(__arm32__) && !defined(__arm26__) #define word0(x) ((ULong *)&x)[1] #define word1(x) ((ULong *)&x)[0] #else #define word0(x) ((ULong *)&x)[0] #define word1(x) ((ULong *)&x)[1] #endif This looks like exactly what we had to fix in jsnum.h... why isn't this code using those macros?
> How about this code at line 244 of jsdtoa.c ? I wasn't looking at that code. I assumes the integer arithmetic is using 64-bit and therefore 1002049323261 is an integer. OK, jsdtoa.c indeed has two problems: line 244ff word0(), word1() line 256ff Storeinc() The cleanest solution is for word0()/word1() to be changed to two sets of macros: get_word1()/get_word1() and set_word0()/set_word1(). Storeinc() is used only for storing so this is OK. Once you've done this you can easily adapt the macros from jsnum.h for this purpose. Note, though, how the endianess in the access is handled differently. In jsnum.h the IS_LITTLE_ENDIAN macro is used, jsdtoa.c uses explicit tests for Arm.
Ok, I think I have a patch that fixes the word0/word1 problems, but I'm not sure what to do about Storeinc(). Do we need similar helpers to access the high and low 16 bits of a 32 bit integer?
> but I'm not sure what to do about Storeinc(). Do we need similar helpers to > access the high and low 16 bits of a 32 bit integer? I have no idea why the Storeinc macro is that complicated anyway. Somebody tried to optimize by hand what the compiler should better do itself. I would simply remove the current definitions and use instead the one given in the comment above: #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
Attached patch patch (obsolete) (deleted) — Splinter Review
> Created an attachment (id=53433) *Looks* (haven't tested it) fine to me. Two things: - I think it is generally bad to not use macro parameters of the macro is in fact used like a function. Even if this means simply passing the parameters through. - I know I gave the form of Storeinc in the comment as the preferred form but it should be changed slightly just to be save: #define Storeinc(a,b,c) (*(a)++ = (b) << 16 | (c) & 0xffff) Note the parenthesis around the parameters. It might not be necessary right now but these are the ugliest bugs to track down so it's better to be cautious.
bryner: jsdtoa.c is derived from the David M. Gay / Guy Steele portable double-to-string code of olde. It wasn't integrated into the JS sources as well as I wanted, and I never had time to fix it myself. Thanks for the patch. A couple of nits: - Don't we have an inconsistency still between jsdtoa.c and jsnum.h on arm? Fix that and we won't need the proliferation of BIGENDIAN_ and LITTLEENDIAN_ macros. - drepper's right, always parenthesize macro parameters in the definition. - Please respect the 80th column (leave it empty for Emacs) in JS sources. /be
> Don't we have an inconsistency still between jsdtoa.c and jsnum.h on arm? > Fix that and we won't need the proliferation of BIGENDIAN_ and LITTLEENDIAN_ > macros. The Arm situation is really ugly. This is the <bits/endian.h> file I have in glibc: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /* ARM is (usually) little-endian but with a big-endian FPU. */ #ifndef _ENDIAN_H # error "Never use <bits/endian.h> directly; include <endian.h> instead." #endif #ifdef __ARMEB__ #define __BYTE_ORDER __BIG_ENDIAN #else #define __BYTE_ORDER __LITTLE_ENDIAN #endif #define __FLOAT_WORD_ORDER __BIG_ENDIAN ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This means that Arm is normally little endian but the floating-point format is always big endian. You will never be able to handle endianness in integer and floating-point numbers with one macros. Having this said it is clear that the current jsnum.h macros (even before the changes made for aliasing some time back) could never have worked for Arm. If you want to solve the problem for good introduce in some central place macros just like those above.
Attached patch patch v2 (deleted) — Splinter Review
Attachment #53433 - Attachment is obsolete: true
Comment on attachment 53499 [details] [diff] [review] patch v2 Looks good to me, thanks again. Uber-nit: JS major comments look like this: /* * Blah blah blah * (blah). */ Note the "empty" first line is /*\n. Fix that, in your earlier comment and in Stefan's, and sr=brendan@mozilla.org. /be
Attachment #53499 - Flags: superreview+
Comment on attachment 53499 [details] [diff] [review] patch v2 r=bbaetz
Attachment #53499 - Flags: review+
checked in.
Status: NEW → RESOLVED
Closed: 23 years ago
Resolution: --- → FIXED
dbaron@fas.harvard.edu: if you get a chance, would you be able to verify this fix? I was never able to see the failure - thanks.
Verified with my -O2 js shell and a .js file reduced from the testcase. /be
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: