Crash in CefResourceRequestJobCallback

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.

Crash in CefResourceRequestJobCallback

Postby sjaved » Wed Mar 07, 2018 5:06 am

Hi,
I am using CEF 3202 on Windows 10.
I am trying to load my own resources(html pages with separate js files) using CefResourceHandler. The problem is that at some point while loading those resources there is a crash, below is the call stack after the crash.
The crash is when job tries to get the status, where the request is not present, at this line
Code: Select all
if (job_->has_response_started() && job_->GetStatus().is_io_pending())
. I tried to change this line to
Code: Select all
if (!job_->is_done() && job_->has_response_started() && job_->GetStatus().is_io_pending())
which makes the things better. This was just a test, do someone have any idea if it is a bug? or something else is going wrong? any pointers towards the actual problem will be really appreciated.

Code: Select all
>   libcef.dll!net::URLRequestJob::GetStatus() Line 701   C++
    libcef.dll!CefResourceRequestJobCallback::ContinueOnIOThread() Line 105   C++
    libcef.dll!base::internal::FunctorTraits<void (__thiscall `anonymous namespace'::CefAuthCallbackImpl::*)(void),void>::Invoke<scoped_refptr<`anonymous namespace'::CefAuthCallbackImpl> const &>(void(`anonymous-namespace'::CefAuthCallbackImpl::*)() method, const scoped_refptr<`anonymous namespace'::CefAuthCallbackImpl> & receiver_ptr) Line 195   C++
    libcef.dll!base::internal::Invoker<base::internal::BindState<void (__thiscall CefResourceRequestJobCallback::*)(void),scoped_refptr<CefResourceRequestJobCallback> >,void __cdecl(void)>::RunImpl<void (__thiscall CefResourceRequestJobCallback::*const &)(void),std::tuple<scoped_refptr<CefResourceRequestJobCallback> > const &,0>(void(CefResourceRequestJobCallback::*)() & functor, const std::tuple<scoped_refptr<CefResourceRequestJobCallback> > & bound, std::integer_sequence<unsigned int,0> __formal) Line 349   C++
    libcef.dll!base::internal::Invoker<base::internal::BindState<void (__thiscall CefResourceRequestJobCallback::*)(void),scoped_refptr<CefResourceRequestJobCallback> >,void __cdecl(void)>::Run(base::internal::BindStateBase * base) Line 331   C++
    libcef.dll!base::debug::TaskAnnotator::RunTask(const char * queue_function, base::PendingTask * pending_task) Line 65   C++
    libcef.dll!base::MessageLoop::RunTask(base::PendingTask * pending_task) Line 407   C++
    libcef.dll!base::MessageLoop::DeferOrRunPendingTask(base::PendingTask pending_task) Line 426   C++
    libcef.dll!base::MessageLoop::DoWork() Line 524   C++
    libcef.dll!base::MessagePumpForIO::DoRunLoop() Line 483   C++
    libcef.dll!base::MessagePumpWin::Run(base::MessagePump::Delegate * delegate) Line 58   C++
    libcef.dll!base::MessageLoop::Run() Line 346   C++
    libcef.dll!base::Thread::Run(base::RunLoop * run_loop) Line 256   C++
    libcef.dll!content::BrowserThreadImpl::IOThreadRun(base::RunLoop * run_loop) Line 279   C++
    libcef.dll!content::BrowserThreadImpl::Run(base::RunLoop * run_loop) Line 313   C++
    libcef.dll!base::Thread::ThreadMain() Line 341   C++
    libcef.dll!base::`anonymous namespace'::ThreadFunc(void * params) Line 91   C++
    [External Code]   


Thanks in advance!!
Best Regards,
sjaved
Techie
 
Posts: 15
Joined: Wed Jun 15, 2016 3:47 am

Re: Crash in CefResourceRequestJobCallback

Postby amaitland » Wed Mar 07, 2018 6:45 am

Does the problem reproduce in 3282? I've not experienced any problems when using CefResourceHandler.
Maintainer of the CefSharp project.
amaitland
Virtuoso
 
Posts: 1292
Joined: Wed Jan 14, 2015 2:35 am

Re: Crash in CefResourceRequestJobCallback

Postby sjaved » Wed Mar 07, 2018 8:03 am

No i have not tired 3282, i will give it a try.
Any other pointers to resolve the existing problem?
sjaved
Techie
 
Posts: 15
Joined: Wed Jun 15, 2016 3:47 am

