hxcpp icon indicating copy to clipboard operation
hxcpp copied to clipboard

NativeArray.address, constRaw and empty Bytes being internally changed

Open grepsuzette opened this issue 3 years ago • 0 comments

Consider this snippet (Haxe 4.1.3 and 4.1.4):

class T {
    public static function main() {
        var a = haxe.io.Bytes.ofString("");
        var b = haxe.io.Bytes.ofString("");
        trace( 'Lengths: ${a.length} VS ${b.length}' ); // Lengths 0 VS 0
        trace( a.compare(b) );  // 0: identical

        // now after this single line
        var foo = cpp.NativeArray.address(a.getData(), 0).constRaw;
        trace( 'Lengths: ${a.length} VS ${b.length}' ); // Lengths 0 VS 0
        trace( a.compare(b) );  // 1: different
    }
}

I'm not sure if the above is the correct way to get a constRaw, if not please tell me. But I think above behavior can create issues.

It seems to happen because the a variable when inspected with a debugger, internally gets through those 2 states:

  1. length=0, mAlloc=0, mBase=0x00
  2. length=1, mAlloc=56, mBase=0x7ffff024a262

Even though on the surface, the Bytes object still gives a.length == 0.

Here what I think happens from tracking this with gdb:

At one point, it gets into (hxcpp/4,1,15/include/cpp/Pointer.h): inline static AutoCast arrayElem(::Array<T> array, int inIndex) { return AutoCast(&array[inIndex]); }

which eventually calls (in hxcpp/4,1,15/include/Array.h):

inline ELEM_ &Item(int inIndex)
   {
      if (inIndex>=(int)length) EnsureSize(inIndex+1);
      else if (inIndex<0) { return * hx::NewNull<ELEM_>(); }
      return * (ELEM_ *)(mBase + inIndex*sizeof(ELEM_));
   }

And the EnsureSize() methods IIUC sets a length of 1, and allocates 64-8 = 56 bytes.

Seems it is enforcing a minimal size of 1 for a certain reason, and then memory alignment rules gives this 56 bytes value and the memcmp() used by Bytes.compare() on cpp target then compares a buffer of 0 vs a buffer of 56 bytes, returning 1 (or -1) instead of 0.

From a purely pragmatic point of view, I need a const unsigned char*, passed from a Bytes that should be allowed to have 0 elements.

I will wait for some feedback on this, as the internals of hxcpp are a bit difficult for me ;). Edit: maybe we can just use the following simple fix?

grepsuzette avatar Nov 08 '20 17:11 grepsuzette