4

Update: This bug affects v28 and was fixed for v29 onward.


Having a function like this:

function arrMany(len) {
    var a = new Array(len);
}

If the function is called rapidly the length of the produced array sometimes has length of previous call to the function.

Expanding the function to:

function arrMany(len, show) {
    var a = new Array(len);
    if (show) {
        someElementTextA.value = a.length;
        someElementTextB.value = len;
    }
}

And calling by e.g.:

function tick() {
    arrMany(2);
    arrMany(4);
    arrMany(6);
    arrMany(10, true);
}

setInerval(tick, 1000 / 200);

after a while someElementTextA shows the value 6 and not 10.

When this happens, and one turn down fps to for example 1, it keeps spitting out wrong length for a long time.


The behavior typically manifests itself after about 20 seconds on my system.

Tested on: Firefox Linux i686; rv:28.0

Notes:

  1. No action in Browser Console or Web Console.
  2. If Web Console is open the error never occurs.
  3. If Web Console is opened when the error manifests, it corrects itself at once.
  4. Given pt. 3. it is rather hard to debug in a sane way using the browser itself.

Any good fix to this?


Update 1:

Have tested this on Firefox, Chrome and Opera. Firefox is the only browser that manifests the bug. No action in console.

From comments and answer: Does not manifest on Window XP, Firefox v31. Does manifest on @jdigital's system – i.e. it's not local to my system.


Update 2:

Always specifying show in above code does not make any difference.

function tick() {
    arrMany(2, false);
    arrMany(4, false);
    arrMany(6, false);
    arrMany(10, true);
}

Nor does using default parameter. But another point being that show is only for the convenience of the sample code.


As to solution for conundrum saying:

if (arr.length !== len) { arr = new Array(len); }

seems to work. But not sure if is is a fix, or if this can break the same way. Using

if (arr.length !== len) { arr = new Array(len); retry = 1; }

show that retry is done quite frequent.


Another fix, (as in debug testing); but in another way. By adding this inside the function, the array is always of correct length. As in: retry is always 0.

for (retry = 0; arr.length !== len && retry < 10; ++retry) {
    arr = new Array(len);
}

As to question.

  • Question is more if there is any good fix to the bug, not if it is a bug or not.

Any information for why this is happening and if there is any similar code, e.g. not handling Arrays, that can break in the same way is also interesting, but was not part of the original question as such.


Update 3:

For, "what I am trying to do", it is a question about it in the general sense, not specific to a case.

It is not a syntax I usually use, but happens from time to time, usually in some debug or verbose output where using a sparse array is simpler then a loop. But it is then nice to know that it is not reliable.

At the same time I recognize others might have different needs and as such solutions to it, in the broad general sense, is always nice to have.

Then again; tipping it the other way around I guess it would be another argument against ever using it ... ;)

Community
  • 1
  • 1
user13500
  • 3,817
  • 2
  • 26
  • 33
  • Have you checked the console to see if there are any exceptions? – jdigital Mar 29 '14 at 03:49
  • @jdigital: Yes, the console is silent. – user13500 Mar 29 '14 at 03:51
  • 1
    Can't reproduce it on FF 31 on WinXP – Oriol Mar 29 '14 at 03:54
  • If the value eventually rights itself, perhaps your machine is having problems keeping up, and that causes many queued updates (I don't know browser internals so I don't know if they collapse events). I can't reproduce this on Windows: I do see the older value, but it is fixed quickly. – jdigital Mar 29 '14 at 03:55
  • @jdigital: Yes, but even so the array length should be that specified as it is local to the function. In the code where I first came across this the called function do a transform of input based on length. As such the result is messed up because the array length becomes wrong. – user13500 Mar 29 '14 at 04:01
  • pass second argument has default value eg: `function arrMany(len, show = false) {` – Tamil Selvan C Mar 29 '14 at 04:01
  • @TamilSelvan: JavaScript does not have default argument. Anyhow, using `false` for all other calls or the like does no difference make. – user13500 Mar 29 '14 at 04:07
  • Could be a Firefox bug. Chrome looks stable. – jdigital Mar 29 '14 at 04:52
  • @jdigital: Yes, I tested in Chrome and Opera here as well. It's only on FF it bugs. – user13500 Mar 29 '14 at 05:02
  • @user "*JavaScript does not have default argument*". ES6 introduces [default parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/default_parameters), currently only supported by Firefox. But I don't think this will fix the problem... – Oriol Mar 29 '14 at 15:27
  • @TamilSelvan: My bad, was not aware Firefox had implemented that. Anyhow, as I've tried to more clearly explain by update to question, is that the parameter is not the issue. As in: The arguments has correct value, it is `new Array(size)` that fails. – user13500 Mar 29 '14 at 23:44
  • @Oriol: Thanks for correcting me. Was not aware Firefox had implemented that. Anyhow. Have tried to explain more in my Q. – user13500 Mar 29 '14 at 23:45

