New Uint8Arrays are sometimes filled with garbage

Unfortunately, I don't have a neat small test case, so please bear with me.

One TweetNaCl-js test with Node.js 4.1 fails, while succeeding with 0.12 and io.js v3.3.1. The test is encrypting a message and comparing the result with a known good value.

To reproduce:

mkdir reproduce
cd reproduce
git clone https://github.com/dchest/tweetnacl-js.git
cd tweetnacl-js
npm install tape
NACL_SRC=nacl.js node ./test/04-secretbox.js | more

Output:

TAP version 13
# nacl.secretbox random test vectors
ok 1 box should be created
ok 2 should be equal
ok 3 box should open
ok 4 should be equal
ok 5 box should be created
not ok 6 should be equal
  ---
    operator: equal
    expected: 'VJViVugBhKeaOvfSlHkTzUQ='
    actual:   'ZpRiVugBhKeaOvfSlHkTzUQ='
    at: Test.<anonymous> (/Users/dchest/reproduce/tweetnacl-js/test/04-secretbox.js:10:17)
  ...

(actual may be different for you)

The cause is in this function in nacl.js:

https://github.com/dchest/tweetnacl-js/blob/master/nacl.js#L990

nacl.secretbox = function(msg, nonce, key) {
  checkArrayTypes(msg, nonce, key);
  checkLengths(key, nonce);
  var m = new Uint8Array(crypto_secretbox_ZEROBYTES + msg.length); // <-- BUG HERE
  var c = new Uint8Array(m.length);
  for (var i = 0; i < msg.length; i++) m[i+crypto_secretbox_ZEROBYTES] = msg[i];
  crypto_secretbox(c, m, m.length, nonce, key);
  return c.subarray(crypto_secretbox_BOXZEROBYTES);
};

This function requires that m must be zero-filled.

If I add console.log after creating m to see what's there:

nacl.secretbox = function(msg, nonce, key) {
  checkArrayTypes(msg, nonce, key);
  checkLengths(key, nonce);
  var m = new Uint8Array(crypto_secretbox_ZEROBYTES + msg.length); // <-- BUG HERE
  console.log(m); // <--- ADDED
  var c = new Uint8Array(m.length);
  for (var i = 0; i < msg.length; i++) m[i+crypto_secretbox_ZEROBYTES] = msg[i];
  crypto_secretbox(c, m, m.length, nonce, key);
  return c.subarray(crypto_secretbox_BOXZEROBYTES);
};

and run the test again, I see that m contains some garbage data (results differ from time to time):

Uint8Array {
  '0': 0,
  '1': 0,
  '2': 0,
  '3': 0,
  '4': 0,
  '5': 0,
  '6': 0,
  '7': 0,
  '8': 0,
  '9': 0,
  '10': 0,
  '11': 0,
  '12': 0,
  '13': 0,
  '14': 0,
  '15': 0,
  '16': 232,
  '17': 0,
  '18': 0,
  '19': 0,
  '20': 0,
  '21': 0,
  '22': 0,
  '23': 0,
  '24': 64,
  '25': 231,
  '26': 96,
  '27': 1,
  '28': 1,
  '29': 0,
  '30': 0,
  '31': 0,
  '32': 0 }

This only happens for this particular 33-byte Uint8Array in this particular setting (e.g. I couldn't reproduce this outside of this test). I can work around this by manually zeroing the array after creating it.

Any ideas? As I said, io.js v3.3.1 and previous Node versions doesn't have this bug.