Re: Crash in CefResourceRequestJobCallback

Postby amaitland » Wed Mar 07, 2018 5:19 pm

Post an example of your code, we're just guessing otherwise.
Maintainer of the CefSharp project.
amaitland
Virtuoso
 
Posts: 1292
Joined: Wed Jan 14, 2015 2:35 am

Re: Crash in CefResourceRequestJobCallback

Postby sjaved » Thu Mar 08, 2018 3:46 am

Below you can find the logic inside resource handler, which (atleast to me) seems quite simple.
Code: Select all
// My resource handler
bool MyResourceHandler::ProcessRequest(CefRefPtr<CefRequest> request,
    CefRefPtr<CefCallback> callback)
{
   // resource files are loaded here from some provided path(specific uri from network)
   // continue if loaded properly
   // stop if not loaded
}


void MyResourceHandler::GetResponseHeaders(CefRefPtr<CefResponse> response,
    int64& response_length, CefString& redirectUrl) {
   // set response headers
   // set response length
}

bool MyResourceHandler::ReadResponse(void* data_out, int bytes_to_read,
    int& bytes_read, CefRefPtr<CefCallback> callback){
   // memcpy data chunks depending on the bytes_to_read and keep the offset
   // continue callback if offset has not reached to the end
   // otherwise return false and stop
}


somewhere in between this loading there is a crash at the mentioned location in my previous comment. Problem is that some of the resources are loaded properly, and it crashes in between. The same resource files work fine with chrome.
What I am not able to understand is that why request goes to null, or is cleaned up before the resource request job is finished? Any Ideas?
Code: Select all
// this is the location where crash happens, because request is null.
// chromium/src/net/url_request/url_request_job.cc
const URLRequestStatus URLRequestJob::GetStatus() {
  return request_->status();
}
sjaved
Techie
 
Posts: 15
Joined: Wed Jun 15, 2016 3:47 am

Re: Crash in CefResourceRequestJobCallback

Postby amaitland » Thu Mar 08, 2018 5:32 am

Comments saying what your doing don't give any clues
Maintainer of the CefSharp project.
amaitland
Virtuoso
 
Posts: 1292
Joined: Wed Jan 14, 2015 2:35 am

Re: Crash in CefResourceRequestJobCallback

Postby sjaved » Fri Mar 09, 2018 4:14 am

