Hi Node.js Gurus!
When writing a node.js extension how do you safely return an object that 
has node::Buffer properties safely so they don't get garbage collected 
afterwards?

Code extract from my node-sodium library, a port of lib sodium to node.

    #define NEW_BUFFER_AND_PTR(name, size) \
      Buffer* name = Buffer::New(size); \
      unsigned char* name ## _ptr = (unsigned char*)Buffer::Data(name)

    Handle<Value> bind_crypto_sign_keypair(const Arguments& args) {
      HandleScope scope;
    
      NEW_BUFFER_AND_PTR(vk, crypto_sign_PUBLICKEYBYTES);
      NEW_BUFFER_AND_PTR(sk, crypto_sign_SECRETKEYBYTES);

      if( crypto_sign_keypair(vk_ptr, sk_ptr) == 0) {
        Local<Object> result = Object::New();
        result->Set(String::NewSymbol("publicKey"), vk->handle_);
        result->Set(String::NewSymbol("secretKey"), sk->handle_);
        return scope.Close(result);
      }
      return scope.Close(Undefined());
    }

This function creates a set of public and secret keys used for signing.
In Javascript I do

    var keys = binding.crypto_sign_keypair();
    console.log(keys.publicKey);
    console.log(keys.secretKey);

This works, but sometimes garbage collection is run and the buffers become 
invalid, and all I get is a stack dump and a crash that starts with the 
output:

    #
    # Fatal error in ../deps/v8/src/api.h, line 297
    # CHECK(allow_empty_handle || that != __null) failed
    #
    ==== Stack trace ============================================
    Security context: 0x2190c4706b71 <JS Object>#0#

Got a suggestion to store the buffer handle in a Local like so

Handle<Value> bind_crypto_box_keypair(const Arguments& args) {
    HandleScope scope;
    
    NEW_BUFFER_AND_PTR(pk, crypto_box_PUBLICKEYBYTES);
    NEW_BUFFER_AND_PTR(sk, crypto_box_SECRETKEYBYTES);
        
    if( crypto_box_keypair(pk_ptr, sk_ptr) == 0) {
        Local<Object> result = Object::New();
        
        // Make sure the key buffers are not garbage collected
        Local<Value> pkH = pk->handle_;
        Local<Value> skH = sk->handle_;
        
        result->Set(String::NewSymbol("publicKey"), pkH, DontDelete);
        result->Set(String::NewSymbol("secretKey"), skH, DontDelete);
        return scope.Close(result);
    }
    return scope.Close(Undefined());
}

But now I get the following compilation error:

../sodium.cc:865:22: error: no viable conversion from

      'v8::Persistent<v8::Object>' to 'Local<v8::Value>'

        Local<Value> skH = sk->handle_;

                     ^     ~~~~~~~~~~~

/Users/xx/.node-gyp/0.10.26/deps/v8/include/v8.h:269:26: note: candidate

      constructor (the implicit copy constructor) not viable: no known

      conversion from 'v8::Persistent<v8::Object>' to 'const

      v8::Local<v8::Value> &' for 1st argument

template <class T> class Local : public Handle<T> {

                         ^

/Users/xx/.node-gyp/0.10.26/deps/v8/include/v8.h:272:29: note: candidate

      template ignored: could not match 'Local' against 'Persistent'

  template <class S> inline Local(Local<S> that)

                            ^

/Users/xx/.node-gyp/0.10.26/deps/v8/include/v8.h:281:29: note: candidate

      template ignored: could not match 'S *' against

      'v8::Persistent<v8::Object>'

  template <class S> inline Local(S* that) : Handle<T>(that) { }


What am I doing wrong and what is the proper way to return buffers inside 
objects to javascript from a C extension?
Any help is very appreciated. I am stuck!

-- 
-- 
Job Board: http://jobs.nodejs.org/
Posting guidelines: 
https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en

--- 
You received this message because you are subscribed to the Google Groups 
"nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to