From 22478d36692b492e993a28b85328beffe89ff604 Mon Sep 17 00:00:00 2001 From: Matt Loring Date: Tue, 10 Nov 2015 18:25:01 -0800 Subject: [PATCH] buffer: move checkFloat from lib into src The type and range checks performed by this function can be done more efficiently in native code. PR-URL: https://github.com/nodejs/node/pull/3763 Reviewed-By: Trevor Norris Reviewed-By: James M Snell --- lib/buffer.js | 28 ++++++++++++---------------- src/node_buffer.cc | 43 ++++++++++++++++++++++++++++++------------- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/lib/buffer.js b/lib/buffer.js index dec02ed8e70a6e..dcb1779dbbc0d8 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -1028,20 +1028,13 @@ Buffer.prototype.writeInt32BE = function(value, offset, noAssert) { }; -function checkFloat(buffer, value, offset, ext) { - if (!(buffer instanceof Buffer)) - throw new TypeError('"buffer" argument must be a Buffer instance'); - if (offset + ext > buffer.length) - throw new RangeError('Index out of range'); -} - - Buffer.prototype.writeFloatLE = function writeFloatLE(val, offset, noAssert) { val = +val; offset = offset >>> 0; if (!noAssert) - checkFloat(this, val, offset, 4); - binding.writeFloatLE(this, val, offset); + binding.writeFloatLE(this, val, offset); + else + binding.writeFloatLE(this, val, offset, true); return offset + 4; }; @@ -1050,8 +1043,9 @@ Buffer.prototype.writeFloatBE = function writeFloatBE(val, offset, noAssert) { val = +val; offset = offset >>> 0; if (!noAssert) - checkFloat(this, val, offset, 4); - binding.writeFloatBE(this, val, offset); + binding.writeFloatBE(this, val, offset); + else + binding.writeFloatBE(this, val, offset, true); return offset + 4; }; @@ -1060,8 +1054,9 @@ Buffer.prototype.writeDoubleLE = function writeDoubleLE(val, offset, noAssert) { val = +val; offset = offset >>> 0; if (!noAssert) - checkFloat(this, val, offset, 8); - binding.writeDoubleLE(this, val, offset); + binding.writeDoubleLE(this, val, offset); + else + binding.writeDoubleLE(this, val, offset, true); return offset + 8; }; @@ -1070,7 +1065,8 @@ Buffer.prototype.writeDoubleBE = function writeDoubleBE(val, offset, noAssert) { val = +val; offset = offset >>> 0; if (!noAssert) - checkFloat(this, val, offset, 8); - binding.writeDoubleBE(this, val, offset); + binding.writeDoubleBE(this, val, offset); + else + binding.writeDoubleBE(this, val, offset, true); return offset + 8; }; diff --git a/src/node_buffer.cc b/src/node_buffer.cc index b508c48c4742e4..8b850700792a5b 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -730,15 +730,37 @@ void ReadDoubleBE(const FunctionCallbackInfo& args) { template -uint32_t WriteFloatGeneric(const FunctionCallbackInfo& args) { - SPREAD_ARG(args[0], ts_obj); +void WriteFloatGeneric(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + + bool should_assert = args.Length() < 4; + + if (should_assert) { + THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]); + } + + Local ts_obj = args[0].As(); + ArrayBuffer::Contents ts_obj_c = ts_obj->Buffer()->GetContents(); + const size_t ts_obj_offset = ts_obj->ByteOffset(); + const size_t ts_obj_length = ts_obj->ByteLength(); + char* const ts_obj_data = + static_cast(ts_obj_c.Data()) + ts_obj_offset; + if (ts_obj_length > 0) + CHECK_NE(ts_obj_data, nullptr); + + T val = args[1]->NumberValue(env->context()).FromMaybe(0); + size_t offset = args[2]->IntegerValue(env->context()).FromMaybe(0); - T val = args[1]->NumberValue(); - uint32_t offset = args[2]->Uint32Value(); size_t memcpy_num = sizeof(T); if (offset + sizeof(T) > ts_obj_length) memcpy_num = ts_obj_length - offset; + if (should_assert) { + CHECK_NOT_OOB(offset + memcpy_num >= memcpy_num); + CHECK_NOT_OOB(offset + memcpy_num <= ts_obj_length); + } + CHECK_LE(offset + memcpy_num, ts_obj_length); + union NoAlias { T val; char bytes[sizeof(T)]; @@ -749,31 +771,26 @@ uint32_t WriteFloatGeneric(const FunctionCallbackInfo& args) { if (endianness != GetEndianness()) Swizzle(na.bytes, sizeof(na.bytes)); memcpy(ptr, na.bytes, memcpy_num); - return offset + memcpy_num; } void WriteFloatLE(const FunctionCallbackInfo& args) { - THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]); - args.GetReturnValue().Set(WriteFloatGeneric(args)); + WriteFloatGeneric(args); } void WriteFloatBE(const FunctionCallbackInfo& args) { - THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]); - args.GetReturnValue().Set(WriteFloatGeneric(args)); + WriteFloatGeneric(args); } void WriteDoubleLE(const FunctionCallbackInfo& args) { - THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]); - args.GetReturnValue().Set(WriteFloatGeneric(args)); + WriteFloatGeneric(args); } void WriteDoubleBE(const FunctionCallbackInfo& args) { - THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]); - args.GetReturnValue().Set(WriteFloatGeneric(args)); + WriteFloatGeneric(args); }