This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

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

Stops Valgrind from complaining about uninitialized memory access.
  • Loading branch information...
bnoordhuis authored and ry committed Jul 28, 2010
1 parent b5b83b2 commit 95638c9b0d3a1133f944d9fcd65ae812dc914974
Showing with 71 additions and 3 deletions.
  1. +2 −0 src/node.cc
  2. +1 −1 src/node.h
  3. +28 −0 src/node_buffer.cc
  4. +40 −2 test/simple/test-buffer.js
View
@@ -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
@@ -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
@@ -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
@@ -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

This comment has been minimized.

Show comment Hide comment
@pkrumins

pkrumins Jul 29, 2010

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

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

@bnoordhuis

This comment has been minimized.

Show comment Hide comment
@bnoordhuis

bnoordhuis Aug 2, 2010

Member

@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?

Member

bnoordhuis replied Aug 2, 2010

@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?

@pkrumins

This comment has been minimized.

Show comment Hide comment
Please sign in to comment.