diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2012-02-01 22:07:42 +0100 |
---|---|---|
committer | Ben Noordhuis <info@bnoordhuis.nl> | 2012-02-02 19:13:56 +0100 |
commit | f101f7c9babb31f077c78b52de7cc45ad687f57e (patch) | |
tree | 8184418aa92f8c0a5dee1d441922a8732666a200 /src/node_buffer.cc | |
parent | 67cd05472e0c3b2859469d2f1d83400b99464447 (diff) | |
download | android-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.cc | 71 |
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")); |