Skip to content

Commit

Permalink
Layout: provide fix for node issue 3992
Browse files Browse the repository at this point in the history
The common Buffer.writeInt{L,B}E methods have a bug; if it appears to be
present in the running version of node substitute the fixed code.

See: nodejs/node#3992
  • Loading branch information
pabigot committed Nov 23, 2015
1 parent 97d7388 commit 1153acb
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 0 deletions.
73 changes: 73 additions & 0 deletions lib/Layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,79 @@

var assert = require('assert');

/* Determine whether node issue #3992 is fixed, and if not replace the
* Buffer functions with ones that work correctly.
*
* See: https://github.com/nodejs/node/issues/3992 */
var issue_3992_is_resolved = (function () {
var buf = new Buffer(2);
buf.writeIntLE(-0x100, 0, 2);
return (0xFF === buf[1]);
})();
/* NB: Backfill code modified from node lib/buffer.js as of
* 8bc80386879538de63cd6f2aef288f59324eb004 (2015-11-20) */
/* istanbul ignore next */
function checkInt(buffer, value, offset, ext, max, min) {
if (!(buffer instanceof Buffer))
throw new TypeError('"buffer" argument must be a Buffer instance');
if (value > max || value < min)
throw new TypeError('"value" argument is out of bounds');
if (offset + ext > buffer.length)
throw new RangeError('Index out of range');
}
/* The grotesquery here is because jshint whines about strict mode
* violations if the function doesn't appear to be a method, and about
* defining functions within a block if the test is in an if
* statement. */
Buffer.prototype.writeIntLE = issue_3992_is_resolved ? Buffer.prototype.writeIntLE : function(value, offset, byteLength, noAssert) {
value = +value;
offset = offset >>> 0;
if (!noAssert) {
checkInt(this,
value,
offset,
byteLength,
Math.pow(2, 8 * byteLength - 1) - 1,
-Math.pow(2, 8 * byteLength - 1));
}

var i = 0;
var mul = 1;
var sub = 0;
this[offset] = value;
while (++i < byteLength && (mul *= 0x100)) {
if (value < 0 && sub === 0 && this[offset + i - 1] !== 0)
sub = 1;
this[offset + i] = ((value / mul) >> 0) - sub;
}

return offset + byteLength;
};
Buffer.prototype.writeIntBE = issue_3992_is_resolved ? Buffer.prototype.writeIntBE : function(value, offset, byteLength, noAssert) {
value = +value;
offset = offset >>> 0;
if (!noAssert) {
checkInt(this,
value,
offset,
byteLength,
Math.pow(2, 8 * byteLength - 1) - 1,
-Math.pow(2, 8 * byteLength - 1));
}

var i = byteLength - 1;
var mul = 1;
var sub = 0;
this[offset + i] = value;
while (--i >= 0 && (mul *= 0x100)) {
if (value < 0 && sub === 0 && this[offset + i + 1] !== 0)
sub = 1;
this[offset + i] = ((value / mul) >> 0) - sub;
}

return offset + byteLength;
};

/* istanbul ignore next */
/* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger */
Number.isInteger = Number.isInteger || function(value) {
Expand Down
9 changes: 9 additions & 0 deletions test/LayoutTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ var assert = require("assert"),
lo = require("../lib/Layout");

suite("Layout", function () {
suite("Buffer", function () {
test("issue 3992", function () {
var buf = new Buffer(4);
buf.writeIntLE(-0x120000, 0, 4);
assert.deepEqual(buf.toJSON().data, [ 0x00, 0x00, 0xee, 0xff ]);
buf.writeIntBE(-0x120000, 0, 4);
assert.deepEqual(buf.toJSON().data, [ 0xff, 0xee, 0x00, 0x00 ]);
});
});
suite("Layout", function () {
test("anonymous ctor", function () {
var d = new lo.Layout(8);
Expand Down

0 comments on commit 1153acb

Please sign in to comment.