From c1d2975b088d6bc472c0e5dffab4a05271057098 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Tue, 19 May 2015 15:21:01 -0700 Subject: [PATCH 01/61] buffer: add readInt64BE, readInt64LE, readUInt64BE, and readUInt64LE --- lib/buffer.js | 32 ++++++++++++++++++ src/node_buffer.cc | 82 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/lib/buffer.js b/lib/buffer.js index 1b9c68465d6b03..5d3d7786de0371 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -818,6 +818,38 @@ Buffer.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) { }; +Buffer.prototype.readInt64LE = function readInt64LE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) + checkOffset(offset, 8, this.length); + return binding.readInt64LE(this, offset); +}; + + +Buffer.prototype.readInt64BE = function readInt64BE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) + checkOffset(offset, 8, this.length); + return binding.readInt64BE(this, offset); +}; + + +Buffer.prototype.readUInt64LE = function readUInt64LE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) + checkOffset(offset, 8, this.length); + return binding.readUInt64LE(this, offset); +}; + + +Buffer.prototype.readUInt64BE = function readUInt64BE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) + checkOffset(offset, 8, this.length); + return binding.readUInt64BE(this, offset); +}; + + function checkInt(buffer, value, offset, ext, max, min) { if (!(buffer instanceof Buffer)) throw new TypeError('buffer must be a Buffer instance'); diff --git a/src/node_buffer.cc b/src/node_buffer.cc index fca08599e50feb..26fb0a508e5d4e 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -9,8 +9,28 @@ #include "v8.h" #include +#include +#include +#include #include +#include +#include +#include +#include // std::hex + +#ifdef _WIN32 + #define __alignof__ __alignof + #define snprintf(buf, bufSize, format, arg) _snprintf_s(buf, bufSize, _TRUNCATE, format, arg) + #define strtoll _strtoi64 + #define strtoull _strtoui64 + #define PRId64 "lld" + #define PRIu64 "llu" +#else + #define __STDC_FORMAT_MACROS + #include +#endif + #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define CHECK_NOT_OOB(r) \ @@ -35,6 +55,12 @@ CHECK_NOT_OOB(end <= end_max); \ size_t length = end - start; +// used by the ReadInt64 functions to determine whether to return a Number +// or String, based on whether or not a JS Number will lose precision. +// http://stackoverflow.com/q/307179/376773 +#define JS_MAX_INT +9007199254740992LL +#define JS_MIN_INT -9007199254740992LL + namespace node { namespace Buffer { @@ -499,6 +525,58 @@ void ReadDoubleBE(const FunctionCallbackInfo& args) { } +template +void ReadInt64Generic(const FunctionCallbackInfo& args, const char *formatter) { + Environment* env = Environment::GetCurrent(args); + + ARGS_THIS(args[0].As()); + + uint32_t offset = args[1]->Uint32Value(); + CHECK_LE(offset + sizeof(T), obj_length); + + union NoAlias { + T val; + char bytes[sizeof(T)]; + }; + + union NoAlias na; + const char* ptr = static_cast(obj_data) + offset; + memcpy(na.bytes, ptr, sizeof(na.bytes)); + if (endianness != GetEndianness()) + Swizzle(na.bytes, sizeof(na.bytes)); + + if (na.val < min || na.val > max) { + // return a String + char strbuf[20]; + int len = snprintf(strbuf, sizeof(strbuf), formatter, na.val); + args.GetReturnValue().Set( node::OneByteString(env->isolate(), strbuf, len) ); + } else { + // return a Number + args.GetReturnValue().Set(static_cast(na.val)); + } +} + + +void ReadInt64LE(const FunctionCallbackInfo& args) { + ReadInt64Generic(args, "%" PRId64); +} + + +void ReadInt64BE(const FunctionCallbackInfo& args) { + ReadInt64Generic(args, "%" PRId64); +} + + +void ReadUInt64LE(const FunctionCallbackInfo& args) { + ReadInt64Generic(args, "%" PRIu64); +} + + +void ReadUInt64BE(const FunctionCallbackInfo& args) { + ReadInt64Generic(args, "%" PRIu64); +} + + template uint32_t WriteFloatGeneric(const FunctionCallbackInfo& args) { ARGS_THIS(args[0].As()) @@ -750,6 +828,10 @@ void Initialize(Handle target, env->SetMethod(target, "readDoubleLE", ReadDoubleLE); env->SetMethod(target, "readFloatBE", ReadFloatBE); env->SetMethod(target, "readFloatLE", ReadFloatLE); + env->SetMethod(target, "readInt64BE", ReadInt64BE); + env->SetMethod(target, "readInt64LE", ReadInt64LE); + env->SetMethod(target, "readUInt64BE", ReadUInt64BE); + env->SetMethod(target, "readUInt64LE", ReadUInt64LE); env->SetMethod(target, "writeDoubleBE", WriteDoubleBE); env->SetMethod(target, "writeDoubleLE", WriteDoubleLE); From 1871fbff3b1c04a240df7ac6c018388f958a66ff Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Tue, 19 May 2015 15:22:38 -0700 Subject: [PATCH 02/61] buffer: add writeInt64BE, writeInt64LE, writeUInt64BE, and writeUInt64LE --- lib/buffer.js | 47 +++++++++++++++++++++++++++++++ src/node_buffer.cc | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) diff --git a/lib/buffer.js b/lib/buffer.js index 5d3d7786de0371..f0ba36cdbdc21f 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -1103,6 +1103,53 @@ Buffer.prototype.writeDoubleBE = function writeDoubleBE(val, offset, noAssert) { return offset + 8; }; + +function checkInt64(buffer, value, offset, ext) { + if (!(buffer instanceof Buffer)) + throw new TypeError('buffer must be a Buffer instance'); + if (!(typeof value === 'string' || typeof value === 'number')) + throw new TypeError('must pass a "string" or "number" for value'); + if (offset + ext > buffer.length) + throw new RangeError('index out of range'); +} + + +Buffer.prototype.writeInt64LE = function writeInt64LE(val, offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) + checkInt64(this, val, offset, 8); + binding.writeInt64LE(this, val, offset); + return offset + 8; +}; + + +Buffer.prototype.writeInt64BE = function writeInt64BE(val, offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) + checkInt64(this, val, offset, 8); + binding.writeInt64BE(this, val, offset); + return offset + 8; +}; + + +Buffer.prototype.writeUInt64LE = function writeUInt64LE(val, offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) + checkInt64(this, val, offset, 8); + binding.writeUInt64LE(this, val, offset); + return offset + 8; +}; + + +Buffer.prototype.writeUInt64BE = function writeUInt64BE(val, offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) + checkInt64(this, val, offset, 8); + binding.writeUInt64BE(this, val, offset); + return offset + 8; +}; + + // ES6 iterator var ITERATOR_KIND_KEYS = 1; diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 26fb0a508e5d4e..0fdeb54dcfb6ab 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -619,6 +619,72 @@ void WriteDoubleBE(const FunctionCallbackInfo& args) { } +template +uint32_t WriteInt64Generic(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + + ARGS_THIS(args[0].As()) + + T val; + if (args[1]->IsNumber()) { + val = args[1]->IntegerValue(); + } else if (args[1]->IsString()) { + // Have to do this because strtoll/strtoull doesn't set errno to 0 on success + errno = 0; + v8::String::Utf8Value str(args[1]); + val = strtoT(*str, NULL, 0); + + if (errno != 0) { + if (errno == EINVAL) { + env->ThrowTypeError("value is invalid"); + } else if (errno == ERANGE) { + env->ThrowRangeError("value is out-of-range"); + } else { + env->ThrowError("unspecified error"); + } + return 0; + } + } else { + env->ThrowTypeError("Argument must be a string or number"); + return 0; + } + + uint32_t offset = args[2]->Uint32Value(); + CHECK_LE(offset + sizeof(T), obj_length); + + union NoAlias { + T val; + char bytes[sizeof(T)]; + }; + + union NoAlias na = { val }; + char* ptr = static_cast(obj_data) + offset; + if (endianness != GetEndianness()) + Swizzle(na.bytes, sizeof(na.bytes)); + memcpy(ptr, na.bytes, sizeof(na.bytes)); + return offset + sizeof(na.bytes); +} + + +void WriteInt64LE(const FunctionCallbackInfo& args) { + args.GetReturnValue().Set(WriteInt64Generic(args)); +} + + +void WriteInt64BE(const FunctionCallbackInfo& args) { + args.GetReturnValue().Set(WriteInt64Generic(args)); +} + +void WriteUInt64LE(const FunctionCallbackInfo& args) { + args.GetReturnValue().Set(WriteInt64Generic(args)); +} + + +void WriteUInt64BE(const FunctionCallbackInfo& args) { + args.GetReturnValue().Set(WriteInt64Generic(args)); +} + + void ByteLengthUtf8(const FunctionCallbackInfo &args) { CHECK(args[0]->IsString()); @@ -837,6 +903,10 @@ void Initialize(Handle target, env->SetMethod(target, "writeDoubleLE", WriteDoubleLE); env->SetMethod(target, "writeFloatBE", WriteFloatBE); env->SetMethod(target, "writeFloatLE", WriteFloatLE); + env->SetMethod(target, "writeInt64BE", WriteInt64BE); + env->SetMethod(target, "writeInt64LE", WriteInt64LE); + env->SetMethod(target, "writeUInt64BE", WriteUInt64BE); + env->SetMethod(target, "writeUInt64LE", WriteUInt64LE); } From ca5549498a42ed5a4ab617e6c9afd4fcf672a333 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Tue, 19 May 2015 15:25:34 -0700 Subject: [PATCH 03/61] buffer: add address() function --- lib/buffer.js | 5 +++++ src/node_buffer.cc | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/lib/buffer.js b/lib/buffer.js index f0ba36cdbdc21f..b6a0576bf015a5 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -454,6 +454,11 @@ Buffer.prototype.fill = function fill(val, start, end) { }; +Buffer.prototype.address = function address() { + return binding.address(this); +}; + + // XXX remove in v0.13 Buffer.prototype.get = util.deprecate(function get(offset) { offset = ~~offset; diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 0fdeb54dcfb6ab..f40d4a294d7581 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -838,6 +838,28 @@ void IndexOfNumber(const FunctionCallbackInfo& args) { ptr ? static_cast(ptr_char - obj_data) : -1); } +void Address(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + + ASSERT(args[0]->IsObject()); + ARGS_THIS(args[0].As()) + + int64_t offset = args[1]->IntegerValue(); + char *ptr = obj_data + offset; + + // pointer-size * 2 (for hex printout) + 1 null byte + char strbuf[(sizeof(char *) * 2) + 1]; + + // using stringstream and std::hex here instead of printf(%#) because + // of cross-platform differences experienced with the later + std::stringstream stream; + stream.rdbuf()->pubsetbuf(strbuf, sizeof(strbuf)); + + stream << std::hex << (intptr_t)ptr << '\0'; + + args.GetReturnValue().Set( node::OneByteString(env->isolate(), strbuf, strlen(strbuf)) ); +} + // pass Buffer object to load prototype methods void SetupBufferJS(const FunctionCallbackInfo& args) { @@ -883,6 +905,7 @@ void Initialize(Handle target, env->SetMethod(target, "setupBufferJS", SetupBufferJS); + env->SetMethod(target, "address", Address); env->SetMethod(target, "byteLengthUtf8", ByteLengthUtf8); env->SetMethod(target, "compare", Compare); env->SetMethod(target, "fill", Fill); From 6c32b7efcc2b631e26b84bcb300f92cac73db09d Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Tue, 19 May 2015 15:28:27 -0700 Subject: [PATCH 04/61] buffer: add 0-length NULL pointer Buffer to exports Seems useful to add for completeness-sake. Presumably useful for i.e. writing the null terminator to a null-terminated C array. --- lib/buffer.js | 4 ++++ src/node_buffer.cc | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/buffer.js b/lib/buffer.js index b6a0576bf015a5..3aecffbb910aff 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -202,6 +202,10 @@ NativeBuffer.prototype = Buffer.prototype; // add methods to Buffer prototype binding.setupBufferJS(NativeBuffer); +// move the static NULL pointer buffer to `exports` instead of `Buffer.prototype` +exports.NULL = NativeBuffer.prototype.NULL; +delete NativeBuffer.prototype.NULL; + // Static methods diff --git a/src/node_buffer.cc b/src/node_buffer.cc index f40d4a294d7581..6116ca6b88baac 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -118,6 +118,11 @@ size_t Length(Handle obj) { return obj->GetIndexedPropertiesExternalArrayDataLength(); } +Local WrapNullPointer(Environment* env) { + size_t buf_size = 0; + char *ptr = reinterpret_cast(NULL); + return Buffer::Use(env, ptr, buf_size); +} Local New(Isolate* isolate, Handle string, enum encoding enc) { EscapableHandleScope scope(isolate); @@ -895,8 +900,11 @@ void SetupBufferJS(const FunctionCallbackInfo& args) { proto->ForceSet(env->offset_string(), Uint32::New(env->isolate(), 0), v8::ReadOnly); -} + // instantiate the static NULL pointer buffer here + // (gets moved to "buffer" module exports in `lib/buffer.js`) + proto->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "NULL"), WrapNullPointer(env)); +} void Initialize(Handle target, Handle unused, From 1f6508892b6418dc1099c394a64a594e1d47951b Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Tue, 19 May 2015 15:31:24 -0700 Subject: [PATCH 05/61] buffer: add the hex address to the inspect() output --- lib/buffer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/buffer.js b/lib/buffer.js index 3aecffbb910aff..a2b3f870d980d5 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -402,7 +402,7 @@ Buffer.prototype.inspect = function inspect() { if (this.length > max) str += ' ... '; } - return '<' + this.constructor.name + ' ' + str + '>'; + return '<' + this.constructor.name + '@0x' + this.address() + ' ' + str + '>'; }; From b8eac6db4cf8c632fa2816ba8c98ca5c0ca05fab Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Tue, 19 May 2015 15:50:54 -0700 Subject: [PATCH 06/61] buffer: add isNull() function --- lib/buffer.js | 5 +++++ src/node_buffer.cc | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/buffer.js b/lib/buffer.js index a2b3f870d980d5..c99f81fe2bf66e 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -463,6 +463,11 @@ Buffer.prototype.address = function address() { }; +Buffer.prototype.isNull = function isNull() { + return binding.isNull(this); +}; + + // XXX remove in v0.13 Buffer.prototype.get = util.deprecate(function get(offset) { offset = ~~offset; diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 6116ca6b88baac..fa2547c3db5db9 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -843,6 +843,16 @@ void IndexOfNumber(const FunctionCallbackInfo& args) { ptr ? static_cast(ptr_char - obj_data) : -1); } +void IsNull(const FunctionCallbackInfo& args) { + ASSERT(args[0]->IsObject()); + ARGS_THIS(args[0].As()) + + int64_t offset = args[1]->IntegerValue(); + char *ptr = obj_data + offset; + + args.GetReturnValue().Set( ptr == NULL ); +} + void Address(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -920,6 +930,7 @@ void Initialize(Handle target, env->SetMethod(target, "indexOfBuffer", IndexOfBuffer); env->SetMethod(target, "indexOfNumber", IndexOfNumber); env->SetMethod(target, "indexOfString", IndexOfString); + env->SetMethod(target, "isNull", IsNull); env->SetMethod(target, "readDoubleBE", ReadDoubleBE); env->SetMethod(target, "readDoubleLE", ReadDoubleLE); From a9cdb38b410a79b5d58d9b2639b4212e5a9c089d Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Wed, 20 May 2015 12:17:49 -0700 Subject: [PATCH 07/61] buffer: remove "base" variable name from template --- src/node_buffer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index fa2547c3db5db9..e09dbdcd73289e 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -624,7 +624,7 @@ void WriteDoubleBE(const FunctionCallbackInfo& args) { } -template +template uint32_t WriteInt64Generic(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); From e338a929c5bf4e456a085d167e565f1cd1a0adf6 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Wed, 20 May 2015 12:19:07 -0700 Subject: [PATCH 08/61] buffer: return the int64 write binding values --- lib/buffer.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/buffer.js b/lib/buffer.js index c99f81fe2bf66e..10852ce409a6c9 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -1132,8 +1132,7 @@ Buffer.prototype.writeInt64LE = function writeInt64LE(val, offset, noAssert) { offset = offset >>> 0; if (!noAssert) checkInt64(this, val, offset, 8); - binding.writeInt64LE(this, val, offset); - return offset + 8; + return binding.writeInt64LE(this, val, offset); }; @@ -1141,8 +1140,7 @@ Buffer.prototype.writeInt64BE = function writeInt64BE(val, offset, noAssert) { offset = offset >>> 0; if (!noAssert) checkInt64(this, val, offset, 8); - binding.writeInt64BE(this, val, offset); - return offset + 8; + return binding.writeInt64BE(this, val, offset); }; @@ -1150,8 +1148,7 @@ Buffer.prototype.writeUInt64LE = function writeUInt64LE(val, offset, noAssert) { offset = offset >>> 0; if (!noAssert) checkInt64(this, val, offset, 8); - binding.writeUInt64LE(this, val, offset); - return offset + 8; + return binding.writeUInt64LE(this, val, offset); }; @@ -1159,8 +1156,7 @@ Buffer.prototype.writeUInt64BE = function writeUInt64BE(val, offset, noAssert) { offset = offset >>> 0; if (!noAssert) checkInt64(this, val, offset, 8); - binding.writeUInt64BE(this, val, offset); - return offset + 8; + return binding.writeUInt64BE(this, val, offset); }; From af8bff410a3f88b9dd5543b3573b01068e9419c1 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Wed, 20 May 2015 12:26:14 -0700 Subject: [PATCH 09/61] buffer: add readPointerLE and readPointerBE --- lib/buffer.js | 12 ++++++++++++ src/node_buffer.cc | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/lib/buffer.js b/lib/buffer.js index 10852ce409a6c9..9969b934ec78af 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -864,6 +864,18 @@ Buffer.prototype.readUInt64BE = function readUInt64BE(offset, noAssert) { }; +Buffer.prototype.readPointerLE = function readPointerLE(offset, length, noAssert) { + offset = offset >>> 0; + return binding.readPointerLE(this, offset, length); +}; + + +Buffer.prototype.readPointerBE = function readPointerBE(offset, length, noAssert) { + offset = offset >>> 0; + return binding.readPointerBE(this, offset, length); +}; + + function checkInt(buffer, value, offset, ext, max, min) { if (!(buffer instanceof Buffer)) throw new TypeError('buffer must be a Buffer instance'); diff --git a/src/node_buffer.cc b/src/node_buffer.cc index e09dbdcd73289e..7b25f744c5b837 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -582,6 +582,44 @@ void ReadUInt64BE(const FunctionCallbackInfo& args) { } +template +void ReadPointerGeneric(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + EscapableHandleScope scope(env->isolate()); + + ARGS_THIS(args[0].As()); + + uint32_t offset = args[1]->Uint32Value(); + CHECK_LE(offset + sizeof(char *), obj_length); + + size_t size = args[2]->Uint32Value(); + + char* ptr = static_cast(obj_data) + offset; + + union NoAlias { + char* val; + char bytes[sizeof(char**)]; + }; + + union NoAlias na = { *reinterpret_cast(ptr) }; + + if (endianness != GetEndianness()) + Swizzle(na.bytes, sizeof(na.bytes)); + + args.GetReturnValue().Set( scope.Escape( Buffer::Use(env, na.val, size) ) ); +} + + +void ReadPointerLE(const FunctionCallbackInfo& args) { + ReadPointerGeneric(args); +} + + +void ReadPointerBE(const FunctionCallbackInfo& args) { + ReadPointerGeneric(args); +} + + template uint32_t WriteFloatGeneric(const FunctionCallbackInfo& args) { ARGS_THIS(args[0].As()) @@ -940,6 +978,8 @@ void Initialize(Handle target, env->SetMethod(target, "readInt64LE", ReadInt64LE); env->SetMethod(target, "readUInt64BE", ReadUInt64BE); env->SetMethod(target, "readUInt64LE", ReadUInt64LE); + env->SetMethod(target, "readPointerBE", ReadPointerBE); + env->SetMethod(target, "readPointerLE", ReadPointerLE); env->SetMethod(target, "writeDoubleBE", WriteDoubleBE); env->SetMethod(target, "writeDoubleLE", WriteDoubleLE); From 0f1e40183490fec3db5930dfd41a9177abd545a4 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Wed, 20 May 2015 12:26:45 -0700 Subject: [PATCH 10/61] buffer: add writePointerLE and writePointerBE --- lib/buffer.js | 23 +++++++++++++++++++++++ src/node_buffer.cc | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/lib/buffer.js b/lib/buffer.js index 9969b934ec78af..3044a5c4ca989f 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -1172,6 +1172,29 @@ Buffer.prototype.writeUInt64BE = function writeUInt64BE(val, offset, noAssert) { }; +function checkPointer(buffer, value, offset) { + if (!(buffer instanceof Buffer)) + throw new TypeError('buffer must be a Buffer instance'); + if (!(value instanceof Buffer)) + throw new TypeError('value must be a Buffer instance'); +} + +Buffer.prototype.writePointerLE = function writePointerLE(val, offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) + checkPointer(this, val, offset); + return binding.writePointerLE(this, val, offset); +}; + + +Buffer.prototype.writePointerBE = function writePointerBE(val, offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) + checkPointer(this, val, offset); + return binding.writePointerBE(this, val, offset); +}; + + // ES6 iterator var ITERATOR_KIND_KEYS = 1; diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 7b25f744c5b837..decb2d2768b7bf 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -728,6 +728,46 @@ void WriteUInt64BE(const FunctionCallbackInfo& args) { } +template +uint32_t WritePointerGeneric(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + + ARGS_THIS(args[0].As()) + + uint32_t offset = args[2]->Uint32Value(); + CHECK_LE(offset + sizeof(char *), obj_length); + + if (!(args[1]->IsNull() || Buffer::HasInstance(args[1]))) { + env->ThrowTypeError("value must be a Buffer instance or null"); + return 0; + } + + char* ptr = static_cast(obj_data) + offset; + + if (args[1]->IsNull()) { + *reinterpret_cast(ptr) = NULL; + } else { + char *input_ptr = Buffer::Data(args[1].As()); + *reinterpret_cast(ptr) = input_ptr; + + if (endianness != GetEndianness()) + Swizzle(ptr, sizeof(char *)); + } + + return offset + sizeof(char *); +} + + +void WritePointerLE(const FunctionCallbackInfo& args) { + args.GetReturnValue().Set(WritePointerGeneric(args)); +} + + +void WritePointerBE(const FunctionCallbackInfo& args) { + args.GetReturnValue().Set(WritePointerGeneric(args)); +} + + void ByteLengthUtf8(const FunctionCallbackInfo &args) { CHECK(args[0]->IsString()); @@ -989,6 +1029,8 @@ void Initialize(Handle target, env->SetMethod(target, "writeInt64LE", WriteInt64LE); env->SetMethod(target, "writeUInt64BE", WriteUInt64BE); env->SetMethod(target, "writeUInt64LE", WriteUInt64LE); + env->SetMethod(target, "writePointerBE", WritePointerBE); + env->SetMethod(target, "writePointerLE", WritePointerLE); } From 2d543869cd9428b6650d3cfd1310975803a1a280 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Wed, 20 May 2015 12:38:18 -0700 Subject: [PATCH 11/61] buffer: use uintptr_t for address() --- src/node_buffer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index decb2d2768b7bf..8a850b6ebc6da4 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -948,7 +948,7 @@ void Address(const FunctionCallbackInfo& args) { std::stringstream stream; stream.rdbuf()->pubsetbuf(strbuf, sizeof(strbuf)); - stream << std::hex << (intptr_t)ptr << '\0'; + stream << std::hex << (uintptr_t)ptr << '\0'; args.GetReturnValue().Set( node::OneByteString(env->isolate(), strbuf, strlen(strbuf)) ); } From db39bc2e3c4f66552c687e5c59d6d6b8b8231351 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Wed, 20 May 2015 15:29:11 -0700 Subject: [PATCH 12/61] buffer: fix JS_MAX_INT and JS_MIN_INT values --- src/node_buffer.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 8a850b6ebc6da4..1257e5afee6104 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -58,8 +58,8 @@ // used by the ReadInt64 functions to determine whether to return a Number // or String, based on whether or not a JS Number will lose precision. // http://stackoverflow.com/q/307179/376773 -#define JS_MAX_INT +9007199254740992LL -#define JS_MIN_INT -9007199254740992LL +#define JS_MAX_INT +9007199254740991LL +#define JS_MIN_INT -9007199254740991LL namespace node { namespace Buffer { From 34feb805d788bed6f1f098d37f2a7cf7ee4fa861 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Thu, 21 May 2015 13:58:08 -0700 Subject: [PATCH 13/61] buffer: add HasInstance check to IsNull() --- src/node_buffer.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 1257e5afee6104..26f47c31d34cff 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -922,7 +922,11 @@ void IndexOfNumber(const FunctionCallbackInfo& args) { } void IsNull(const FunctionCallbackInfo& args) { - ASSERT(args[0]->IsObject()); + Environment* env = Environment::GetCurrent(args); + + if (!HasInstance(args[0])) + return env->ThrowTypeError("first arg should be a Buffer"); + ARGS_THIS(args[0].As()) int64_t offset = args[1]->IntegerValue(); From 89e7d61e07a05f1ffab5def8e0dced1ca1b6e029 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Thu, 21 May 2015 13:58:34 -0700 Subject: [PATCH 14/61] buffer: add HasInstance check to Address() --- src/node_buffer.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 26f47c31d34cff..e5d9e5e4ce127c 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -938,7 +938,9 @@ void IsNull(const FunctionCallbackInfo& args) { void Address(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - ASSERT(args[0]->IsObject()); + if (!HasInstance(args[0])) + return env->ThrowTypeError("first arg should be a Buffer"); + ARGS_THIS(args[0].As()) int64_t offset = args[1]->IntegerValue(); From 5e9c2a4b2c94ca87bac81499922312dd4ef7834a Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Thu, 21 May 2015 14:14:09 -0700 Subject: [PATCH 15/61] buffer: allow offset to be passed to isNull and address --- lib/buffer.js | 10 ++++++---- src/node_buffer.cc | 10 ++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/buffer.js b/lib/buffer.js index 3044a5c4ca989f..3ec1423769bb79 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -458,13 +458,15 @@ Buffer.prototype.fill = function fill(val, start, end) { }; -Buffer.prototype.address = function address() { - return binding.address(this); +Buffer.prototype.address = function address(offset) { + offset = offset >>> 0; + return binding.address(this, offset); }; -Buffer.prototype.isNull = function isNull() { - return binding.isNull(this); +Buffer.prototype.isNull = function isNull(offset) { + offset = offset >>> 0; + return binding.isNull(this, offset); }; diff --git a/src/node_buffer.cc b/src/node_buffer.cc index e5d9e5e4ce127c..078a0c1def4f6b 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -921,6 +921,7 @@ void IndexOfNumber(const FunctionCallbackInfo& args) { ptr ? static_cast(ptr_char - obj_data) : -1); } + void IsNull(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -929,12 +930,15 @@ void IsNull(const FunctionCallbackInfo& args) { ARGS_THIS(args[0].As()) - int64_t offset = args[1]->IntegerValue(); + uint32_t offset = args[1]->Uint32Value(); + CHECK_LE(offset + sizeof(char *), obj_length); + char *ptr = obj_data + offset; args.GetReturnValue().Set( ptr == NULL ); } + void Address(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -943,7 +947,9 @@ void Address(const FunctionCallbackInfo& args) { ARGS_THIS(args[0].As()) - int64_t offset = args[1]->IntegerValue(); + uint32_t offset = args[1]->Uint32Value(); + CHECK_LE(offset + sizeof(char *), obj_length); + char *ptr = obj_data + offset; // pointer-size * 2 (for hex printout) + 1 null byte From db6aea9054f5dbd1dcfc805c16a709b9d37abdd1 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Thu, 21 May 2015 14:22:19 -0700 Subject: [PATCH 16/61] buffer: fix offset checking logic --- src/node_buffer.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 078a0c1def4f6b..b41d2c02a06a5a 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -931,7 +931,7 @@ void IsNull(const FunctionCallbackInfo& args) { ARGS_THIS(args[0].As()) uint32_t offset = args[1]->Uint32Value(); - CHECK_LE(offset + sizeof(char *), obj_length); + CHECK_LE(offset, obj_length); char *ptr = obj_data + offset; @@ -948,7 +948,7 @@ void Address(const FunctionCallbackInfo& args) { ARGS_THIS(args[0].As()) uint32_t offset = args[1]->Uint32Value(); - CHECK_LE(offset + sizeof(char *), obj_length); + CHECK_LE(offset, obj_length); char *ptr = obj_data + offset; From 1fdf53130619b8a11a72b4d5c15d2a73958b3860 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 10:19:09 -0700 Subject: [PATCH 17/61] buffer: inline WrapNullPointer --- src/node_buffer.cc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index b41d2c02a06a5a..e82399a35dfd39 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -118,12 +118,6 @@ size_t Length(Handle obj) { return obj->GetIndexedPropertiesExternalArrayDataLength(); } -Local WrapNullPointer(Environment* env) { - size_t buf_size = 0; - char *ptr = reinterpret_cast(NULL); - return Buffer::Use(env, ptr, buf_size); -} - Local New(Isolate* isolate, Handle string, enum encoding enc) { EscapableHandleScope scope(isolate); @@ -1003,7 +997,8 @@ void SetupBufferJS(const FunctionCallbackInfo& args) { // instantiate the static NULL pointer buffer here // (gets moved to "buffer" module exports in `lib/buffer.js`) - proto->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "NULL"), WrapNullPointer(env)); + proto->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "NULL"), + Buffer::Use(env, nullptr, 0)); } void Initialize(Handle target, From ff5a09406589dd24ba8c085eed2b55cafd2eab3b Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 10:19:25 -0700 Subject: [PATCH 18/61] buffer: use nullptr --- src/node_buffer.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index e82399a35dfd39..c949fbc1f8e1ed 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -669,7 +669,7 @@ uint32_t WriteInt64Generic(const FunctionCallbackInfo& args) { // Have to do this because strtoll/strtoull doesn't set errno to 0 on success errno = 0; v8::String::Utf8Value str(args[1]); - val = strtoT(*str, NULL, 0); + val = strtoT(*str, nullptr, 0); if (errno != 0) { if (errno == EINVAL) { @@ -739,7 +739,7 @@ uint32_t WritePointerGeneric(const FunctionCallbackInfo& args) { char* ptr = static_cast(obj_data) + offset; if (args[1]->IsNull()) { - *reinterpret_cast(ptr) = NULL; + *reinterpret_cast(ptr) = nullptr; } else { char *input_ptr = Buffer::Data(args[1].As()); *reinterpret_cast(ptr) = input_ptr; @@ -929,7 +929,7 @@ void IsNull(const FunctionCallbackInfo& args) { char *ptr = obj_data + offset; - args.GetReturnValue().Set( ptr == NULL ); + args.GetReturnValue().Set(ptr == nullptr); } From dea8c4d1ede98fb2d50764c8e2fd7ab2737c9718 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 10:20:53 -0700 Subject: [PATCH 19/61] buffer: asterisks lean to the left --- src/node_buffer.cc | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index c949fbc1f8e1ed..f95e4e36ea7a5d 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -525,7 +525,7 @@ void ReadDoubleBE(const FunctionCallbackInfo& args) { template -void ReadInt64Generic(const FunctionCallbackInfo& args, const char *formatter) { +void ReadInt64Generic(const FunctionCallbackInfo& args, const char* formatter) { Environment* env = Environment::GetCurrent(args); ARGS_THIS(args[0].As()); @@ -584,7 +584,7 @@ void ReadPointerGeneric(const FunctionCallbackInfo& args) { ARGS_THIS(args[0].As()); uint32_t offset = args[1]->Uint32Value(); - CHECK_LE(offset + sizeof(char *), obj_length); + CHECK_LE(offset + sizeof(char*), obj_length); size_t size = args[2]->Uint32Value(); @@ -592,10 +592,10 @@ void ReadPointerGeneric(const FunctionCallbackInfo& args) { union NoAlias { char* val; - char bytes[sizeof(char**)]; + char bytes[sizeof(char*)]; }; - union NoAlias na = { *reinterpret_cast(ptr) }; + union NoAlias na = { *reinterpret_cast(ptr) }; if (endianness != GetEndianness()) Swizzle(na.bytes, sizeof(na.bytes)); @@ -656,7 +656,7 @@ void WriteDoubleBE(const FunctionCallbackInfo& args) { } -template +template uint32_t WriteInt64Generic(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -729,7 +729,7 @@ uint32_t WritePointerGeneric(const FunctionCallbackInfo& args) { ARGS_THIS(args[0].As()) uint32_t offset = args[2]->Uint32Value(); - CHECK_LE(offset + sizeof(char *), obj_length); + CHECK_LE(offset + sizeof(char*), obj_length); if (!(args[1]->IsNull() || Buffer::HasInstance(args[1]))) { env->ThrowTypeError("value must be a Buffer instance or null"); @@ -739,16 +739,16 @@ uint32_t WritePointerGeneric(const FunctionCallbackInfo& args) { char* ptr = static_cast(obj_data) + offset; if (args[1]->IsNull()) { - *reinterpret_cast(ptr) = nullptr; + *reinterpret_cast(ptr) = nullptr; } else { - char *input_ptr = Buffer::Data(args[1].As()); - *reinterpret_cast(ptr) = input_ptr; + char* input_ptr = Buffer::Data(args[1].As()); + *reinterpret_cast(ptr) = input_ptr; if (endianness != GetEndianness()) - Swizzle(ptr, sizeof(char *)); + Swizzle(ptr, sizeof(char*)); } - return offset + sizeof(char *); + return offset + sizeof(char*); } @@ -927,7 +927,7 @@ void IsNull(const FunctionCallbackInfo& args) { uint32_t offset = args[1]->Uint32Value(); CHECK_LE(offset, obj_length); - char *ptr = obj_data + offset; + char* ptr = obj_data + offset; args.GetReturnValue().Set(ptr == nullptr); } @@ -944,10 +944,10 @@ void Address(const FunctionCallbackInfo& args) { uint32_t offset = args[1]->Uint32Value(); CHECK_LE(offset, obj_length); - char *ptr = obj_data + offset; + char* ptr = obj_data + offset; // pointer-size * 2 (for hex printout) + 1 null byte - char strbuf[(sizeof(char *) * 2) + 1]; + char strbuf[(sizeof(char*) * 2) + 1]; // using stringstream and std::hex here instead of printf(%#) because // of cross-platform differences experienced with the later From 4dae6be971c89ce2a431c08a8bd8690805f18bdc Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 10:22:23 -0700 Subject: [PATCH 20/61] buffer: remove unnecessary #defines --- src/node_buffer.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index f95e4e36ea7a5d..abcdef03be7a97 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -20,8 +20,6 @@ #include // std::hex #ifdef _WIN32 - #define __alignof__ __alignof - #define snprintf(buf, bufSize, format, arg) _snprintf_s(buf, bufSize, _TRUNCATE, format, arg) #define strtoll _strtoi64 #define strtoull _strtoui64 #define PRId64 "lld" From 619d136deaa567d99e28b2ee59d2c5d0738f335d Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 10:37:46 -0700 Subject: [PATCH 21/61] buffer: fix most of the cpplint errors --- src/node_buffer.cc | 51 ++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index abcdef03be7a97..f0ccb2fe01df51 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -17,7 +17,7 @@ #include #include #include -#include // std::hex +#include // std::hex #ifdef _WIN32 #define strtoll _strtoi64 @@ -523,7 +523,8 @@ void ReadDoubleBE(const FunctionCallbackInfo& args) { template -void ReadInt64Generic(const FunctionCallbackInfo& args, const char* formatter) { +void ReadInt64Generic(const FunctionCallbackInfo& args, + const char* formatter) { Environment* env = Environment::GetCurrent(args); ARGS_THIS(args[0].As()); @@ -546,7 +547,7 @@ void ReadInt64Generic(const FunctionCallbackInfo& args, const char* forma // return a String char strbuf[20]; int len = snprintf(strbuf, sizeof(strbuf), formatter, na.val); - args.GetReturnValue().Set( node::OneByteString(env->isolate(), strbuf, len) ); + args.GetReturnValue().Set(node::OneByteString(env->isolate(), strbuf, len)); } else { // return a Number args.GetReturnValue().Set(static_cast(na.val)); @@ -555,12 +556,14 @@ void ReadInt64Generic(const FunctionCallbackInfo& args, const char* forma void ReadInt64LE(const FunctionCallbackInfo& args) { - ReadInt64Generic(args, "%" PRId64); + ReadInt64Generic(args, + "%" PRId64); } void ReadInt64BE(const FunctionCallbackInfo& args) { - ReadInt64Generic(args, "%" PRId64); + ReadInt64Generic(args, + "%" PRId64); } @@ -581,16 +584,17 @@ void ReadPointerGeneric(const FunctionCallbackInfo& args) { ARGS_THIS(args[0].As()); + char* ptr; uint32_t offset = args[1]->Uint32Value(); - CHECK_LE(offset + sizeof(char*), obj_length); + CHECK_LE(offset + sizeof(ptr), obj_length); size_t size = args[2]->Uint32Value(); - char* ptr = static_cast(obj_data) + offset; + ptr = static_cast(obj_data) + offset; union NoAlias { char* val; - char bytes[sizeof(char*)]; + char bytes[sizeof(ptr)]; }; union NoAlias na = { *reinterpret_cast(ptr) }; @@ -598,7 +602,7 @@ void ReadPointerGeneric(const FunctionCallbackInfo& args) { if (endianness != GetEndianness()) Swizzle(na.bytes, sizeof(na.bytes)); - args.GetReturnValue().Set( scope.Escape( Buffer::Use(env, na.val, size) ) ); + args.GetReturnValue().Set(scope.Escape(Buffer::Use(env, na.val, size))); } @@ -654,7 +658,8 @@ void WriteDoubleBE(const FunctionCallbackInfo& args) { } -template +template uint32_t WriteInt64Generic(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -664,7 +669,7 @@ uint32_t WriteInt64Generic(const FunctionCallbackInfo& args) { if (args[1]->IsNumber()) { val = args[1]->IntegerValue(); } else if (args[1]->IsString()) { - // Have to do this because strtoll/strtoull doesn't set errno to 0 on success + // Have to do this because strt(u)oll doesn't set errno to 0 on success errno = 0; v8::String::Utf8Value str(args[1]); val = strtoT(*str, nullptr, 0); @@ -702,21 +707,25 @@ uint32_t WriteInt64Generic(const FunctionCallbackInfo& args) { void WriteInt64LE(const FunctionCallbackInfo& args) { - args.GetReturnValue().Set(WriteInt64Generic(args)); + args.GetReturnValue().Set(WriteInt64Generic(args)); } void WriteInt64BE(const FunctionCallbackInfo& args) { - args.GetReturnValue().Set(WriteInt64Generic(args)); + args.GetReturnValue().Set(WriteInt64Generic(args)); } void WriteUInt64LE(const FunctionCallbackInfo& args) { - args.GetReturnValue().Set(WriteInt64Generic(args)); + args.GetReturnValue().Set(WriteInt64Generic(args)); } void WriteUInt64BE(const FunctionCallbackInfo& args) { - args.GetReturnValue().Set(WriteInt64Generic(args)); + args.GetReturnValue().Set(WriteInt64Generic(args)); } @@ -726,8 +735,9 @@ uint32_t WritePointerGeneric(const FunctionCallbackInfo& args) { ARGS_THIS(args[0].As()) + char* ptr; uint32_t offset = args[2]->Uint32Value(); - CHECK_LE(offset + sizeof(char*), obj_length); + CHECK_LE(offset + sizeof(ptr), obj_length); if (!(args[1]->IsNull() || Buffer::HasInstance(args[1]))) { env->ThrowTypeError("value must be a Buffer instance or null"); @@ -743,10 +753,10 @@ uint32_t WritePointerGeneric(const FunctionCallbackInfo& args) { *reinterpret_cast(ptr) = input_ptr; if (endianness != GetEndianness()) - Swizzle(ptr, sizeof(char*)); + Swizzle(ptr, sizeof(ptr)); } - return offset + sizeof(char*); + return offset + sizeof(ptr); } @@ -945,7 +955,7 @@ void Address(const FunctionCallbackInfo& args) { char* ptr = obj_data + offset; // pointer-size * 2 (for hex printout) + 1 null byte - char strbuf[(sizeof(char*) * 2) + 1]; + char strbuf[(sizeof(ptr) * 2) + 1]; // using stringstream and std::hex here instead of printf(%#) because // of cross-platform differences experienced with the later @@ -954,7 +964,8 @@ void Address(const FunctionCallbackInfo& args) { stream << std::hex << (uintptr_t)ptr << '\0'; - args.GetReturnValue().Set( node::OneByteString(env->isolate(), strbuf, strlen(strbuf)) ); + args.GetReturnValue().Set(node::OneByteString(env->isolate(), + strbuf, strlen(strbuf))); } From 6e07bbc6e55b84e03af94f4a89e6d8391c3c177a Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 10:55:23 -0700 Subject: [PATCH 22/61] buffer: remove EscapableHandleScope in readPointer --- src/node_buffer.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index f0ccb2fe01df51..a1b234434e89e6 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -580,7 +580,6 @@ void ReadUInt64BE(const FunctionCallbackInfo& args) { template void ReadPointerGeneric(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - EscapableHandleScope scope(env->isolate()); ARGS_THIS(args[0].As()); @@ -602,7 +601,7 @@ void ReadPointerGeneric(const FunctionCallbackInfo& args) { if (endianness != GetEndianness()) Swizzle(na.bytes, sizeof(na.bytes)); - args.GetReturnValue().Set(scope.Escape(Buffer::Use(env, na.val, size))); + args.GetReturnValue().Set(Buffer::Use(env, na.val, size)); } From e6f32627050c5f2d52d8cf84c332551076298193 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 11:00:20 -0700 Subject: [PATCH 23/61] buffer: add CHECK calls --- src/node_buffer.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index a1b234434e89e6..b934d7d6252699 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -662,6 +662,7 @@ template & args) { Environment* env = Environment::GetCurrent(args); + CHECK(args[0]->IsObject()); ARGS_THIS(args[0].As()) T val; @@ -732,6 +733,7 @@ template uint32_t WritePointerGeneric(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); + CHECK(args[0]->IsObject()); ARGS_THIS(args[0].As()) char* ptr; @@ -929,6 +931,7 @@ void IsNull(const FunctionCallbackInfo& args) { if (!HasInstance(args[0])) return env->ThrowTypeError("first arg should be a Buffer"); + CHECK(args[0]->IsObject()); ARGS_THIS(args[0].As()) uint32_t offset = args[1]->Uint32Value(); @@ -946,6 +949,7 @@ void Address(const FunctionCallbackInfo& args) { if (!HasInstance(args[0])) return env->ThrowTypeError("first arg should be a Buffer"); + CHECK(args[0]->IsObject()); ARGS_THIS(args[0].As()) uint32_t offset = args[1]->Uint32Value(); From 565a1e84ddc890f711acee673de042437654635b Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 11:01:35 -0700 Subject: [PATCH 24/61] buffer: remove variable redefinition --- src/node_buffer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index b934d7d6252699..4a5ea329f63528 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -745,7 +745,7 @@ uint32_t WritePointerGeneric(const FunctionCallbackInfo& args) { return 0; } - char* ptr = static_cast(obj_data) + offset; + ptr = static_cast(obj_data) + offset; if (args[1]->IsNull()) { *reinterpret_cast(ptr) = nullptr; From 66d68ef8866eca69ad7a3ab4f274e42db8db2315 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 11:13:29 -0700 Subject: [PATCH 25/61] buffer: use node::Utf8Value --- src/node_buffer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 4a5ea329f63528..d4ed0138bdb445 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -671,7 +671,7 @@ uint32_t WriteInt64Generic(const FunctionCallbackInfo& args) { } else if (args[1]->IsString()) { // Have to do this because strt(u)oll doesn't set errno to 0 on success errno = 0; - v8::String::Utf8Value str(args[1]); + node::Utf8Value str(env->isolate(), args[1]); val = strtoT(*str, nullptr, 0); if (errno != 0) { From 51e9556f054ea3d9cc55e893e9cef0825b2ca8cf Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 11:25:10 -0700 Subject: [PATCH 26/61] buffer: don't use C++ streams, use printf %lx --- src/node_buffer.cc | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index d4ed0138bdb445..48222329394fdf 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -14,11 +14,6 @@ #include #include -#include -#include -#include -#include // std::hex - #ifdef _WIN32 #define strtoll _strtoi64 #define strtoull _strtoui64 @@ -959,13 +954,9 @@ void Address(const FunctionCallbackInfo& args) { // pointer-size * 2 (for hex printout) + 1 null byte char strbuf[(sizeof(ptr) * 2) + 1]; + const uintptr_t pointer = reinterpret_cast(ptr); - // using stringstream and std::hex here instead of printf(%#) because - // of cross-platform differences experienced with the later - std::stringstream stream; - stream.rdbuf()->pubsetbuf(strbuf, sizeof(strbuf)); - - stream << std::hex << (uintptr_t)ptr << '\0'; + snprintf(strbuf, sizeof(strbuf), "%lx", pointer); args.GetReturnValue().Set(node::OneByteString(env->isolate(), strbuf, strlen(strbuf))); From 2b6ec58e73d1dbeeb628cccd8325295879640307 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 11:26:46 -0700 Subject: [PATCH 27/61] buffer: don't rely on snprintf return value --- src/node_buffer.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 48222329394fdf..93373e3ce9655b 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -541,8 +541,9 @@ void ReadInt64Generic(const FunctionCallbackInfo& args, if (na.val < min || na.val > max) { // return a String char strbuf[20]; - int len = snprintf(strbuf, sizeof(strbuf), formatter, na.val); - args.GetReturnValue().Set(node::OneByteString(env->isolate(), strbuf, len)); + snprintf(strbuf, sizeof(strbuf), formatter, na.val); + args.GetReturnValue().Set(node::OneByteString(env->isolate(), + strbuf, strlen(strbuf))); } else { // return a Number args.GetReturnValue().Set(static_cast(na.val)); From c84e8904ecee96794f478646fe90846f12c9bc44 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 15:58:05 -0700 Subject: [PATCH 28/61] test: fix tests for new Buffer#inspect() behavior --- test/parallel/test-buffer-inspect.js | 18 +++++++++--------- test/parallel/test-buffer.js | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/test/parallel/test-buffer-inspect.js b/test/parallel/test-buffer-inspect.js index 707f778255ad51..8c5dd250c4c2a1 100644 --- a/test/parallel/test-buffer-inspect.js +++ b/test/parallel/test-buffer-inspect.js @@ -14,10 +14,10 @@ b.fill('1234'); var s = new buffer.SlowBuffer(4); s.fill('1234'); -var expected = ''; +var expected = //; -assert.strictEqual(util.inspect(b), expected); -assert.strictEqual(util.inspect(s), expected); +assert(expected.test(util.inspect(b))); +assert(expected.test(util.inspect(s))); b = new Buffer(2); b.fill('12'); @@ -25,14 +25,14 @@ b.fill('12'); s = new buffer.SlowBuffer(2); s.fill('12'); -expected = ''; +expected = //; -assert.strictEqual(util.inspect(b), expected); -assert.strictEqual(util.inspect(s), expected); +assert(expected.test(util.inspect(b))); +assert(expected.test(util.inspect(s))); buffer.INSPECT_MAX_BYTES = Infinity; assert.doesNotThrow(function() { - assert.strictEqual(util.inspect(b), expected); - assert.strictEqual(util.inspect(s), expected); -}); \ No newline at end of file + assert(expected.test(util.inspect(b))); + assert(expected.test(util.inspect(s))); +}); diff --git a/test/parallel/test-buffer.js b/test/parallel/test-buffer.js index 1d02148734e38a..52ae8451a17fc8 100644 --- a/test/parallel/test-buffer.js +++ b/test/parallel/test-buffer.js @@ -619,7 +619,7 @@ function buildBuffer(data) { var x = buildBuffer([0x81, 0xa3, 0x66, 0x6f, 0x6f, 0xa3, 0x62, 0x61, 0x72]); console.log(x.inspect()); -assert.equal('', x.inspect()); +assert(//.test(x.inspect())); var z = x.slice(4); console.log(z.inspect()); From 001b0720e242361c27c99de21af46b5984dc1922 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 16:34:55 -0700 Subject: [PATCH 29/61] doc: add docs for Buffer read/writePointer --- doc/api/buffer.markdown | 59 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index 106097451b73d1..69c1891a2c23f4 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -600,6 +600,36 @@ Example: // 0.3333333333333333 +### buf.readPointerLE(offset, length[, noAssert]) +### buf.readPointerBE(offset, length[, noAssert]) + +* `offset` Number +* `length` Number +* `noAssert` Boolean, Optional, Default: false +* Return: Number + +Reads a pointer from the buffer by dereferencing at the specified +offset with specified endian format. + +A new Buffer instance is returned at the memory address pointed to +by `buf`, with its length set to `length`. + +Set `noAssert` to true to skip validation of `offset`. This means that `offset` +may be beyond the end of the buffer. Defaults to `false`. + +__WARNING__: The "Pointer" family of functions relates to direct +memory access, which can easily get you into trouble (segmentation +faults, etc.) if you don't know what you're doing. Generally these +functions are only used in relation to the `dlopen` and `ffi` modules. + +Example: + + // assume `buf` is a pointer to some external `int` data + var intBuf = buf.readPointer(0, ffi.sizeof.int); + + console.log(intBuf.readInt32LE(0)); + // 6 + ### buf.writeUInt8(value, offset[, noAssert]) * `value` Number @@ -797,6 +827,35 @@ Example: // // +### buf.writePointerLE(pointer, offset[, noAssert]) +### buf.writePointerBE(pointer, offset[, noAssert]) + +* `pointer` Buffer or null +* `offset` Number +* `noAssert` Boolean, Optional, Default: false + +Writes the memory address of `pointer` to the buffer at the specified offset +with specified endian format. If `null` is given the the NULL pointer will +be written as the memory address. + +Set `noAssert` to true to skip validation of `value` and `offset`. This means +that `value` may be too large for the specific function and `offset` may be +beyond the end of the buffer leading to the values being silently dropped. This +should not be used unless you are certain of correctness. Defaults to `false`. + +Example: + + var b = new Buffer('a'); + // + + var b2 = new Buffer(ffi.sizeof.pointer); + // + + buf.writePointerBE(b, 0); + // + // ^ ^ ^ ^ ^ + // notice the value here is the same as the address of `b` + ### buf.fill(value[, offset][, end]) * `value` From 86ff08ca789141f7afa252cf65accc802dbdfa74 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 16:53:48 -0700 Subject: [PATCH 30/61] doc: buffer docs tweaks --- doc/api/buffer.markdown | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index 69c1891a2c23f4..c4457ec02a8f24 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -617,7 +617,7 @@ by `buf`, with its length set to `length`. Set `noAssert` to true to skip validation of `offset`. This means that `offset` may be beyond the end of the buffer. Defaults to `false`. -__WARNING__: The "Pointer" family of functions relates to direct +__WARNING__: The "Pointer" family of functions relate to direct memory access, which can easily get you into trouble (segmentation faults, etc.) if you don't know what you're doing. Generally these functions are only used in relation to the `dlopen` and `ffi` modules. @@ -843,6 +843,11 @@ that `value` may be too large for the specific function and `offset` may be beyond the end of the buffer leading to the values being silently dropped. This should not be used unless you are certain of correctness. Defaults to `false`. +__WARNING__: The "Pointer" family of functions relate to direct +memory access, which can easily get you into trouble (segmentation +faults, etc.) if you don't know what you're doing. Generally these +functions are only used in relation to the `dlopen` and `ffi` modules. + Example: var b = new Buffer('a'); @@ -853,7 +858,7 @@ Example: buf.writePointerBE(b, 0); // - // ^ ^ ^ ^ ^ + // ^ ^ ^ ^ ^ // notice the value here is the same as the address of `b` ### buf.fill(value[, offset][, end]) From 319e5934a757a38372a0ee3fbb6b5a6a3a4ac729 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 16:53:58 -0700 Subject: [PATCH 31/61] doc: add Buffer readInt64* docs --- doc/api/buffer.markdown | 53 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index c4457ec02a8f24..13935e4c46dc62 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -498,6 +498,37 @@ Example: // 0x03042342 // 0x42230403 +### buf.readUInt64LE(offset[, noAssert]) +### buf.readUInt64BE(offset[, noAssert]) + +* `offset` Number +* `noAssert` Boolean, Optional, Default: false +* Return: Number or String + +Reads an unsigned 64 bit integer from the buffer at the specified offset with +specified endian format. + +If the value is greater than `Number.MAX_SAFE_INTEGER` then a String is +returned, otherwise a Number is returned. Because of this, it is assumed +that you will pass the return value to JavaScript Int64 module, rather +than interact with the value directly. + +Set `noAssert` to true to skip validation of `offset`. This means that `offset` +may be beyond the end of the buffer. Defaults to `false`. + +Example: + + var buf = new Buffer(8); + buf[0] = buf[1] = buf[2] = buf[3] = 0x00; + buf[4] = buf[5] = buf[6] = buf[7] = 0xff; + // + + b.readUInt64BE(0); + // 4294967295 + + b.readUInt64LE(0); + // '1844674406941458432' + ### buf.readInt8(offset[, noAssert]) * `offset` Number @@ -544,6 +575,28 @@ may be beyond the end of the buffer. Defaults to `false`. Works as `buffer.readUInt32*`, except buffer contents are treated as two's complement signed values. +### buf.readInt64LE(offset[, noAssert]) +### buf.readInt64BE(offset[, noAssert]) + +* `offset` Number or String +* `noAssert` Boolean, Optional, Default: false +* Return: Number + +Reads a signed 64 bit integer from the buffer at the specified offset with +specified endian format. + +If the value is less than `Number.MIN_SAFE_INTEGER` or greater than +`Number.MAX_SAFE_INTEGER` then a String is returned, otherwise a Number +is returned. Because of this, it is assumed that you will pass the +return value to JavaScript Int64 module, rather than interact with the +value directly. + +Set `noAssert` to true to skip validation of `offset`. This means that `offset` +may be beyond the end of the buffer. Defaults to `false`. + +Works as `buffer.readUInt64*`, except buffer contents are treated as two's +complement signed values. + ### buf.readFloatLE(offset[, noAssert]) ### buf.readFloatBE(offset[, noAssert]) From 924da7f226aee7b364ece1195fba1eb115816d93 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 16:57:58 -0700 Subject: [PATCH 32/61] doc: add fake memory addresses to old examples --- doc/api/buffer.markdown | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index 13935e4c46dc62..30c10505ce2af3 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -213,7 +213,7 @@ Supports up to 48 bits of accuracy. For example: var b = new Buffer(6); b.writeUIntBE(0x1234567890ab, 0, 6); - // + // Set `noAssert` to `true` to skip validation of `value` and `offset`. Defaults to `false`. @@ -283,7 +283,7 @@ Example: }); console.log(copy); - // + // ### buf[index] @@ -707,7 +707,7 @@ Example: console.log(buf); - // + // ### buf.writeUInt16LE(value, offset[, noAssert]) ### buf.writeUInt16BE(value, offset[, noAssert]) @@ -737,8 +737,8 @@ Example: console.log(buf); - // - // + // + // ### buf.writeUInt32LE(value, offset[, noAssert]) ### buf.writeUInt32BE(value, offset[, noAssert]) @@ -766,8 +766,8 @@ Example: console.log(buf); - // - // + // + // ### buf.writeInt8(value, offset[, noAssert]) @@ -848,8 +848,8 @@ Example: console.log(buf); - // - // + // + // ### buf.writeDoubleLE(value, offset[, noAssert]) ### buf.writeDoubleBE(value, offset[, noAssert]) @@ -877,8 +877,8 @@ Example: console.log(buf); - // - // + // + // ### buf.writePointerLE(pointer, offset[, noAssert]) ### buf.writePointerBE(pointer, offset[, noAssert]) From ed4d2201ae47780cc89c9de5e8649b404f4e0369 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 17:15:42 -0700 Subject: [PATCH 33/61] buffer: return `null` from readPointer upon NULL --- src/node_buffer.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 93373e3ce9655b..9e84d006ceae06 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -577,6 +577,7 @@ template void ReadPointerGeneric(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); + CHECK(args[0]->IsObject()); ARGS_THIS(args[0].As()); char* ptr; @@ -597,7 +598,11 @@ void ReadPointerGeneric(const FunctionCallbackInfo& args) { if (endianness != GetEndianness()) Swizzle(na.bytes, sizeof(na.bytes)); - args.GetReturnValue().Set(Buffer::Use(env, na.val, size)); + if (na.val) { + args.GetReturnValue().Set(Buffer::Use(env, na.val, size)); + } else { + args.GetReturnValue().Set(v8::Null(env->isolate())); + } } From 13c77bd446c98f9ebca2ec4c7a18b7b3b32b4446 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 17:16:06 -0700 Subject: [PATCH 34/61] buffer: remove static `buffer.NULL` Buffer Should no longer be necessary now that readPointer() returns `null` explictly. --- lib/buffer.js | 4 ---- src/node_buffer.cc | 5 ----- 2 files changed, 9 deletions(-) diff --git a/lib/buffer.js b/lib/buffer.js index 3ec1423769bb79..29e26681e38f0b 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -202,10 +202,6 @@ NativeBuffer.prototype = Buffer.prototype; // add methods to Buffer prototype binding.setupBufferJS(NativeBuffer); -// move the static NULL pointer buffer to `exports` instead of `Buffer.prototype` -exports.NULL = NativeBuffer.prototype.NULL; -delete NativeBuffer.prototype.NULL; - // Static methods diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 9e84d006ceae06..40f78ab424367d 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -1003,11 +1003,6 @@ void SetupBufferJS(const FunctionCallbackInfo& args) { proto->ForceSet(env->offset_string(), Uint32::New(env->isolate(), 0), v8::ReadOnly); - - // instantiate the static NULL pointer buffer here - // (gets moved to "buffer" module exports in `lib/buffer.js`) - proto->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "NULL"), - Buffer::Use(env, nullptr, 0)); } void Initialize(Handle target, From 61c5c7c7787c218810a42019821b4c620120e772 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 17:16:59 -0700 Subject: [PATCH 35/61] doc: document Buffer#readPointer `null` behavior --- doc/api/buffer.markdown | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index 30c10505ce2af3..42613b65f2ae15 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -665,7 +665,8 @@ Reads a pointer from the buffer by dereferencing at the specified offset with specified endian format. A new Buffer instance is returned at the memory address pointed to -by `buf`, with its length set to `length`. +by `buf`, with its length set to `length`. If the NULL pointer is +read, then JS `null` is returned, and `length` is disregarded. Set `noAssert` to true to skip validation of `offset`. This means that `offset` may be beyond the end of the buffer. Defaults to `false`. @@ -678,11 +679,21 @@ functions are only used in relation to the `dlopen` and `ffi` modules. Example: // assume `buf` is a pointer to some external `int` data - var intBuf = buf.readPointer(0, ffi.sizeof.int); + var intBuf = buf.readPointerLE(0, ffi.sizeof.int); + + console.log(intBuf); + // console.log(intBuf.readInt32LE(0)); // 6 + + // if a NULL pointer is read, then JS `null` is returned + buf.fill(0); + + console.log(buf.readPointerLE(0)); + // null + ### buf.writeUInt8(value, offset[, noAssert]) * `value` Number @@ -904,16 +915,21 @@ functions are only used in relation to the `dlopen` and `ffi` modules. Example: var b = new Buffer('a'); - // + console.log(b.address()); + // '103032008' var b2 = new Buffer(ffi.sizeof.pointer); - // buf.writePointerBE(b, 0); // // ^ ^ ^ ^ ^ // notice the value here is the same as the address of `b` + + // if null is given, then a NULL pointer is written + buf.writePointerBE(null, 0); + // + ### buf.fill(value[, offset][, end]) * `value` From a9e8f62aab9c171823562a3047ae5fb1853e3e3a Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 17:17:54 -0700 Subject: [PATCH 36/61] buffer: remove Buffer#isNull() Should no longer be necessary now that readPointer*() returns JS `null` explicitly. --- lib/buffer.js | 6 ------ src/node_buffer.cc | 19 ------------------- 2 files changed, 25 deletions(-) diff --git a/lib/buffer.js b/lib/buffer.js index 29e26681e38f0b..13224625301e59 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -460,12 +460,6 @@ Buffer.prototype.address = function address(offset) { }; -Buffer.prototype.isNull = function isNull(offset) { - offset = offset >>> 0; - return binding.isNull(this, offset); -}; - - // XXX remove in v0.13 Buffer.prototype.get = util.deprecate(function get(offset) { offset = ~~offset; diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 40f78ab424367d..0591bf68f1c46c 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -926,24 +926,6 @@ void IndexOfNumber(const FunctionCallbackInfo& args) { } -void IsNull(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - - if (!HasInstance(args[0])) - return env->ThrowTypeError("first arg should be a Buffer"); - - CHECK(args[0]->IsObject()); - ARGS_THIS(args[0].As()) - - uint32_t offset = args[1]->Uint32Value(); - CHECK_LE(offset, obj_length); - - char* ptr = obj_data + offset; - - args.GetReturnValue().Set(ptr == nullptr); -} - - void Address(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -1019,7 +1001,6 @@ void Initialize(Handle target, env->SetMethod(target, "indexOfBuffer", IndexOfBuffer); env->SetMethod(target, "indexOfNumber", IndexOfNumber); env->SetMethod(target, "indexOfString", IndexOfString); - env->SetMethod(target, "isNull", IsNull); env->SetMethod(target, "readDoubleBE", ReadDoubleBE); env->SetMethod(target, "readDoubleLE", ReadDoubleLE); From f0cec38a8978f9fedee9b3ce02edc75d235a0d47 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 17:19:26 -0700 Subject: [PATCH 37/61] buffer: remove `offset` param from `address()` Would make the function simply return `true` for any value >= 1, so doesn't really make any sense to keep it around. --- lib/buffer.js | 5 ++--- src/node_buffer.cc | 9 ++------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/lib/buffer.js b/lib/buffer.js index 13224625301e59..9e132a14caf288 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -454,9 +454,8 @@ Buffer.prototype.fill = function fill(val, start, end) { }; -Buffer.prototype.address = function address(offset) { - offset = offset >>> 0; - return binding.address(this, offset); +Buffer.prototype.address = function address() { + return binding.address(this); }; diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 0591bf68f1c46c..042d2f8331373b 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -935,14 +935,9 @@ void Address(const FunctionCallbackInfo& args) { CHECK(args[0]->IsObject()); ARGS_THIS(args[0].As()) - uint32_t offset = args[1]->Uint32Value(); - CHECK_LE(offset, obj_length); - - char* ptr = obj_data + offset; - // pointer-size * 2 (for hex printout) + 1 null byte - char strbuf[(sizeof(ptr) * 2) + 1]; - const uintptr_t pointer = reinterpret_cast(ptr); + char strbuf[(sizeof(obj_data) * 2) + 1]; + const uintptr_t pointer = reinterpret_cast(obj_data); snprintf(strbuf, sizeof(strbuf), "%lx", pointer); From 3f0d7a0035680b10ec308ca6f560afed4beb6ca8 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 17:20:52 -0700 Subject: [PATCH 38/61] doc: fix buffer typo --- doc/api/buffer.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index 42613b65f2ae15..d1b659a84599f2 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -510,7 +510,7 @@ specified endian format. If the value is greater than `Number.MAX_SAFE_INTEGER` then a String is returned, otherwise a Number is returned. Because of this, it is assumed -that you will pass the return value to JavaScript Int64 module, rather +that you will pass the return value to a JavaScript Int64 module, rather than interact with the value directly. Set `noAssert` to true to skip validation of `offset`. This means that `offset` @@ -588,7 +588,7 @@ specified endian format. If the value is less than `Number.MIN_SAFE_INTEGER` or greater than `Number.MAX_SAFE_INTEGER` then a String is returned, otherwise a Number is returned. Because of this, it is assumed that you will pass the -return value to JavaScript Int64 module, rather than interact with the +return value to a JavaScript Int64 module, rather than interact with the value directly. Set `noAssert` to true to skip validation of `offset`. This means that `offset` From ea44b75dc255678421179919b5c88d792ad1b222 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 17:23:56 -0700 Subject: [PATCH 39/61] buffer: fix checkPointer when null is passed in --- lib/buffer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/buffer.js b/lib/buffer.js index 9e132a14caf288..c65242d9d9e6f5 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -1166,8 +1166,8 @@ Buffer.prototype.writeUInt64BE = function writeUInt64BE(val, offset, noAssert) { function checkPointer(buffer, value, offset) { if (!(buffer instanceof Buffer)) throw new TypeError('buffer must be a Buffer instance'); - if (!(value instanceof Buffer)) - throw new TypeError('value must be a Buffer instance'); + if (!(value === null || value instanceof Buffer)) + throw new TypeError('value must be a Buffer instance or null'); } Buffer.prototype.writePointerLE = function writePointerLE(val, offset, noAssert) { From 7326597b6ec7308032c98878330dd70c477255fa Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 17:25:59 -0700 Subject: [PATCH 40/61] doc: add Buffer#address() docs --- doc/api/buffer.markdown | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index d1b659a84599f2..a1414833cce862 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -943,6 +943,15 @@ buffer. var b = new Buffer(50); b.fill("h"); +### buffer.address() + +Returns a String representation of the hex address of the pointer in memory. + + var b = new Buffer(1); + + b.address(); + // + ### buffer.values() Creates iterator for buffer values (bytes). This function is called automatically From 2ace08f0ad88a8fcd4dc8e2917265b5c1b079928 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 17:27:58 -0700 Subject: [PATCH 41/61] doc: fix Buffer#address() output in example --- doc/api/buffer.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index a1414833cce862..690e799eeddff6 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -950,7 +950,7 @@ Returns a String representation of the hex address of the pointer in memory. var b = new Buffer(1); b.address(); - // + // '10202ee08' ### buffer.values() From e7f8d77c32d4d1f1a1c4c7689eedf89a112e84cc Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 17:33:57 -0700 Subject: [PATCH 42/61] doc: add Buffer writeInt64*() docs --- doc/api/buffer.markdown | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index 690e799eeddff6..f968c1654a00f4 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -780,6 +780,31 @@ Example: // // +### buf.writeUInt64LE(value, offset[, noAssert]) +### buf.writeUInt64BE(value, offset[, noAssert]) + +* `value` Number or String +* `offset` Number +* `noAssert` Boolean, Optional, Default: false + +Writes `value` to the buffer at the specified offset with specified endian +format. Note, `value` must be a valid unsigned 64 bit integer, or a String +representation of one. + +Set `noAssert` to true to skip validation of `value` and `offset`. This means +that `value` may be too large for the specific function and `offset` may be +beyond the end of the buffer leading to the values being silently dropped. This +should not be used unless you are certain of correctness. Defaults to `false`. + +Example: + + var buf = new Buffer(8); + + b.writeUInt64LE('0xffffffffffff') + + console.log(b); + // + ### buf.writeInt8(value, offset[, noAssert]) * `value` Number @@ -833,6 +858,25 @@ should not be used unless you are certain of correctness. Defaults to `false`. Works as `buffer.writeUInt32*`, except value is written out as a two's complement signed integer into `buffer`. +### buf.writeInt64(value, offset[, noAssert]) +### buf.writeInt64(value, offset[, noAssert]) + +* `value` Number or String +* `offset` Number +* `noAssert` Boolean, Optional, Default: false + +Writes `value` to the buffer at the specified offset with specified endian +format. Note, `value` must be a valid signed 64 bit integer, or a String +representation of one. + +Set `noAssert` to true to skip validation of `value` and `offset`. This means +that `value` may be too large for the specific function and `offset` may be +beyond the end of the buffer leading to the values being silently dropped. This +should not be used unless you are certain of correctness. Defaults to `false`. + +Works as `buffer.writeUInt64*`, except value is written out as a two's +complement signed integer into `buffer`. + ### buf.writeFloatLE(value, offset[, noAssert]) ### buf.writeFloatBE(value, offset[, noAssert]) From 4ee5354a6f4099354b846924a55dcd2d616401f6 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 17:34:49 -0700 Subject: [PATCH 43/61] Revert "doc: add fake memory addresses to old examples" This reverts commit 22213182bf118f3be0d99a6c8f4603c6a1525b07. --- doc/api/buffer.markdown | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index f968c1654a00f4..a24892ab13c741 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -213,7 +213,7 @@ Supports up to 48 bits of accuracy. For example: var b = new Buffer(6); b.writeUIntBE(0x1234567890ab, 0, 6); - // + // Set `noAssert` to `true` to skip validation of `value` and `offset`. Defaults to `false`. @@ -283,7 +283,7 @@ Example: }); console.log(copy); - // + // ### buf[index] @@ -718,7 +718,7 @@ Example: console.log(buf); - // + // ### buf.writeUInt16LE(value, offset[, noAssert]) ### buf.writeUInt16BE(value, offset[, noAssert]) @@ -748,8 +748,8 @@ Example: console.log(buf); - // - // + // + // ### buf.writeUInt32LE(value, offset[, noAssert]) ### buf.writeUInt32BE(value, offset[, noAssert]) @@ -777,8 +777,8 @@ Example: console.log(buf); - // - // + // + // ### buf.writeUInt64LE(value, offset[, noAssert]) ### buf.writeUInt64BE(value, offset[, noAssert]) @@ -903,8 +903,8 @@ Example: console.log(buf); - // - // + // + // ### buf.writeDoubleLE(value, offset[, noAssert]) ### buf.writeDoubleBE(value, offset[, noAssert]) @@ -932,8 +932,8 @@ Example: console.log(buf); - // - // + // + // ### buf.writePointerLE(pointer, offset[, noAssert]) ### buf.writePointerBE(pointer, offset[, noAssert]) From f364f1b1d4abcd5bb0f01d967cdb0cff5b41964f Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 17:35:46 -0700 Subject: [PATCH 44/61] doc: add fake memory addresses to old examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Properly this timeā€¦ --- doc/api/buffer.markdown | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index a24892ab13c741..713b5e1041cdbb 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -213,7 +213,7 @@ Supports up to 48 bits of accuracy. For example: var b = new Buffer(6); b.writeUIntBE(0x1234567890ab, 0, 6); - // + // Set `noAssert` to `true` to skip validation of `value` and `offset`. Defaults to `false`. @@ -283,7 +283,7 @@ Example: }); console.log(copy); - // + // ### buf[index] @@ -718,7 +718,7 @@ Example: console.log(buf); - // + // ### buf.writeUInt16LE(value, offset[, noAssert]) ### buf.writeUInt16BE(value, offset[, noAssert]) @@ -748,8 +748,8 @@ Example: console.log(buf); - // - // + // + // ### buf.writeUInt32LE(value, offset[, noAssert]) ### buf.writeUInt32BE(value, offset[, noAssert]) @@ -777,8 +777,8 @@ Example: console.log(buf); - // - // + // + // ### buf.writeUInt64LE(value, offset[, noAssert]) ### buf.writeUInt64BE(value, offset[, noAssert]) @@ -903,8 +903,8 @@ Example: console.log(buf); - // - // + // + // ### buf.writeDoubleLE(value, offset[, noAssert]) ### buf.writeDoubleBE(value, offset[, noAssert]) @@ -932,8 +932,8 @@ Example: console.log(buf); - // - // + // + // ### buf.writePointerLE(pointer, offset[, noAssert]) ### buf.writePointerBE(pointer, offset[, noAssert]) From 13b5d67fc720ea4363825b5eecdfe7620f40302f Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 17:38:40 -0700 Subject: [PATCH 45/61] doc: add another fake memory address to example --- doc/api/errors.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/errors.markdown b/doc/api/errors.markdown index df5f2d74ac4ce1..109bca49685328 100644 --- a/doc/api/errors.markdown +++ b/doc/api/errors.markdown @@ -389,7 +389,7 @@ fs.readFile('/some/file/that/does-not-exist', function nodeStyleCallback(err, da fs.readFile('/some/file/that/does-exist', function(err, data) { console.log(err) // null - console.log(data) // + console.log(data) // }) ``` From f451ee7693f67bfcdd36a89b79058a3f1fade984 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Sat, 23 May 2015 11:54:34 -0700 Subject: [PATCH 46/61] test: add Buffer#address() test case --- test/parallel/test-buffer.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/parallel/test-buffer.js b/test/parallel/test-buffer.js index 52ae8451a17fc8..7826774df14e2d 100644 --- a/test/parallel/test-buffer.js +++ b/test/parallel/test-buffer.js @@ -1172,3 +1172,12 @@ Buffer.poolSize = ps; assert.throws(function() { Buffer(10).copy(); }); + +// Test that Buffer#address() returns a hex string +var b = new Buffer(1); + +// just assert that it's a lowercase hex value with length >= 1 +var hex = /[\da-f]+/; + +console.log(b.address()); +assert(hex.test(b.address())); From 39d468c0da5dfcfe959422515d19e3a0a79fc156 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Sat, 23 May 2015 12:19:48 -0700 Subject: [PATCH 47/61] test: add Buffer int64 read/write tests Mostly copied and refactored from the `ref` tests. --- test/parallel/test-buffer-int64.js | 76 ++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 test/parallel/test-buffer-int64.js diff --git a/test/parallel/test-buffer-int64.js b/test/parallel/test-buffer-int64.js new file mode 100644 index 00000000000000..f870123dacf053 --- /dev/null +++ b/test/parallel/test-buffer-int64.js @@ -0,0 +1,76 @@ +'use strict'; +var common = require('../common'); +var assert = require('assert'); + +var Buffer = require('buffer').Buffer; + +var buf = new Buffer(8); + +['LE', 'BE'].forEach(function (endianness) { + // should allow simple ints to be written and read + var val = 123456789; + buf['writeInt64' + endianness](val, 0); + var rtn = buf['readInt64' + endianness](0); + assert.equal(val, rtn); + + // should allow INT64_MAX to be written and read + var val = '9223372036854775807'; + buf['writeInt64' + endianness](val, 0); + var rtn = buf['readInt64' + endianness](0); + assert.equal(val, rtn); + + // should return a Number when reading Number.MIN_SAFE_INTEGER + buf['writeInt64' + endianness](Number.MIN_SAFE_INTEGER, 0); + var rtn = buf['readInt64' + endianness](0); + assert.equal('number', typeof rtn); + assert.equal(Number.MIN_SAFE_INTEGER, rtn); + + // should return a Number when reading Number.MAX_SAFE_INTEGER + buf['writeInt64' + endianness](Number.MAX_SAFE_INTEGER, 0); + var rtn = buf['readInt64' + endianness](0); + assert.equal('number', typeof rtn); + assert.equal(Number.MAX_SAFE_INTEGER, rtn); + + // should return a String when reading Number.MAX_SAFE_INTEGER+1 + var plus_one = '9007199254740992'; + buf['writeInt64' + endianness](plus_one, 0); + var rtn = buf['readInt64' + endianness](0); + assert.equal('string', typeof rtn); + assert.equal(plus_one, rtn); + + // should return a String when reading Number.MIN_SAFE_INTEGER-1 + var minus_one = '-9007199254740992'; + buf['writeInt64' + endianness](minus_one, 0); + var rtn = buf['readInt64' + endianness](0); + assert.equal('string', typeof rtn); + assert.equal(minus_one, rtn); + + // should return a Number when reading 0, even when written as a String + var zero = '0'; + buf['writeInt64' + endianness](zero, 0); + var rtn = buf['readInt64' + endianness](0); + assert.equal('number', typeof rtn); + assert.equal(0, rtn); + + // should read and write a negative signed 64-bit integer + var val = -123456789; + buf['writeInt64' + endianness](val, 0); + assert.equal(val, buf['readInt64' + endianness](0)); + + // should read and write an unsigned 64-bit integer + var val = 123456789; + buf['writeUInt64' + endianness](val, 0); + assert.equal(val, buf['readUInt64' + endianness](0)); + + // should throw a RangeError upon INT64_MAX+1 being written + assert.throws(function () { + var val = '9223372036854775808'; + buf['writeInt64' + endianness](val, 0); + }, RangeError); + + // should throw a RangeError upon UINT64_MAX+1 being written + assert.throws(function () { + var val = '18446744073709551616'; + buf['writeUInt64' + endianness](val, 0); + }, RangeError); +}); From 0c80b8c9a279fdce11a024e9f8e082414a79e7c8 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Sat, 23 May 2015 12:22:47 -0700 Subject: [PATCH 48/61] test: add writeInt64 TypeError bad input tests --- test/parallel/test-buffer-int64.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/parallel/test-buffer-int64.js b/test/parallel/test-buffer-int64.js index f870123dacf053..8408ab51ee23ae 100644 --- a/test/parallel/test-buffer-int64.js +++ b/test/parallel/test-buffer-int64.js @@ -73,4 +73,14 @@ var buf = new Buffer(8); var val = '18446744073709551616'; buf['writeUInt64' + endianness](val, 0); }, RangeError); + + // should throw a TypeError upon invalid input + assert.throws(function () { + buf['writeInt64' + endianness]('bad', 0); + }, TypeError); + + // should throw a TypeError upon invalid input + assert.throws(function () { + buf['writeUInt64' + endianness]('bad', 0); + }, TypeError); }); From 1867bd63feaf5950899112c32008c7af601ccbde Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Sat, 23 May 2015 12:39:03 -0700 Subject: [PATCH 49/61] test: add Buffer read/writePointer test cases --- test/parallel/test-buffer-pointer.js | 44 ++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 test/parallel/test-buffer-pointer.js diff --git a/test/parallel/test-buffer-pointer.js b/test/parallel/test-buffer-pointer.js new file mode 100644 index 00000000000000..ea7d7728e44597 --- /dev/null +++ b/test/parallel/test-buffer-pointer.js @@ -0,0 +1,44 @@ +'use strict'; +var common = require('../common'); +var assert = require('assert'); + +var Buffer = require('buffer').Buffer; + +// TODO: use `sizeof.pointer` here when it's landed +var size = 8; + +['LE', 'BE'].forEach(function (endianness) { + var buf = new Buffer(size); + + // should write and read back a pointer (Buffer) in a Buffer with length + var test = new Buffer('hello'); + buf['writePointer' + endianness](test, 0); + var out = buf['readPointer' + endianness](0, test.length); + assert.equal(out.length, test.length); + assert.equal(out.address(), test.address()); + for (var i = 0, l = out.length; i < l; i++) { + assert.equal(out[i], test[i]); + } + + // should return `null` when reading a NULL pointer + buf.fill(0); + assert.strictEqual(null, buf['readPointer' + endianness](0)); + + // should write a NULL pointer when `null` is given + buf.fill(1); + buf['writePointer' + endianness](null, 0); + for (var i = 0, l = buf.length; i < l; i++) { + assert.equal(buf[i], 0); + } + + // should read two pointers next to each other in memory + var buf = new Buffer(8 * 2); + var a = new Buffer('hello'); + var b = new Buffer('world'); + buf['writePointer' + endianness](a, 0 * size); + buf['writePointer' + endianness](b, 1 * size); + var _a = buf['readPointer' + endianness](0 * size); + var _b = buf['readPointer' + endianness](1 * size); + assert.equal(a.address(), _a.address()); + assert.equal(b.address(), _b.address()); +}); From b929ed00fda009e2f02cfe08faa3523fb78fdad9 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Sat, 23 May 2015 13:14:04 -0700 Subject: [PATCH 50/61] buffer: use memcpy instead of reinterpret_cast To avoid aliasing. @bnoordhuis I believe this is what you meant in: https://github.com/nodejs/io.js/pull/1750#discussion_r30900208 The `test/parallel/test-buffer-pointer.js` test still passes after this patch, so apparently it's working correctly. --- src/node_buffer.cc | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 042d2f8331373b..13c2ea6c681077 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -593,7 +593,8 @@ void ReadPointerGeneric(const FunctionCallbackInfo& args) { char bytes[sizeof(ptr)]; }; - union NoAlias na = { *reinterpret_cast(ptr) }; + union NoAlias na; + memcpy(&na.val, ptr, sizeof(&ptr)); if (endianness != GetEndianness()) Swizzle(na.bytes, sizeof(na.bytes)); @@ -738,6 +739,7 @@ uint32_t WritePointerGeneric(const FunctionCallbackInfo& args) { ARGS_THIS(args[0].As()) char* ptr; + char* input_ptr; uint32_t offset = args[2]->Uint32Value(); CHECK_LE(offset + sizeof(ptr), obj_length); @@ -746,18 +748,18 @@ uint32_t WritePointerGeneric(const FunctionCallbackInfo& args) { return 0; } - ptr = static_cast(obj_data) + offset; - if (args[1]->IsNull()) { - *reinterpret_cast(ptr) = nullptr; + input_ptr = nullptr; } else { - char* input_ptr = Buffer::Data(args[1].As()); - *reinterpret_cast(ptr) = input_ptr; - - if (endianness != GetEndianness()) - Swizzle(ptr, sizeof(ptr)); + input_ptr = Buffer::Data(args[1].As()); } + ptr = static_cast(obj_data) + offset; + memcpy(ptr, &input_ptr, sizeof(input_ptr)); + + if (endianness != GetEndianness()) + Swizzle(ptr, sizeof(ptr)); + return offset + sizeof(ptr); } From 0e5cbe54c6496e8d361cb07491ad58b905b6a349 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Wed, 27 May 2015 18:14:45 -0700 Subject: [PATCH 51/61] buffer: use MDN links for max/min JS int values --- src/node_buffer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 13c2ea6c681077..51470c4b3d76c0 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -50,7 +50,7 @@ // used by the ReadInt64 functions to determine whether to return a Number // or String, based on whether or not a JS Number will lose precision. -// http://stackoverflow.com/q/307179/376773 +// http://mdn.io/max_safe_integer, http://mdn.io/min_safe_integer #define JS_MAX_INT +9007199254740991LL #define JS_MIN_INT -9007199254740991LL From d6e37cd4071b07ee23c79ec21c983ad44b10d5fb Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Wed, 27 May 2015 18:17:09 -0700 Subject: [PATCH 52/61] buffer: do not free() buffers from readPointer*() --- src/node_buffer.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 51470c4b3d76c0..03e118c756a04a 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -573,6 +573,12 @@ void ReadUInt64BE(const FunctionCallbackInfo& args) { } +void PointerFree(char* data, void* hint) { + // do nothing, since Buffers returned from `readPointer*()` + // must not be free()'d by us since we do not own the memory +} + + template void ReadPointerGeneric(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -600,7 +606,8 @@ void ReadPointerGeneric(const FunctionCallbackInfo& args) { Swizzle(na.bytes, sizeof(na.bytes)); if (na.val) { - args.GetReturnValue().Set(Buffer::Use(env, na.val, size)); + args.GetReturnValue().Set( + Buffer::New(env, na.val, size, PointerFree, nullptr)); } else { args.GetReturnValue().Set(v8::Null(env->isolate())); } From 01a3ad3266acfb363620e15d9902af362610dc90 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Mon, 1 Jun 2015 11:43:38 -0700 Subject: [PATCH 53/61] doc: remove backticks from code examples --- doc/api/buffer.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index 713b5e1041cdbb..f345ff4f5cc4c3 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -678,7 +678,7 @@ functions are only used in relation to the `dlopen` and `ffi` modules. Example: - // assume `buf` is a pointer to some external `int` data + // assume buf is a pointer to some external int data var intBuf = buf.readPointerLE(0, ffi.sizeof.int); console.log(intBuf); @@ -688,7 +688,7 @@ Example: // 6 - // if a NULL pointer is read, then JS `null` is returned + // if a NULL pointer is read, then JS null is returned buf.fill(0); console.log(buf.readPointerLE(0)); @@ -798,7 +798,7 @@ should not be used unless you are certain of correctness. Defaults to `false`. Example: - var buf = new Buffer(8); + var buf = new Buffer(8) b.writeUInt64LE('0xffffffffffff') @@ -967,7 +967,7 @@ Example: buf.writePointerBE(b, 0); // // ^ ^ ^ ^ ^ - // notice the value here is the same as the address of `b` + // notice the value here is the same as the address of b // if null is given, then a NULL pointer is written From df5bda7d6e250e683a12a68613caf5a708b5f513 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Mon, 1 Jun 2015 11:47:08 -0700 Subject: [PATCH 54/61] buffer: remove __STDC_FORMAT_MACROS Ben says it's not necessary. --- src/node_buffer.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 03e118c756a04a..da90a79d6a72f5 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -20,7 +20,6 @@ #define PRId64 "lld" #define PRIu64 "llu" #else - #define __STDC_FORMAT_MACROS #include #endif From 8477e98771921ab2ddf4e333e8d61c9d18112f7f Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Mon, 1 Jun 2015 12:25:20 -0700 Subject: [PATCH 55/61] buffer: revert unnecessary whitespace fix --- src/node_buffer.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index da90a79d6a72f5..1a956fd7913003 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -110,6 +110,7 @@ size_t Length(Handle obj) { return obj->GetIndexedPropertiesExternalArrayDataLength(); } + Local New(Isolate* isolate, Handle string, enum encoding enc) { EscapableHandleScope scope(isolate); From 3887226699a58213b8cb29ea4fa5ad58dca06e99 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Mon, 1 Jun 2015 12:26:47 -0700 Subject: [PATCH 56/61] buffer: add instanceof check to address() --- lib/buffer.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/buffer.js b/lib/buffer.js index c65242d9d9e6f5..7818275187d66f 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -455,6 +455,8 @@ Buffer.prototype.fill = function fill(val, start, end) { Buffer.prototype.address = function address() { + if (!(this instanceof Buffer)) + throw new TypeError('this must be a Buffer'); return binding.address(this); }; From c79e4f7b6bf917494e6699d85569be5b73097ced Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Thu, 4 Jun 2015 14:36:28 -0700 Subject: [PATCH 57/61] buffer: remove "pointer" functions These will be moved to static functions in the `ffi` module, to remind users of their unsafe nature on the API level. --- doc/api/buffer.markdown | 80 ----------------------- lib/buffer.js | 12 ---- src/node_buffer.cc | 98 ---------------------------- test/parallel/test-buffer-pointer.js | 44 ------------- 4 files changed, 234 deletions(-) delete mode 100644 test/parallel/test-buffer-pointer.js diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index f345ff4f5cc4c3..84ae79ab11a11c 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -653,47 +653,6 @@ Example: // 0.3333333333333333 -### buf.readPointerLE(offset, length[, noAssert]) -### buf.readPointerBE(offset, length[, noAssert]) - -* `offset` Number -* `length` Number -* `noAssert` Boolean, Optional, Default: false -* Return: Number - -Reads a pointer from the buffer by dereferencing at the specified -offset with specified endian format. - -A new Buffer instance is returned at the memory address pointed to -by `buf`, with its length set to `length`. If the NULL pointer is -read, then JS `null` is returned, and `length` is disregarded. - -Set `noAssert` to true to skip validation of `offset`. This means that `offset` -may be beyond the end of the buffer. Defaults to `false`. - -__WARNING__: The "Pointer" family of functions relate to direct -memory access, which can easily get you into trouble (segmentation -faults, etc.) if you don't know what you're doing. Generally these -functions are only used in relation to the `dlopen` and `ffi` modules. - -Example: - - // assume buf is a pointer to some external int data - var intBuf = buf.readPointerLE(0, ffi.sizeof.int); - - console.log(intBuf); - // - - console.log(intBuf.readInt32LE(0)); - // 6 - - - // if a NULL pointer is read, then JS null is returned - buf.fill(0); - - console.log(buf.readPointerLE(0)); - // null - ### buf.writeUInt8(value, offset[, noAssert]) * `value` Number @@ -935,45 +894,6 @@ Example: // // -### buf.writePointerLE(pointer, offset[, noAssert]) -### buf.writePointerBE(pointer, offset[, noAssert]) - -* `pointer` Buffer or null -* `offset` Number -* `noAssert` Boolean, Optional, Default: false - -Writes the memory address of `pointer` to the buffer at the specified offset -with specified endian format. If `null` is given the the NULL pointer will -be written as the memory address. - -Set `noAssert` to true to skip validation of `value` and `offset`. This means -that `value` may be too large for the specific function and `offset` may be -beyond the end of the buffer leading to the values being silently dropped. This -should not be used unless you are certain of correctness. Defaults to `false`. - -__WARNING__: The "Pointer" family of functions relate to direct -memory access, which can easily get you into trouble (segmentation -faults, etc.) if you don't know what you're doing. Generally these -functions are only used in relation to the `dlopen` and `ffi` modules. - -Example: - - var b = new Buffer('a'); - console.log(b.address()); - // '103032008' - - var b2 = new Buffer(ffi.sizeof.pointer); - - buf.writePointerBE(b, 0); - // - // ^ ^ ^ ^ ^ - // notice the value here is the same as the address of b - - - // if null is given, then a NULL pointer is written - buf.writePointerBE(null, 0); - // - ### buf.fill(value[, offset][, end]) * `value` diff --git a/lib/buffer.js b/lib/buffer.js index 7818275187d66f..ab6f224650adcb 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -857,18 +857,6 @@ Buffer.prototype.readUInt64BE = function readUInt64BE(offset, noAssert) { }; -Buffer.prototype.readPointerLE = function readPointerLE(offset, length, noAssert) { - offset = offset >>> 0; - return binding.readPointerLE(this, offset, length); -}; - - -Buffer.prototype.readPointerBE = function readPointerBE(offset, length, noAssert) { - offset = offset >>> 0; - return binding.readPointerBE(this, offset, length); -}; - - function checkInt(buffer, value, offset, ext, max, min) { if (!(buffer instanceof Buffer)) throw new TypeError('buffer must be a Buffer instance'); diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 1a956fd7913003..17a3221c59086e 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -573,57 +573,6 @@ void ReadUInt64BE(const FunctionCallbackInfo& args) { } -void PointerFree(char* data, void* hint) { - // do nothing, since Buffers returned from `readPointer*()` - // must not be free()'d by us since we do not own the memory -} - - -template -void ReadPointerGeneric(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - - CHECK(args[0]->IsObject()); - ARGS_THIS(args[0].As()); - - char* ptr; - uint32_t offset = args[1]->Uint32Value(); - CHECK_LE(offset + sizeof(ptr), obj_length); - - size_t size = args[2]->Uint32Value(); - - ptr = static_cast(obj_data) + offset; - - union NoAlias { - char* val; - char bytes[sizeof(ptr)]; - }; - - union NoAlias na; - memcpy(&na.val, ptr, sizeof(&ptr)); - - if (endianness != GetEndianness()) - Swizzle(na.bytes, sizeof(na.bytes)); - - if (na.val) { - args.GetReturnValue().Set( - Buffer::New(env, na.val, size, PointerFree, nullptr)); - } else { - args.GetReturnValue().Set(v8::Null(env->isolate())); - } -} - - -void ReadPointerLE(const FunctionCallbackInfo& args) { - ReadPointerGeneric(args); -} - - -void ReadPointerBE(const FunctionCallbackInfo& args) { - ReadPointerGeneric(args); -} - - template uint32_t WriteFloatGeneric(const FunctionCallbackInfo& args) { ARGS_THIS(args[0].As()) @@ -738,49 +687,6 @@ void WriteUInt64BE(const FunctionCallbackInfo& args) { } -template -uint32_t WritePointerGeneric(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - - CHECK(args[0]->IsObject()); - ARGS_THIS(args[0].As()) - - char* ptr; - char* input_ptr; - uint32_t offset = args[2]->Uint32Value(); - CHECK_LE(offset + sizeof(ptr), obj_length); - - if (!(args[1]->IsNull() || Buffer::HasInstance(args[1]))) { - env->ThrowTypeError("value must be a Buffer instance or null"); - return 0; - } - - if (args[1]->IsNull()) { - input_ptr = nullptr; - } else { - input_ptr = Buffer::Data(args[1].As()); - } - - ptr = static_cast(obj_data) + offset; - memcpy(ptr, &input_ptr, sizeof(input_ptr)); - - if (endianness != GetEndianness()) - Swizzle(ptr, sizeof(ptr)); - - return offset + sizeof(ptr); -} - - -void WritePointerLE(const FunctionCallbackInfo& args) { - args.GetReturnValue().Set(WritePointerGeneric(args)); -} - - -void WritePointerBE(const FunctionCallbackInfo& args) { - args.GetReturnValue().Set(WritePointerGeneric(args)); -} - - void ByteLengthUtf8(const FunctionCallbackInfo &args) { CHECK(args[0]->IsString()); @@ -1014,8 +920,6 @@ void Initialize(Handle target, env->SetMethod(target, "readInt64LE", ReadInt64LE); env->SetMethod(target, "readUInt64BE", ReadUInt64BE); env->SetMethod(target, "readUInt64LE", ReadUInt64LE); - env->SetMethod(target, "readPointerBE", ReadPointerBE); - env->SetMethod(target, "readPointerLE", ReadPointerLE); env->SetMethod(target, "writeDoubleBE", WriteDoubleBE); env->SetMethod(target, "writeDoubleLE", WriteDoubleLE); @@ -1025,8 +929,6 @@ void Initialize(Handle target, env->SetMethod(target, "writeInt64LE", WriteInt64LE); env->SetMethod(target, "writeUInt64BE", WriteUInt64BE); env->SetMethod(target, "writeUInt64LE", WriteUInt64LE); - env->SetMethod(target, "writePointerBE", WritePointerBE); - env->SetMethod(target, "writePointerLE", WritePointerLE); } diff --git a/test/parallel/test-buffer-pointer.js b/test/parallel/test-buffer-pointer.js deleted file mode 100644 index ea7d7728e44597..00000000000000 --- a/test/parallel/test-buffer-pointer.js +++ /dev/null @@ -1,44 +0,0 @@ -'use strict'; -var common = require('../common'); -var assert = require('assert'); - -var Buffer = require('buffer').Buffer; - -// TODO: use `sizeof.pointer` here when it's landed -var size = 8; - -['LE', 'BE'].forEach(function (endianness) { - var buf = new Buffer(size); - - // should write and read back a pointer (Buffer) in a Buffer with length - var test = new Buffer('hello'); - buf['writePointer' + endianness](test, 0); - var out = buf['readPointer' + endianness](0, test.length); - assert.equal(out.length, test.length); - assert.equal(out.address(), test.address()); - for (var i = 0, l = out.length; i < l; i++) { - assert.equal(out[i], test[i]); - } - - // should return `null` when reading a NULL pointer - buf.fill(0); - assert.strictEqual(null, buf['readPointer' + endianness](0)); - - // should write a NULL pointer when `null` is given - buf.fill(1); - buf['writePointer' + endianness](null, 0); - for (var i = 0, l = buf.length; i < l; i++) { - assert.equal(buf[i], 0); - } - - // should read two pointers next to each other in memory - var buf = new Buffer(8 * 2); - var a = new Buffer('hello'); - var b = new Buffer('world'); - buf['writePointer' + endianness](a, 0 * size); - buf['writePointer' + endianness](b, 1 * size); - var _a = buf['readPointer' + endianness](0 * size); - var _b = buf['readPointer' + endianness](1 * size); - assert.equal(a.address(), _a.address()); - assert.equal(b.address(), _b.address()); -}); From 91e35b4983d00b48e5d467364862020702ceef3e Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Thu, 4 Jun 2015 14:39:17 -0700 Subject: [PATCH 58/61] buffer: revert unnecessary whitespace change --- src/node_buffer.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 17a3221c59086e..b804948c708298 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -897,6 +897,7 @@ void SetupBufferJS(const FunctionCallbackInfo& args) { v8::ReadOnly); } + void Initialize(Handle target, Handle unused, Handle context) { From 797ef991426327b3c07176ef54be7af791844af8 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Thu, 4 Jun 2015 14:43:38 -0700 Subject: [PATCH 59/61] buffer: use base of 10 for the strto(u)ll calls Less room for computer error this way --- src/node_buffer.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index b804948c708298..80c93d01ea33a8 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -630,7 +630,8 @@ uint32_t WriteInt64Generic(const FunctionCallbackInfo& args) { // Have to do this because strt(u)oll doesn't set errno to 0 on success errno = 0; node::Utf8Value str(env->isolate(), args[1]); - val = strtoT(*str, nullptr, 0); + + val = strtoT(*str, nullptr, 10); if (errno != 0) { if (errno == EINVAL) { From 475aabba0c8ad175c6ba8577217d52e20c495bd7 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Thu, 4 Jun 2015 14:45:56 -0700 Subject: [PATCH 60/61] buffer: change C++-land throw to a CHECK() We're already checking for typeof "string"/"number" in JS-land. No need for the extra conditional logic. --- src/node_buffer.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 80c93d01ea33a8..de88c26ad6f4c6 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -621,6 +621,7 @@ uint32_t WriteInt64Generic(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); CHECK(args[0]->IsObject()); + CHECK(args[1]->IsString() || args[1]->IsNumber()); ARGS_THIS(args[0].As()) T val; @@ -644,7 +645,7 @@ uint32_t WriteInt64Generic(const FunctionCallbackInfo& args) { return 0; } } else { - env->ThrowTypeError("Argument must be a string or number"); + UNREACHABLE(): return 0; } From ce009832a72b325f512c9bb091c9736833d52373 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Thu, 4 Jun 2015 17:50:18 -0700 Subject: [PATCH 61/61] buffer: make strto(u)ll usage cross-platform The errno EINVAL behavior is a BSDism, and won't work cross platform. Instead, pass in the char* endptr value and check where it ended up. --- src/node_buffer.cc | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index de88c26ad6f4c6..0a94994a02f8ea 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -616,7 +616,7 @@ void WriteDoubleBE(const FunctionCallbackInfo& args) { template + T (*strtoT)(const char*, char**, int), T min, T max> uint32_t WriteInt64Generic(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -628,24 +628,22 @@ uint32_t WriteInt64Generic(const FunctionCallbackInfo& args) { if (args[1]->IsNumber()) { val = args[1]->IntegerValue(); } else if (args[1]->IsString()) { - // Have to do this because strt(u)oll doesn't set errno to 0 on success - errno = 0; node::Utf8Value str(env->isolate(), args[1]); + const char* cstr = *str; + char* endptr; - val = strtoT(*str, nullptr, 10); + errno = 0; /* To distinguish success/failure after call */ + val = strtoT(cstr, &endptr, 10); - if (errno != 0) { - if (errno == EINVAL) { - env->ThrowTypeError("value is invalid"); - } else if (errno == ERANGE) { - env->ThrowRangeError("value is out-of-range"); - } else { - env->ThrowError("unspecified error"); - } + if (errno == ERANGE && (val == min || val == max)) { + env->ThrowRangeError("value is out-of-range"); + return 0; + } else if (endptr == cstr || *endptr != '\0') { + env->ThrowTypeError("value is invalid"); return 0; } } else { - UNREACHABLE(): + UNREACHABLE(); return 0; } @@ -667,25 +665,25 @@ uint32_t WriteInt64Generic(const FunctionCallbackInfo& args) { void WriteInt64LE(const FunctionCallbackInfo& args) { - args.GetReturnValue().Set(WriteInt64Generic(args)); + args.GetReturnValue().Set(WriteInt64Generic(args)); } void WriteInt64BE(const FunctionCallbackInfo& args) { - args.GetReturnValue().Set(WriteInt64Generic(args)); + args.GetReturnValue().Set(WriteInt64Generic(args)); } void WriteUInt64LE(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(WriteInt64Generic(args)); + strtoull, 0, ULLONG_MAX>(args)); } void WriteUInt64BE(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(WriteInt64Generic(args)); + strtoull, 0, ULLONG_MAX>(args)); }