Subj : Re: JSVAL_IS_NUMBER(NaN) == TRUE (!?) To : Brendan Eich From : Rob Swindell Date : Sun Feb 20 2005 01:16 am Re: Re: JSVAL_IS_NUMBER(NaN) == TRUE (!?) By: Brendan Eich to Rob Swindell on Fri Feb 18 2005 02:55 pm > > I found it odd that if jsval is NaN, a test of JSVAL_IS_NUMBER(jsval) woul > > evaluate as TRUE. > > > Sure, it's of "number" type (see also typeof(0/0)). It just seemed illogical (to me) that: is (not a number) a number? would evaluate to a true statement. > > And my native methods don't consider NaN a valid number either, so I neede > > valid test for is number, but non NaN, so I came up with: > > > > #include /* JSDOUBLE_IS_NaN() */ > > > > JSBool > > jsval_isNaN(JSContext *cx, jsval v) > > { > > jsdouble d; > > > > if(JSVAL_IS_DOUBLE(v)) { > > if (!JS_ValueToNumber(cx, v, &d)) > > > No need to convert v to number if it's already a double (which is a > subtype of number). But JSDOUBLE_IS_NaN() requires a double argument. You can't simply typecast a jsval to a jsdouble, so it must be converted (before it may be checked for NaN). Or am I missing something? > > return JS_FALSE; > > if(JSDOUBLE_IS_NaN(d)) > > return JS_TRUE; > > } > > return JS_FALSE; > > } > > > > // Replacement for JSVAL_IS_NUMBER(): > > #define JSVAL_IS_NUM(cx,v) (JSVAL_IS_NUMBER(v) && !jsval_isNaN(cx,v)) > > > > I'm surprised there's not something like this already in the jsapi. > > Yeah, it hasn't come up till now. Most native methods should let NaNs > flow through and produce NaN results. Why not yours? I have some native methods which parse through the passed arguments and use the values passed based on their type as well as their order. Simple stated, my native functions aren't going to like a NaN value when they expect an number. These functions attempt to convert a "number" argument to an integer using JS_ValueToInt32(). The test for a "number" was done using JSVAL_IS_NUMBER, which if the value is NaN, can't logically produce a valid int32 value. I don't know if this is the reason, but js32.dll v1.5 pre-release 5a (the version used in the current release of my product) will crash if NaN is passed to JS_ValueToInt32. Here's an example callstack of one such crash: NTDLL! 77f813b1() Decompile(SprintStack * 0x035dc4b0, unsigned char * 0x03eaf4ce, int 0x00000003) line 1860 + 47 bytes js_DecompileCode(JSPrinter * 0x05622208, JSScript * 0x03eaf400, unsigned char * 0x03eaf4ce, unsigned int 0x00000003) line 2347 + 17 bytes js_DecompileValueGenerator(JSContext * 0x02f42b70, int 0x00000001, long 0x030b6322, JSString * 0x00000000) line 2669 + 27 bytes js_ValueToInt32(JSContext * 0x02f42b70, long 0x030b6322, long * 0x035dc89c) line 765 + 17 bytes JS_ValueToInt32(JSContext * 0x02f42b70, long 0x030b6322, long * 0x035dc89c) line 552 + 17 bytes js_get_msg_header(JSContext * 0x02f42b70, JSObject * 0x055f13a0, unsigned int 0x00000002, long * 0x03ea401c, long * 0x035dcd48) line 643 + 32 bytes js_Invoke(JSContext * 0x02f42b70, unsigned int 0x00000002, unsigned int 0x00000000) line 843 + 26 bytes js_Interpret(JSContext * 0x02f42b70, long * 0x035de164) line 2852 + 15 bytes js_Execute(JSContext * 0x02f42b70, JSObject * 0x030b6340, JSScript * 0x03ea3700, JSStackFrame * 0x00000000, unsigned int 0x00000000, long * 0x035de164) line 1055 + 13 bytes JS_ExecuteScript(JSContext * 0x02f42b70, JSObject * 0x030b6340, JSScript * 0x03ea3700, long * 0x035de164) line 3373 + 25 bytes exec_ssjs(http_session_t * 0x035de234, char * 0x035de351) line 2758 + 36 bytes respond(http_session_t * 0x035de234) line 2809 + 18 bytes http_session_thread(void * 0x00000000) line 2943 + 12 bytes _threadstart(void * 0x050286f0) line 187 + 13 bytes KERNEL32! 7c57b388() I don't know whether it *should* be legal for JS_ValueToInt32() to convert a NaN jsval or not, but in any case, it's not what I intended this method to do if passed such a value. It instead should return the proper error result, as it does now, using the JSVAL_IS_NUM() macro to test for a valid number value (not including NaN). I'm assuming the root cause of the above crash has been fixed in later versions of SpiderMonkey as tests conducted with newer libjs.so's (for Linux and FreeBSD) did not crash. But the crash highlighted the fact my methods were attempting to process the passed value as a valid number, when in fact it was not. digital man Snapple "Real Fact" #135: A single coffee tree produces only about a pound of coffee beans per year. .