TooTallNate / ref

Turn Buffer instances into "pointers"
http://tootallnate.github.com/ref
453 stars 141 forks source link

Void** deref -> Void* Sometimes provides Buffer of Length 0 #46

Closed sedouard closed 8 years ago

sedouard commented 8 years ago

Consider this tiny repro:

var ref = require('ref');

var types = {
  HKEY: ref.refType(ref.types.void)
}

types.PHKEY = ref.refType(types.HKEY);

var pHKey = ref.alloc(types.PHKEY);

console.log('pHKey length: ' + pHKey.length);
console.log('hKey length: ' + pHKey.deref().length);

This error doesn't seem OS specific. Run this repeatedly and see:

>node ./ref-test.js
pHKey length: 8
hKey length: 8
>node ./ref-test.js
pHKey length: 8
hKey length: 8

>node ./ref-test.js
pHKey length: 8
hKey length: 8

>node ./ref-test.js
pHKey length: 8
hKey length: 8

>node ./ref-test.js
pHKey length: 8
hKey length: 8

>node ./ref-test.js
pHKey length: 8
hKey length: 0 << I would expect void* to still have POINTER_SIZE length
sedouard commented 8 years ago

Debugging shows that after this cast the val pointer is NULL

TooTallNate commented 8 years ago

Which versions of node.js, node-ffi and which platform and architecture of your CPU please?

sedouard commented 8 years ago
sedouard commented 8 years ago

Sorry -- this is ref@1.2.0

TooTallNate commented 8 years ago

I can repro on node v0.12.7 on 64-bit OS X, but not node v4.2.1. Interesting…

TooTallNate commented 8 years ago

nvm, happens on v4.2.1 as well.

So this is actually expected behavior: what's happening is that pHKey buffer is allocated with uninitialized memory, meaning that it could contain any random bits of data. Sometimes that data is all 0s, which when dereferenced via pHKey.deref() causes a NULL pointer to be read, which ref forces to 0 byte length.

Closing as working as expected.

Is there a bit of C code that you're attempting to convert to ffi? I can help with that if you have a C snippet to show.

sedouard commented 8 years ago

Thanks @TooTallNate!

I thought that's what was happening from looking at the code -- but not what I would expect. The mistake I was making was thinking that ref.alloc(PHKEY) would allocate (but not necessarily initialize) the memory I needed.

I'm actually mocking out the the calls to the API and just trying to emulate what the native api is doing (we cant get to these APIs in our CI environment) which is just setting void\ pHKey to some arbitrary handle (in mocking I don't really care what this value is).

So from the 'Fake' native code (JS mocking code) I'm doing:

ref.writeUInt64LE(pHKey.deref(), 0, <some dummy pointer>)

I changed to ref.alloc(PHKEY, new Buffer(ref.sizeof.pointer)) and I think its working fine now.