Native/javascript shared ArrayBuffer crash

Having problems with building or using CEF's C/C++ APIs? This forum is here to help. Please do not post bug reports or feature requests here.

Native/javascript shared ArrayBuffer crash

Postby sdiverdi » Fri Dec 25, 2020 7:58 pm

Hi, happy holidays! I'm new to CEF and having trouble sharing data between C++ and Javascript via an ArrayBuffer, would appreciate some help understanding what's wrong. I'm starting from the cefsimple example on osx / xcode, and have created a SimpleAppRenderer from SimpleApp to use as the app in the helper process. In SimpleAppRenderer I have:

Code: Select all
void SimpleAppRenderer::OnContextCreated(
    CefRefPtr<CefBrowser> browser,
    CefRefPtr<CefFrame> frame,
    CefRefPtr<CefV8Context> context) {
  CefRefPtr<CefV8Value> object = context->GetGlobal();

  int bufsize = 256 * 256 * 4;
  unsigned char* buffer = new unsigned char[bufsize];
  // fill buffer
  for(int i = 0; i < bufsize; ++i) {
    buffer[i] = rand() & 256;
  }
  buffer[0] = 'd';
  buffer[1] = 'e';
  buffer[2] = 'a';
  buffer[3] = 'd';
  arrbuf_ = CefV8Value::CreateArrayBuffer(buffer, bufsize, this);

  object->SetValue("arrbuf", arrbuf_, V8_PROPERTY_ATTRIBUTE_NONE);
}


My SimpleApp then loads a local index.html file containing:

Code: Select all
<html>
<head>
<script>
function myFunction() {
  var canvas = document.getElementById('image');
  var ctx = canvas.getContext('2d');
  var buf8 = new Uint8ClampedArray(window.arrbuf);
  console.log(String.fromCharCode(buf8[0], buf8[1], buf8[2], buf8[3]));
  var image = new ImageData(buf8, 256, 256);
  ctx.putImageData(image, 0, 0);
}
</script>
</head>
<body>
<div>Hello world!</div>
<div><button onclick="myFunction()">Click me</button></div>
<div><canvas id="image" width="256" height="256" /></div>
</body>
</html>


Pretty simple I hope! When I run this project, I see "dead" printed to the console as expected (I've also separately confirmed that javascript sees the correct byteLength for arrbuf), but when the ctx.putImageData line gets called, the helper process crashes and the browser window goes flat gray (I've also confirmed that if instead of window.arrbuf I create a new ArrayBuffer in myFunction and pass it to putImageData it works fine). If I attach a debugger first, I get EXC_BREAKPOINT triggered inside cef_execute_process in the helper process, but no more information than that (see xcode callstack in image).

callstack.png
callstack.png (911.34 KiB) Viewed 6388 times


What am I doing wrong here? Or how can I debug further? Thanks! -steve
sdiverdi
Mentor
 
Posts: 51
Joined: Fri Dec 25, 2020 7:41 pm

Re: Native/javascript shared ArrayBuffer crash

Postby magreenblatt » Fri Dec 25, 2020 11:07 pm

The putImageData method expects an array of pixel values. See the documentation at https://developer.mozilla.org/en-US/doc ... ith_canvas
magreenblatt
Site Admin
 
Posts: 12408
Joined: Fri May 29, 2009 6:57 pm

Re: Native/javascript shared ArrayBuffer crash

Postby sdiverdi » Sat Dec 26, 2020 2:31 pm

Hmm I've read that documentation but I'm not sure the distinction you're drawing. putImageData takes an ImageData which is constructed from a Uint8ClampedArray view of an ArrayBuffer, which is what I have. The ArrayBuffer is just bytes, so I don't understand what it means to be "pixel values" as opposed to some other bytes. But to verify, I tried this in my index.html:

Code: Select all
function myFunction() {
  var canvas = document.getElementById('image');
  var ctx = canvas.getContext('2d');
  var arrbuf = new ArrayBuffer(256 * 256 * 4);
  // var arrbuf = window.arrbuf;
  var buf8 = new Uint8ClampedArray(arrbuf);
  buf8.fill(255);
  console.log(arrbuf.byteLength);
  console.log(buf8[0], buf8[1], buf8[2], buf8[3]);
  var image = new ImageData(buf8, 256, 256);
  ctx.putImageData(image, 0, 0);
}


which works -- canvas is filled with a white square and I see printed to the console the byteLength 262144 and the first four byte values 255 255 255 255. If instead I change it to use the native ArrayBuffer like this:

Code: Select all
function myFunction() {
  var canvas = document.getElementById('image');
  var ctx = canvas.getContext('2d');
  //var arrbuf = new ArrayBuffer(256 * 256 * 4);
  var arrbuf = window.arrbuf;
  var buf8 = new Uint8ClampedArray(arrbuf);
  console.log(arrbuf.byteLength);
  console.log(buf8[0], buf8[1], buf8[2], buf8[3]);
  var image = new ImageData(buf8, 256, 256);
  ctx.putImageData(image, 0, 0);
}


and do the initialization of window.arrbuf in C++ like this:

Code: Select all
  int bufsize = 256 * 256 * 4;
  unsigned char* buffer = new unsigned char[bufsize];
  for(int i = 0; i < bufsize; ++i) {
    buffer[i] = 255;
  }
  arrbuf_ = CefV8Value::CreateArrayBuffer(buffer, bufsize, this);
  object->SetValue("arrbuf", arrbuf_, V8_PROPERTY_ATTRIBUTE_NONE);


I see the same things printed to the console, the byteLength 262144 and the first four bytes 255 255 255 255, but the helper app crashes. So it appears I have the same ArrayBuffer contents in each case, and I do the same javascript code to draw that ArrayBuffer into the canvas, but if the ArrayBuffer comes from the native side, it crashes.
sdiverdi
Mentor
 
Posts: 51
Joined: Fri Dec 25, 2020 7:41 pm

Re: Native/javascript shared ArrayBuffer crash

Postby magreenblatt » Sat Dec 26, 2020 8:09 pm

Sorry, I misread your original post. Can you iterate the complete array in JS? Are you getting the CefV8ArrayBufferReleaseCallback?
magreenblatt
Site Admin
 
Posts: 12408
Joined: Fri May 29, 2009 6:57 pm

Re: Native/javascript shared ArrayBuffer crash

Postby sdiverdi » Sat Dec 26, 2020 9:25 pm

No problem! Yes, I'm able to iterate the whole ArrayBuffer in my Javascript:

Code: Select all
  for (var i = 0; i < 256 * 256; ++i) {
    console.log(buf8[i*4+0], buf8[i*4+1], buf8[i*4+2], buf8[i*4+3]);
  }


prints out all the pixel values (all 255,255,255,255) successfully). I do register the callback, though I removed the delete statement in case I was misunderstanding the lifetime requirements:

Code: Select all
void SimpleAppRenderer::ReleaseBuffer(void* buffer) {
  fprintf(stderr, "****SimpleAppRenderer::ReleaseBuffer****");
//  delete [] (unsigned char*) buffer;
}


I have the print statement in there to confirm the callback doesn't get called -- it doesn't. Have to use print statements because I'm having trouble getting breakpoints to trigger.

Is there some way I can get more information about what is failing inside CEF? Since it's an EXC_BREAKPOINT I suspect it's some sort of an assert or something, might be helpful to diagnose.
sdiverdi
Mentor
 
Posts: 51
Joined: Fri Dec 25, 2020 7:41 pm

Re: Native/javascript shared ArrayBuffer crash

Postby magreenblatt » Sat Dec 26, 2020 10:52 pm

You can download symbols from the same place you downloaded the binary distribution. Extract the dDYM and place next to the “Chromium Embedded Framework” binary in the app bundle.
magreenblatt
Site Admin
 
Posts: 12408
Joined: Fri May 29, 2009 6:57 pm

Re: Native/javascript shared ArrayBuffer crash

Postby sdiverdi » Mon Dec 28, 2020 7:23 pm

Okay made some progress. Got the symbols and now have this callstack:

callstack.jpg
callstack.jpg (557.47 KiB) Viewed 6326 times


which points to this file and line:

https://source.chromium.org/chromium/ch ... er.cc;l=78

Code: Select all
DOMArrayBuffer* V8ArrayBuffer::ToImpl(v8::Local<v8::Object> object) {
  DCHECK(object->IsArrayBuffer());
  v8::Local<v8::ArrayBuffer> v8buffer = object.As<v8::ArrayBuffer>();
  // TODO(ahaas): The use of IsExternal is wrong here. Instead we should call
  // ToScriptWrappable(object)->ToImpl<ArrayBuffer>() and check for nullptr.
  // We can then also avoid the call to Externalize below.
  if (v8buffer->IsExternal()) {
    const WrapperTypeInfo* wrapper_type = ToWrapperTypeInfo(object);
    CHECK(wrapper_type);
    CHECK_EQ(wrapper_type->gin_embedder, gin::kEmbedderBlink);  // THIS LINE
    return ToScriptWrappable(object)->ToImpl<DOMArrayBuffer>();
  }


But I guess I don't really know what to do with this information. Will keep looking into it, but ideas appreciated.
sdiverdi
Mentor
 
Posts: 51
Joined: Fri Dec 25, 2020 7:41 pm

Re: Native/javascript shared ArrayBuffer crash

Postby ndesktop » Tue Dec 29, 2020 2:01 am

I'd start looking for issues similar with this.
Either the embedder field(s) remained zero for some reason - specifically gin_embedder - or, most likely, is kNativeGinEmbedder instead of kEmbedderBlink (I cannot say).
Try to see in debugger what value is wrapper_type->gin_embedder (other fields of wrapper type might be of help, too).
The reason I'm saying this is the fix for issue 1006600 above, the fix was this, which initializes all embedder fields to Smi::kZero. The wrapper type for v8 ArrayBuffer seems to be kEmbedderBlink.
ndesktop
Master
 
Posts: 756
Joined: Thu Dec 03, 2015 10:10 am

Re: Native/javascript shared ArrayBuffer crash

Postby sdiverdi » Tue Dec 29, 2020 3:24 pm

Ah, hmm, I see. I was hoping that this was an error in the way I was calling CEF because I was mis-understanding something about how it works. It seems instead this is a bug in CEF itself. This a quick experiment to evaluate CEF's appropriateness for something I'd like to build, so getting into debugging CEF is out of scope for me.

I will note that cef-project pulls this version of CEF: 81.2.24+gc0b313d+chromium-81.0.4044.113 but the latest available on https://cef-builds.spotifycdn.com/index.html is 87.1.12+g03f9336+chromium-87.0.4280.88 so it's possible the newer version will behave differently. I'll try.

However, from some of the digging I did, I found that the way CEF is calling v8:ArrayBuffer::New() is depcreated in V8. Here's are notes about the deprecation:

"v8::ArrayBuffer::New() without a BackingStore is deprecated in V8 8.0"
https://github.com/nodejs/node/issues/30529

"Issue 9908: Feedback for the new ArrayBuffer BackingStore API"
https://bugs.chromium.org/p/v8/issues/detail?id=9908

And here's where the deprecated version is called inside CEF:
https://bitbucket.org/chromiumembedded/ ... lines-1413

Since the change is to how ArrayBuffers are externalized, it may be that the deprecated functionality has been broken here.

Thanks again for the help, and happy new year!
sdiverdi
Mentor
 
Posts: 51
Joined: Fri Dec 25, 2020 7:41 pm

Re: Native/javascript shared ArrayBuffer crash

Postby sdiverdi » Thu Dec 31, 2020 2:38 pm

Just to close the loop, the problem persists in the latest stable libcef version from https://cef-builds.spotifycdn.com/index.html , 87.1.12+g03f9336+chromium-87.0.4280.88 .
sdiverdi
Mentor
 
Posts: 51
Joined: Fri Dec 25, 2020 7:41 pm

Next

Return to Support Forum

Who is online

Users browsing this forum: No registered users and 73 guests