Hi I am adding the actual code. It is communicating with Java so you can see some JNI Code.
Code: Select all
bool MyResourceHandler::ProcessRequest(CefRefPtr<CefRequest> request,
    CefRefPtr<CefCallback> callback)
{

    bool handled = false;
   
    string url = request->GetURL();
    string queryMethod = request->GetMethod();
    string queryContentType = "";
    CefRefPtr<CefPostData> postData = request->GetPostData();

    // Header Map
    CefRequest::HeaderMap headerMap;
    request->GetHeaderMap(headerMap);

    JNIEnv* env = mCefBrowserAdapter.getJNIEnv();
    string logIDs = retrieveLOGIDS(env);

 
    if (env) {
        // In this part, we treat  MapHeaders
        jobjectArray headerMapArray = NULL;

        if (headerMap.size() > 0) {
            CefRequest::HeaderMap::const_iterator it = headerMap.begin();
            jsize size = (jsize) (2*headerMap.size());
            headerMapArray =
                env->NewObjectArray(size,
                env->FindClass("java/lang/String"),
                0);

            int j = 0;
            for (; it != headerMap.end(); ++it) {
                string key = (*it).first;
                env->SetObjectArrayElement(headerMapArray, j,
                    env->NewStringUTF(key.c_str()));

                j++;
                string value = (*it).second;
                env->SetObjectArrayElement(headerMapArray, j,
                    env->NewStringUTF(value.c_str()));

                j++;
                if(key.compare("Content-type") == 0 ||
                    key.compare("Content-Type") == 0)
                    queryContentType = value;
            }
        }

        // In this part, we treat PostData
        jbyteArray byteArrayPostData = env->NewByteArray(0);
        jsize dataSize = 0;
        if( postData.get() ){
            CefPostData::ElementVector elements;
            postData->GetElements(elements);
            if (elements.size() > 0) {
                CefRefPtr<CefPostDataElement> element;
                CefPostData::ElementVector::const_iterator it = elements.begin();
                for (; it != elements.end(); ++it) {
                    element = (*it);
                    if (element->GetType() == PDE_TYPE_BYTES) { // the element is composed of bytes
                        size_t size = element->GetBytesCount();
                        if(size == 0) {
                            //Empty
                        }else {
                            // Retrieve the data.
                            jbyte* bytes = new jbyte[size];
                            element->GetBytes(size, bytes);
                            jbyte* tempBytes = env->GetByteArrayElements(byteArrayPostData, false);
                            byteArrayPostData = env->NewByteArray(dataSize + size);
                            if(tempBytes)
                                env->SetByteArrayRegion(byteArrayPostData, 0, dataSize, tempBytes);
                            env->SetByteArrayRegion(byteArrayPostData, dataSize, size, bytes);
                            dataSize += size;
                            delete [] bytes;
                        }
                    } else if (element->GetType() == PDE_TYPE_FILE) {
                        //get file
                        string content = "";
                        string filename = std::string(element->GetFile());
                        ifstream file(filename.c_str(), ios::in); // declaration of the flow and open the file
                        if (file) {
                            string line;
                            while (getline(file, line)) {
                                content.append(line);
                            }
                            jbyte* tempBytes = env->GetByteArrayElements(byteArrayPostData, false);
                            byteArrayPostData = env->NewByteArray(dataSize + content.size());
                            if(tempBytes)
                                env->SetByteArrayRegion(byteArrayPostData, 0, dataSize, tempBytes);
                            env->SetByteArrayRegion(byteArrayPostData, dataSize, content.size(), (jbyte*)content.c_str());
                            dataSize += content.size();
                            file.close();
                        } else {
                            cerr << "Unable to open file " << filename << endl;
                        }
                    }
                }
            }
        }

        jstring jurl = env->NewStringUTF(url.c_str());
        jstring jqueryMethod = env->NewStringUTF(queryMethod.c_str());
        jstring jqueryContentType = env->NewStringUTF(queryContentType.c_str());

        jobject newTranscation = mCefBrowserAdapter.newTransaction(jurl, jqueryMethod, jqueryContentType, byteArrayPostData, headerMapArray);
        jobjectArray resultArray = (jobjectArray)mCefBrowserAdapter.processTransaction(newTranscation);
        jsize resultSize = 0;


        if( resultArray != NULL) {
            resultSize = env->GetArrayLength(resultArray);
         jstring replyContentType = (jstring)env->GetObjectArrayElement(resultArray, 0);
            jbyteArray byteArray = (jbyteArray)env->GetObjectArrayElement(resultArray, 1);

            int replyStatus = CrowJavaBridge::instance()->getObjectValueInteger(env->GetObjectArrayElement(resultArray, 2));


            jobjectArray replyHeaders = (jobjectArray)env->GetObjectArrayElement(resultArray, 3);

            data_ = "";
            // In this part, I just put the data in the good format
            if( replyContentType != NULL || byteArray != NULL){
                content_type_ = env->GetStringUTFChars(replyContentType, NULL);
                jsize n = env->GetArrayLength(byteArray);
     
                jboolean isACopy = JNI_FALSE;
                jbyte* buf = (jbyte*) env->GetPrimitiveArrayCritical(byteArray, &isACopy);
   

                int number_of_elements_in_header = env->GetArrayLength(replyHeaders);
                number_of_headers_ = number_of_elements_in_header/2;

              //Log Filtering
                if (containsLOGID(logIDs,45))
                {
                   stringstream ss;
                   ss<<number_of_headers_;
                }

                reply_headers_ = new string[number_of_headers_];

                string tempHeaderElement;

                int j=0;

                for (int i=0; i<number_of_elements_in_header; i++)
                {
                   jstring aHeader = (jstring) env->GetObjectArrayElement(replyHeaders,i);

                   if(!aHeader)
                   {
                      char *tempBuffer = (char*)malloc(1);
                      strcpy(tempBuffer, "");
                      jstring jstrBuffer = env->NewStringUTF(tempBuffer);

                       const char * charHeader = env->GetStringUTFChars(jstrBuffer, 0);

                       if ( i%2 == 1 && i != 0)
                       {
                          tempHeaderElement.append(":");
                   }

                       tempHeaderElement.append(charHeader);
                   }
                   else
                   {
                      const char * charHeader = env->GetStringUTFChars(aHeader, 0);

                      if ( i%2 == 1 && i != 0)
                  {
                     tempHeaderElement.append(":");
                  }
                  tempHeaderElement.append(charHeader);
                   }

                   if ( i%2 == 1 && i != 0 )
                   {
                      reply_headers_[j].append(tempHeaderElement);
                      tempHeaderElement.clear();
                      j++;
               }

   
            }


                unsigned char* temp_bytes_ = new unsigned char[n];
                memcpy(temp_bytes_, buf, n);
                data_ = string(reinterpret_cast<const char*>(temp_bytes_), n);
                delete [] temp_bytes_;
                env->ReleasePrimitiveArrayCritical(byteArray, buf, JNI_OK);




                status_= replyStatus;
                handled = true;
            } else {
                content_type_ = "text/html";
                data_= "Unable to process transaction";
                status_ = 404;
                handled = true;
            }
        }

    }

    if (handled) {
        callback->Continue();

        return true;
    }

    return false;
}

