std::bad_alloc exception if a too big buffer is allocated #1710

Closed
exi opened this Issue Sep 15, 2011 · 4 comments

Projects

None yet

3 participants

@exi
exi commented Sep 15, 2011

if i allocate a buffer that is bigger than the RAM left, i get:
%node (master,134)
> var b = new Buffer(999999999);
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
[2] 13425 abort node

this happens in the current master (commit cb6b9eb)

@tshinnic

Tested on 0.5.8 pre master dcd911e:

> [ os.type(), os.platform(), os.arch(), os.release(), os.totalmem(), os.freemem() ]
[ 'Linux',
  'linux',
  'ia32',
  '2.6.40.4-5.fc15.i686.PAE',
  1051783168,
  143138816 ]
> [ process.versions, process.platform, process.arch ]
[ { node: '0.5.8-pre',
    v8: '3.6.4',
    ares: '1.7.4',
    uv: '0.1',
    openssl: '1.0.0e-fips' },
  'linux',
  'ia32' ]

Four different behaviors:

[Tom@TLSF15A node-1]$ ./node
> var b = new Buffer(999999999)
> 

[Tom@TLSF15A node-1]$ ./node
> var b = new Buffer(1250000000)
FATAL ERROR: v8::Object::SetIndexedPropertiesToExternalArrayData() length exceeds max acceptable value

[Tom@TLSF15A node-1]$ ./node
> var b = new Buffer(1500000000)
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Aborted (core dumped)

> [Tom@TLSF15A node-1]$ ./node
> var b = new Buffer(2999999999)
TypeError: Bad argument
    at new Buffer (buffer.js:235:21)
    at repl:1:9
    at REPLServer.eval (repl.js:80:28)
    at repl.js:178:16
    at REPLServer.eval (repl.js:84:5)
    at Interface.<anonymous> (repl.js:170:12)
    at Interface.emit (events.js:67:17)
    at Interface._onLine (readline.js:162:10)
    at Interface._line (readline.js:425:8)
    at Interface._ttyWrite (readline.js:602:14)

Three different memory sizes for changes in behavior

1073741824 == 0x40000000

[Tom@TLSF15A node-1]$ ./node
> var b = new Buffer(1073741823)
>

[Tom@TLSF15A node-1]$ ./node
> var b = new Buffer(1073741824)
FATAL ERROR: v8::Object::SetIndexedPropertiesToExternalArrayData() length exceeds max acceptable value

1500025000 == 0x596890A8
(Note that this address moved on me while testing, so probably is dependent on a system value like free memory)

[Tom@TLSF15A node-1]$ ./node
> var b = new Buffer(1500025000)
FATAL ERROR: v8::Object::SetIndexedPropertiesToExternalArrayData() length exceeds max acceptable value

[Tom@TLSF15A node-1]$ ./node
> var b = new Buffer(1500025050)
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Aborted (core dumped)

2147483647 == 0x7FFFFFFF

[Tom@TLSF15A node-1]$ ./node
> var b = new Buffer(2147483647)      == 7FFFFFFF
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Aborted (core dumped)

[Tom@TLSF15A node-1]$ ./node
> var b = new Buffer(2147483648)
TypeError: Bad argument
    at new Buffer (buffer.js:235:21)
    at repl:1:9
    at REPLServer.eval (repl.js:80:28)
    at repl.js:178:16
    at REPLServer.eval (repl.js:84:5)
    at Interface.<anonymous> (repl.js:170:12)
    at Interface.emit (events.js:67:17)
    at Interface._onLine (readline.js:162:10)
    at Interface._line (readline.js:425:8)
    at Interface._ttyWrite (readline.js:602:14)

Testing which of all these errors might be caught:

[Tom@TLSF15A node-1]$ ./node
> function swh(howMany) {
...   try {
...     var b = new Buffer(howMany);
...   } catch(ex) {
...     console.log('  eek! ', ex);
...   }
... }
> swh(1250000000)
FATAL ERROR: v8::Object::SetIndexedPropertiesToExternalArrayData() length exceeds max acceptable value

> swh(1500030000)
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Aborted (core dumped)

> swh(2999999999)
  eek!  [TypeError: Bad argument]
>
@tshinnic

Internally external arrays are checked against the limit in deps/v8/src/objects.h

    ExternalArray::kMaxLength = 0x3fffffff;

or 1073741823 which is the first magic number in testing above.

buffer.js and maybe node_buffer.cc should check for sizes below this, e.g.

    if (this.length > Buffer.poolSize) {
      // Big buffer, just alloc one.
      this.parent = new SlowBuffer(this.length);

should have an additional check for 'goodness'.

Unfortunately the v8 limit is only known from v8/src/objects.h in v8/src/v8.h which is not the same beast as v8/include/v8.h. Is it okay to just use the magic constant by copying rather than importing/including?

@tshinnic tshinnic added a commit to tshinnic/node-1 that referenced this issue Sep 19, 2011
@tshinnic tshinnic Fix for issue #1710 : aborts from new Buffer(too_large)
"std::bad_alloc exception if a too big buffer is allocated"

Add check against for upper limit size for ExternalArray within v8.
edd1fd3
@tshinnic

Submitted pull request #1735

@bnoordhuis
Member

Addressed in 8c02f9b.

@bnoordhuis bnoordhuis closed this Jul 28, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment