CefProcessMessage requires copy or becomes invalid

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.

CefProcessMessage requires copy or becomes invalid

Postby sketch34 » Mon Jul 19, 2021 4:20 am

Note: I'm using CEF version 75.1.4+g4210896+chromium-75.0.3770.100 because I need hardware accelerated OSR.

I've noticed some behavior I don't quite understand. If I attempt to hold a pointer to CefRefPtr<CefProcessMessage> or a CefRefPtr<CefDictionaryValue> etc. it contains, then access the pointer later, the message or value seems to be invalid.

Some code probably makes it clearer, simplified for brevity. See code comments below:

Code: Select all
bool MyClient::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefProcessId source_process, CefRefPtr<CefProcessMessage> message)
{
    CEF_REQUIRE_UI_THREAD();
    CEF_ML_SCOPED_LOCK(_mutex);
    Q_ASSERT(browser);

    auto* h = getMyProcHandler();
    Q_ASSERT(message->IsValid());
    Q_ASSERT(frame->IsValid());

    // TODO: For some reason, if we pass the original message CefRefPtr<CefProcessMessage> we get a crash
    // when calling GetString() on the message.
    // The message becomes invalid on my main thread even though all ref-counting is correctly applied
    // during closure capture. Manually calling AddRef() made no difference. Suspect a bug in CEF, since
    // CefProcessMessage claims to be thread-safe.

    auto msgCopy = message->Copy();   // *** NOTE: Copy() ***

    my::utils::dispatchToMyMainThread([=]() {
        REQUIRE_MY_MAIN_THREAD();
        Q_ASSERT(msgCopy->IsValid());   // This is false if we pass original message instead of a copy.
        Q_ASSERT(frame->IsValid());
        h->onProcessMessageReceived(browser, frame, source_process, msgCopy);
    });
   
    return true;
}


Since CefProcessMessage is thread safe and both threads are in the browser process, I would expect to not have to make a copy.
Why does the Copy() work and not the original CefProcessMessage?
sketch34
Techie
 
Posts: 11
Joined: Sun Apr 25, 2021 8:24 pm

Re: CefProcessMessage requires copy or becomes invalid

Postby ndesktop » Mon Jul 19, 2021 4:49 am

Most likely because dispatchToMyMainThread does what it says - runs on another thread - and the CefRefPtr you are holding is valid only on the function scope. It looks like a problem of lifetime, not thread safety.

If you do not make a copy you may try to store the CefRefPtr inside of MyClient in some map[cookie] = CefRefPtr and pass the cookie to the dispatchToMyMainThread, which in turn pops the CefRefPtr from the map and processes it (although it does not make much sense since you want to process the message and forget about it).
ndesktop
Master
 
Posts: 750
Joined: Thu Dec 03, 2015 10:10 am

Re: CefProcessMessage requires copy or becomes invalid

Postby magreenblatt » Mon Jul 19, 2021 9:22 am

Read the OnProcessMessageReceived documentation for your CEF version. I believe Copy() is required in that version.
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: CefProcessMessage requires copy or becomes invalid

Postby sketch34 » Mon Jul 19, 2021 8:29 pm

Bingo, thanks. I had a look at the comment in the header for my version:

// Do not keep a reference to or attempt to access the message outside of this callback.


Copy() it is :)

Does Copy() do a deep or shallow copy on the message? It seems like need to also Copy() items within the arguments list?
sketch34
Techie
 
Posts: 11
Joined: Sun Apr 25, 2021 8:24 pm

Re: CefProcessMessage requires copy or becomes invalid

Postby magreenblatt » Mon Jul 19, 2021 9:09 pm

It should be a deep copy.
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: CefProcessMessage requires copy or becomes invalid

Postby sketch34 » Mon Jul 19, 2021 11:14 pm

Okay I think I see what is happening, there is still a little gotcha tucked in here.

Code: Select all
// Inside OnProcessMessageReceieved(..., CefRefPtr<CefProcessMessage> msg)
CefRefPtr<CefProcessMessage> msgCopy = msg->Copy();

util::runOnMyMainThread([=]()
{
    CefRefPtr<CefDictionaryValue> dict = msgCopy->GetArgumentList()->GetDictionary(0);
    someObject->setDictionary(dict); // Dictionary becomes invalid when message msgCopy is released.
});


To fix this you must either:
a) dict->Copy(true); // or pass false.
b) Hold the msgCopy and access data through it.

It seems like when a CefRefPtr<CefProcessMessage> is released it will release all values it contains even if the values themselves have valid CefRefPtr to them.

Reminder to people this is CEF v75, things may have changed.
sketch34
Techie
 
Posts: 11
Joined: Sun Apr 25, 2021 8:24 pm


Return to Support Forum

Who is online

Users browsing this forum: Google [Bot] and 28 guests