Observability of NaN distinctions — is this a concern?

Brandon Benvie bbenvie at mozilla.com
Tue Mar 26 10:39:40 PDT 2013

On 3/26/2013 10:03 AM, Brandon Benvie wrote:
> On 3/26/2013 1:12 AM, Jussi Kalliokoski wrote:
>> The NaN distinction is only observable in the byte array, not if you 
>> extract the value, because at that point it becomes an ES NaN value, 
>> so that example is invalid.
> It becomes observable on the read end by doing:
>     float64array[0] = shouldBeImmutable.foo;
>     new Uint32Array(float64array.buffer)[0]; // or [1] depending on 
> endianness
> ...unless you canonicalize the NaN on either on the read or the write. 
> This is pretty damning.
It does appear that in practice (at least in V8 and SpiderMonkey), the 
attempt to write a different NaN does not succeed. It still is possible 
to use a packed NaN to deliver information as a kind of secret 
communication channel. Demonstration:

   var buff = new ArrayBuffer(8);
   var f64 = new Float64Array(buff);
   var ui32 = new Uint32Array(buff);
   ui32[1] = 0xfff80000; // may need to be 1 depending on endianness

   function packNaN(value){
     ui32[1] = value;
     return f64[1]; // may need to be 0 depending on endianness

   function unpackNaN(nan){
     f64[0] = nan;
     return ui32[0]; // may need to be 1 depending on endianness

   var shouldBeImmutable = Object.freeze({ foo: packNaN(1500) });
   console.log(unpackNaN(shouldBeImmutable.foo)); // 1500
   // the following silently fails in V8 and throws in SpiderMonkey
   Object.defineProperty(shouldBeImmutable, 'foo', { value: 
packNaN(2000) });

More information about the es-discuss mailing list