3 Answers3

2

This worked for me:

function arrMany(w, show) {
    (function () {
        var a = new Array(w);
        if (show) {
            arw1.value = a.length;
            arw2.value = w;
        }
    })();
}

Interesting read: JavaScript's Strange Threaded Nature

This code explores the following property:

(function() { new Object(); })(); is garbage collected properly

Anthony Accioly
  • 21,918
  • 9
  • 70
  • 118
  • Interesting. Guess this comes close to an answer to how to reliable using `new Array(sz)` in a general sense given the (likely) bug. Have done various tests with this approach and I'm not able to reproduce the issue at hand this way. – user13500 Mar 30 '14 at 09:14
  • Well, I'm not a specialist in JavaScript engines, but I don't think that we can blame everything on `new Array` syntax here (at least not as the single culprit). Engines are doing all sorts of stuff (including optimizations of all sorts). While browser implementations are single-threaded, events can be interleaved in strange ways, and variable scopes can also be also rearranged in strange ways. (See http://stackoverflow.com/questions/2734025/is-javascript-guaranteed-to-be-single-threaded). I would definitively file a bug (https://bugzilla.mozilla.org/) and see how firefox developers respond. – Anthony Accioly Mar 30 '14 at 16:50
  • Yes, as per [bug 989586](https://bugzilla.mozilla.org/show_bug.cgi?id=989586) this is now fixed per v31. (v28-v30 is tagged as affected.) Bug caused by e.g. inlining of new Array in JIT by template object used for creating array. I'm not quite getting what is happening there, but the linked case [922270](https://bugzilla.mozilla.org/show_bug.cgi?id=922270) might shed more light then looking at the bug-fix itself, (if interested). – user13500 Apr 02 '14 at 15:12
  • Cool, that was a fast fix ;). My kudos to the FF community (and you for identifying and reporting the bug). In the end the solution was a simple [if](https://hg.mozilla.org/mozilla-central/rev/37d8a465a7b8) to not let the code be inlined by IonMonkey :). – Anthony Accioly Apr 02 '14 at 15:33
1

It looks like a bug in Firefox. This problem does not occur in Chrome etc.
When I add a logging statement:

function arrMany(w, show) {
    var a = new Array(w);
    if (show) {
        if( a.length != w ) {
            console.log(a);
        }
        arw1.value = a.length;
        arw2.value = w;
    }
}

When I run this, I can see that console.log is occasionally triggered, and the Firefox Web Console window shows that the array has 5 elements.

jdigital
  • 11,926
  • 4
  • 34
  • 51
1

If I understand correctly, you want a workaround for this bug, even if it is an ugly hack, as long as it is reliable. If so, consider this approach, which explicitly initializes the array:

function arrMany(w, show) {
    // should be:
    //      var a = new Array(w);
    // but there's a bug in Firefox, see StackOverflow 22726716
    //
    var a = [];
    for( var i = 0; i < w; i++ ) a[i] = undefined;

    if (show) {
        arw1.value = a.length;
        arw2.value = w;
    }
}
jdigital
  • 11,926
  • 4
  • 34
  • 51
  • Yes. This would be good as any. Simply never use `new Array(sz)`. I'm sorry for my vagueness in my question, should have been more clear on intentions. – user13500 Mar 30 '14 at 09:11