Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Buffer: adjust buffer size so the base64-decoded input fits snugly.

Stops Valgrind from complaining about uninitialized memory access.
  • Loading branch information...
commit 95638c9b0d3a1133f944d9fcd65ae812dc914974 1 parent b5b83b2
@bnoordhuis bnoordhuis authored ry committed
View
2  src/node.cc
@@ -783,6 +783,8 @@ enum encoding ParseEncoding(Handle<Value> encoding_v, enum encoding _default) {
return UTF8;
} else if (strcasecmp(*encoding, "ascii") == 0) {
return ASCII;
+ } else if (strcasecmp(*encoding, "base64") == 0) {
+ return BASE64;
} else if (strcasecmp(*encoding, "binary") == 0) {
return BINARY;
} else if (strcasecmp(*encoding, "raw") == 0) {
View
2  src/node.h
@@ -41,7 +41,7 @@ do { \
__callback##_TEM); \
} while (0)
-enum encoding {ASCII, UTF8, BINARY};
+enum encoding {ASCII, UTF8, BASE64, BINARY};
enum encoding ParseEncoding(v8::Handle<v8::Value> encoding_v,
enum encoding _default = BINARY);
void FatalException(v8::TryCatch &try_catch);
View
28 src/node_buffer.cc
@@ -149,6 +149,29 @@ Handle<Value> Buffer::New(const Arguments &args) {
Local<String> s = args[0]->ToString();
enum encoding e = ParseEncoding(args[1], UTF8);
int length = e == UTF8 ? s->Utf8Length() : s->Length();
+
+ // input gets base64-decoded, adjust buffer size
+ if (e == BASE64 && length > 0) {
+ const int remainder = length % 4;
+
+ length = (length / 4) * 3;
+ if (remainder) {
+ if (length == 0 && remainder == 1) {
+ // special case: 1-byte input cannot be decoded, return empty buffer
+ length = 0;
+ } else {
+ // non-padded input, add 1 or 2 extra bytes
+ length += 1 + (remainder == 3);
+ }
+ } else {
+ // check for trailing padding (1 or 2 bytes)
+ const String::AsciiValue data(s);
+ const char *const end = *data + data.length();
+ if (end[-1] == '=') length--;
+ if (end[-2] == '=') length--;
+ }
+ }
+
buffer = new Buffer(length);
} else if (Buffer::HasInstance(args[0]) && args.Length() > 2) {
// var slice = new Buffer(buffer, 123, 130);
@@ -516,6 +539,11 @@ 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));
+ }
+
if (offset >= buffer->length_) {
return ThrowException(Exception::TypeError(String::New(
"Offset is out of bounds")));
View
42 test/simple/test-buffer.js
@@ -258,5 +258,43 @@ bytesWritten = b.write(expected, 0, 'base64');
assert.equal(quote, b.toString('ascii', 0, quote.length));
assert.equal(quote.length+1, bytesWritten); // writes a \0 too
-
-
+assert.equal(new Buffer('', 'base64').toString(), '');
+assert.equal(new Buffer('K', 'base64').toString(), '');
+
+// multiple-of-4 with padding
+assert.equal(new Buffer('Kg==', 'base64').toString(), '*');
+assert.equal(new Buffer('Kio=', 'base64').toString(), '**');
+assert.equal(new Buffer('Kioq', 'base64').toString(), '***');
+assert.equal(new Buffer('KioqKg==', 'base64').toString(), '****');
+assert.equal(new Buffer('KioqKio=', 'base64').toString(), '*****');
+assert.equal(new Buffer('KioqKioq', 'base64').toString(), '******');
+assert.equal(new Buffer('KioqKioqKg==', 'base64').toString(), '*******');
+assert.equal(new Buffer('KioqKioqKio=', 'base64').toString(), '********');
+assert.equal(new Buffer('KioqKioqKioq', 'base64').toString(), '*********');
+assert.equal(new Buffer('KioqKioqKioqKg==', 'base64').toString(), '**********');
+assert.equal(new Buffer('KioqKioqKioqKio=', 'base64').toString(), '***********');
+assert.equal(new Buffer('KioqKioqKioqKioq', 'base64').toString(), '************');
+assert.equal(new Buffer('KioqKioqKioqKioqKg==', 'base64').toString(), '*************');
+assert.equal(new Buffer('KioqKioqKioqKioqKio=', 'base64').toString(), '**************');
+assert.equal(new Buffer('KioqKioqKioqKioqKioq', 'base64').toString(), '***************');
+assert.equal(new Buffer('KioqKioqKioqKioqKioqKg==', 'base64').toString(), '****************');
+assert.equal(new Buffer('KioqKioqKioqKioqKioqKio=', 'base64').toString(), '*****************');
+assert.equal(new Buffer('KioqKioqKioqKioqKioqKioq', 'base64').toString(), '******************');
+assert.equal(new Buffer('KioqKioqKioqKioqKioqKioqKg==', 'base64').toString(), '*******************');
+assert.equal(new Buffer('KioqKioqKioqKioqKioqKioqKio=', 'base64').toString(), '********************');
+
+// no padding, not a multiple of 4
+assert.equal(new Buffer('Kg', 'base64').toString(), '*');
+assert.equal(new Buffer('Kio', 'base64').toString(), '**');
+assert.equal(new Buffer('KioqKg', 'base64').toString(), '****');
+assert.equal(new Buffer('KioqKio', 'base64').toString(), '*****');
+assert.equal(new Buffer('KioqKioqKg', 'base64').toString(), '*******');
+assert.equal(new Buffer('KioqKioqKio', 'base64').toString(), '********');
+assert.equal(new Buffer('KioqKioqKioqKg', 'base64').toString(), '**********');
+assert.equal(new Buffer('KioqKioqKioqKio', 'base64').toString(), '***********');
+assert.equal(new Buffer('KioqKioqKioqKioqKg', 'base64').toString(), '*************');
+assert.equal(new Buffer('KioqKioqKioqKioqKio', 'base64').toString(), '**************');
+assert.equal(new Buffer('KioqKioqKioqKioqKioqKg', 'base64').toString(), '****************');
+assert.equal(new Buffer('KioqKioqKioqKioqKioqKio', 'base64').toString(), '*****************');
+assert.equal(new Buffer('KioqKioqKioqKioqKioqKioqKg', 'base64').toString(), '*******************');
+assert.equal(new Buffer('KioqKioqKioqKioqKioqKioqKio', 'base64').toString(), '********************');

3 comments on commit 95638c9

@pkrumins

Base64 is broken currently for binary data. Please add binary tests, not just ascii.

@bnoordhuis

@pkrumins: If we are talking about the same thing then this problem should be fixed. Could you post an example test if it hasn't?

Please sign in to comment.
Something went wrong with that request. Please try again.