void MyResourceHandler::GetResponseHeaders(CefRefPtr<CefResponse> response,
    int64& response_length, CefString& redirectUrl) {

      int i = 0;
      string key;
      string value;

      CefResponse::HeaderMap headerMap;

      if (content_type_.compare("") != 0) {
            response->SetMimeType(content_type_);
        } else {
            //log error
        }

      string tempKey;
      string tempValue;

      CefString cefKey;
      CefString cefValue;

      while (i<number_of_headers_)
      {

         int colonPosition = reply_headers_[i].find(":");

            tempKey = reply_headers_[i].substr(0, colonPosition);

            int tempLength = reply_headers_[i].length();

            if (tempLength == colonPosition)
            {
               tempValue = "";
            }
            else
            {
               tempValue = reply_headers_[i].substr(colonPosition+1);
            }

         cefKey.FromString(tempKey);
         cefValue.FromString(tempValue);

            JNIEnv *env = Logger::instance()->getJNIEnv();
         string logIDs = retrieveLOGIDS(env);

      
         headerMap.insert(pair<CefString, CefString>(cefKey,cefValue));

         i++;

           //releasejni
           Logger::instance()->releaseJNIEnv();
      }

      response->SetHeaderMap(headerMap);

      response->SetStatus(status_);
        // Set the resulting response length
        response_length = data_.length();
}


bool MyResourceHandler::ReadResponse(void* data_out,
    int bytes_to_read, int& bytes_read, CefRefPtr<CefCallback> callback)
{
   bool has_data = false;
    bytes_read = 0;

    if (offset_ < data_.length()) {
        // Copy the next block of data into the buffer.
        int transfer_size = min<int>(bytes_to_read, static_cast<int>(data_.length() - offset_));
        memcpy(data_out, data_.c_str() + offset_, transfer_size);
        offset_ += transfer_size;

        bytes_read = transfer_size;
        has_data = true;
    }

    if (has_data) {
        callback->Continue();
        return true;
    }
    return has_data;
}
sjaved
Techie
 
Posts: 15
Joined: Wed Jun 15, 2016 3:47 am

Re: Crash in CefResourceRequestJobCallback

Postby ndesktop » Fri Mar 09, 2018 9:01 am

Maybe request and/or job_ are nullptr?
ndesktop
Master
 
Posts: 756
Joined: Thu Dec 03, 2015 10:10 am

Re: Crash in CefResourceRequestJobCallback

Postby sjaved » Fri Mar 09, 2018 9:31 am

request is a nullptr, job_ is not.
If control is at this location
Code: Select all
if (job_->has_response_started() && job_->GetStatus().is_io_pending())
this means that job_ is valid and also bytes are available(they are checked before reaching to this point inside ContinueOnIOThread()), then how come request is nullptr, while job_ is still existing :?:
sjaved
Techie
 
Posts: 15
Joined: Wed Jun 15, 2016 3:47 am

Re: Crash in CefResourceRequestJobCallback

Postby ndesktop » Mon Mar 12, 2018 2:35 am

I was thinking that crash may occur on
Code: Select all
CefRefPtr<CefPostData> postData = request->GetPostData();

Why request can be nullptr while job is not nullptr? I don't remember the internals now, but I think the lifetime of a job is controller from another place (request is only using a job but not own it).
Probably Marshall ro Czarek can explain better than me the inners. (I might also be wrong).
ndesktop
Master
 
Posts: 756
Joined: Thu Dec 03, 2015 10:10 am

Next

Return to Support Forum

Who is online

Users browsing this forum: No registered users and 85 guests