aboutsummaryrefslogtreecommitdiff
path: root/src/node_buffer.cc
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2012-02-01 22:07:42 +0100
committerBen Noordhuis <info@bnoordhuis.nl>2012-02-02 19:13:56 +0100
commitf101f7c9babb31f077c78b52de7cc45ad687f57e (patch)
tree8184418aa92f8c0a5dee1d441922a8732666a200 /src/node_buffer.cc
parent67cd05472e0c3b2859469d2f1d83400b99464447 (diff)
downloadandroid-node-v8-f101f7c9babb31f077c78b52de7cc45ad687f57e.tar.gz
android-node-v8-f101f7c9babb31f077c78b52de7cc45ad687f57e.tar.bz2
android-node-v8-f101f7c9babb31f077c78b52de7cc45ad687f57e.zip
buffers: honor length argument in base64 decoder
Honor the length argument in `buf.write(s, 0, buf.length, 'base64')`. Before this commit, the length argument was ignored. The decoder would keep writing until it hit the end of the buffer. Since most buffers in Node are slices of a parent buffer (the slab), this bug would overwrite the content of adjacent buffers. The bug is trivially demonstrated with the following test case: var assert = require('assert'); var a = Buffer(3); var b = Buffer('xxx'); a.write('aaaaaaaa', 'base64'); assert.equal(b.toString(), 'xxx'); This commit coincidentally also fixes a bug where Buffer._charsWritten was not updated for zero length buffers.
Diffstat (limited to 'src/node_buffer.cc')
-rw-r--r--src/node_buffer.cc71
1 files changed, 28 insertions, 43 deletions
diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index d2335ff28f..34ae5e5cc0 100644
--- a/src/node_buffer.cc
+++ b/src/node_buffer.cc
@@ -584,17 +584,6 @@ Handle<Value> Buffer::AsciiWrite(const Arguments &args) {
Handle<Value> Buffer::Base64Write(const Arguments &args) {
HandleScope scope;
- assert(unbase64('/') == 63);
- assert(unbase64('+') == 62);
- assert(unbase64('T') == 19);
- assert(unbase64('Z') == 25);
- assert(unbase64('t') == 45);
- assert(unbase64('z') == 51);
-
- assert(unbase64(' ') == -2);
- assert(unbase64('\n') == -2);
- assert(unbase64('\r') == -2);
-
Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
if (!args[0]->IsString()) {
@@ -604,67 +593,52 @@ Handle<Value> Buffer::Base64Write(const Arguments &args) {
String::AsciiValue s(args[0]->ToString());
size_t offset = args[1]->Int32Value();
-
- // handle zero-length buffers graciously
- if (offset == 0 && buffer->length_ == 0) {
- return scope.Close(Integer::New(0));
- }
+ size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
+ : args[2]->Uint32Value();
+ max_length = MIN(s.length(), MIN(buffer->length_ - offset, max_length));
if (offset >= buffer->length_) {
return ThrowException(Exception::TypeError(String::New(
"Offset is out of bounds")));
}
- const size_t size = base64_decoded_size(*s, s.length());
- if (size > buffer->length_ - offset) {
- // throw exception, don't silently truncate
- return ThrowException(Exception::TypeError(String::New(
- "Buffer too small")));
- }
-
char a, b, c, d;
char* start = buffer->data_ + offset;
char* dst = start;
- const char *src = *s;
- const char *const srcEnd = src + s.length();
+ char* const dstEnd = dst + max_length;
+ const char* src = *s;
+ const char* const srcEnd = src + s.length();
- while (src < srcEnd) {
+ while (src < srcEnd && dst < dstEnd) {
int remaining = srcEnd - src;
- while (unbase64(*src) < 0 && src < srcEnd) {
- src++;
- remaining--;
- }
+ while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--;
if (remaining == 0 || *src == '=') break;
a = unbase64(*src++);
- while (unbase64(*src) < 0 && src < srcEnd) {
- src++;
- remaining--;
- }
+ while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--;
if (remaining <= 1 || *src == '=') break;
b = unbase64(*src++);
+
*dst++ = (a << 2) | ((b & 0x30) >> 4);
+ if (dst == dstEnd) break;
- while (unbase64(*src) < 0 && src < srcEnd) {
- src++;
- remaining--;
- }
+ while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--;
if (remaining <= 2 || *src == '=') break;
c = unbase64(*src++);
+
*dst++ = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2);
+ if (dst == dstEnd) break;
- while (unbase64(*src) < 0 && src < srcEnd) {
- src++;
- remaining--;
- }
+ while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--;
if (remaining <= 3 || *src == '=') break;
d = unbase64(*src++);
+
*dst++ = ((c & 0x03) << 6) | (d & 0x3F);
}
constructor_template->GetFunction()->Set(chars_written_sym,
- Integer::New(s.length()));
+ Integer::New(dst - start));
return scope.Close(Integer::New(dst - start));
}
@@ -759,6 +733,17 @@ bool Buffer::HasInstance(v8::Handle<v8::Value> val) {
void Buffer::Initialize(Handle<Object> target) {
HandleScope scope;
+ // sanity checks
+ assert(unbase64('/') == 63);
+ assert(unbase64('+') == 62);
+ assert(unbase64('T') == 19);
+ assert(unbase64('Z') == 25);
+ assert(unbase64('t') == 45);
+ assert(unbase64('z') == 51);
+ assert(unbase64(' ') == -2);
+ assert(unbase64('\n') == -2);
+ assert(unbase64('\r') == -2);
+
length_symbol = Persistent<String>::New(String::NewSymbol("length"));
chars_written_sym = Persistent<String>::New(String::NewSymbol("_charsWritten"));