Skip to content

CefRequest.setURL("") and reading back a malformed URL crash the Debug/coverage build (CEF's own CHECK/NOTREACHED) #21

Description

@Thrameos

Summary

Same class of issue as #20, found in the same bad-path test-writing round. Two distinct crash signatures, both Debug/coverage-build-only (confirmed neither reproduces in Release):

  1. CefRequest.setURL("") (empty string):
FATAL:.../libcef_dll/ctocpp/request_ctocpp.cc:75] Check failed: !url.empty().
  1. Calling .toString() (which internally reads back the URL) on a CefRequest whose URL was set to a genuinely unparseable string (e.g. "://missing-scheme"):
FATAL:url/gurl.cc:159] NOTREACHED hit. Trying to get the spec of an invalid URL!

setURL() itself accepts malformed-but-non-empty strings fine (confirmed via isolated testing that "not a valid url at all", "http://", and "://missing-scheme" all pass through setURL() without crashing) -- it's specifically reading the URL back afterward (getURL()/toString()) that hits the GURL::spec() NOTREACHED for a URL that never successfully parsed.

request_ctocpp.cc is auto-generated by CEF's own build (from include/cef_request.h via tools/make_ctocpp_impl.py, not checked into the chromiumembedded/cef source repo as a static file), so the exact generated CHECK logic wasn't directly inspectable -- confirmed only empirically via isolated test runs.

Repro

Added to java/tests/junittests/MalformedInputEdgeCaseTest.java (the empty-URL case is @Disabled with a link to this issue -- remove @Disabled to re-run it, under the ENABLE_COVERAGE/Debug build specifically):

CefRequest request = CefRequest.create();
request.setURL("");  // crashes in Debug only: Check failed: !url.empty()

The three malformed-but-non-empty-string cases (requestSetURLWithNoSchemeStringDoesNotThrow/WithSchemeOnlyStringDoesNotThrow/WithMissingSchemeColonStringDoesNotThrow) are kept enabled -- confirmed safe as long as nothing calls .toString()/getURL() on the request afterward. The .toString()-after-malformed-setURL() crash itself isn't currently captured as a standalone reproducer test (the version of this test that did that was rewritten to avoid it once isolated as the cause) -- worth adding a dedicated @Disabled test for that specific combination if this issue is picked up.

Impact

Same as #20: both crashed early enough in the process to prevent CoverageTestHelper.flush() from running, losing an entire coverage-measurement run's .gcda data each time (0 files written both times this was hit).

Fix sketch (not implemented here)

For the empty-URL case: validate in native/CefRequest_N.cpp's N_SetURL that the string is non-empty before calling into CEF. For the malformed-URL-then-read-back case: less clear what the "right" JCEF-side fix is, since setURL() itself succeeding with a malformed value is arguably already the questionable part -- may need either upstream CEF discussion or a JCEF-side URL-validity check before accepting a setURL() call at all.

Found via

This fork's coverage-expansion effort (tracked in #5), same bad-path test-writing round as #20 -- specifically while re-running Track B's ENABLE_COVERAGE Debug-build measurement with this session's newly-added tests included, immediately after fixing #20.

Activity

  1. Thrameos commented on Aug 29, 2026

    @Thrameos
    OwnerAuthor

    Found a second, identically-rooted reproduction while continuing coverage work: CefRequest.setURL(null) (not just setURL("")) hits the same CHECK(!url.empty()) in request_ctocpp.cc, because native/CefRequest_N.cpp's N_SetURL marshals a null jstring to an empty CefString() with no guard -- same code path as the empty-string case, just reached via null. Debug/coverage-build-only, confirmed via isolated repro. Test added as NullParameterEdgeCaseTest.requestSetURLWithNullDoesNotThrow(), @Disabled pending the same fix.

  2. Thrameos commented on Aug 29, 2026

    @Thrameos
    OwnerAuthor

    Third reproduction of the same root cause: CefRequest.set(null, method, postData, headerMap) (null url argument) also hits CHECK(!url.empty()) via CefRequest::Set(). Disabled as NullParameterEdgeCaseTest.requestSetAcceptsAllNullArguments().

  3. Thrameos commented on Aug 30, 2026

    @Thrameos
    OwnerAuthor

    Fourth reproduction, same class of bug but a different setter: CefRequest.setMethod(null) hits CHECK(!method.empty()) in request_ctocpp.cc via CefRequest::SetMethod(). Same root pattern as the others in this issue -- native/CefRequest_N.cpp's setters marshal a null jstring straight to an empty CefString() with no guard, and several of CEF's own setters CHECK their string argument is non-empty. Worth considering a single fix that guards all of CefRequest_N.cpp's string setters against null/empty where CEF's own API requires non-empty, rather than patching one call site at a time. Disabled as NullParameterEdgeCaseTest.requestSetMethodWithNullDoesNotThrow().

  4. Thrameos commented on Aug 30, 2026

    @Thrameos
    OwnerAuthor

    Sixth reproduction, same pattern but a different value type: CefPostDataElement.setToFile(null) hits CHECK(!fileName.empty()) via CefPostDataElement::SetToFile(). At this point the pattern is clearly systemic, not isolated to CefRequest: at least 6 confirmed call sites across CefRequest_N.cpp and CefPostDataElement_N.cpp marshal a null/empty jstring straight to an empty CefString() with no guard, and CEF's own bundled binary CHECKs non-empty on several of those parameters (url, method, header name, file path). Recommend a single fix pass across both _N.cpp files' string setters (guard-and-no-op on null/empty where CEF requires non-empty) rather than patching call sites one at a time -- filing/triaging each individually is producing a lot of near-duplicate issues (#19, #20, #21) for what looks like one root cause. Disabled as NullParameterEdgeCaseTest.postDataElementSetToFileAcceptsNull().

  5. Thrameos commented on Aug 30, 2026

    @Thrameos
    OwnerAuthor

    Seventh reproduction, on CefResponse this time: CefResponse.setHeaderByName(null, "value", true) hits CHECK(!name.empty()) in response_ctocpp.cc via CefResponse::SetHeaderByName(). Confirms this isn't CefRequest/CefPostDataElement-specific -- CefResponse_N.cpp has the identical unguarded-null pattern. Disabled as NullParameterEdgeCaseTest.responseSetHeaderByNameWithNullNameDoesNotThrow().

  6. Thrameos commented on Aug 31, 2026

    @Thrameos
    OwnerAuthor

    Fixed the empty-URL half of this issue (the setURL("") CHECK(!url.empty()) crash). native/CefRequest_N.cpp's N_SetURL now rejects an empty URL before calling into CEF (no-op instead of crashing).

    The second crash signature described here (NOTREACHED in gurl.cc when reading back a URL that was successfully setURL()'d with a malformed-but-non-empty string, e.g. "://missing-scheme") is NOT addressed by this fix and remains open -- as the issue notes, setURL() itself accepting such strings is arguably already the questionable part, and the right JCEF-side fix isn't clear-cut. Leaving this issue open to track that remaining half; happy to split it into a separate issue if preferred.

    Un-disabled requestSetURLWithEmptyStringDoesNotThrow in MalformedInputEdgeCaseTest.java. Verified passing in a full-suite run (156/156 tests, 0 failures).

  7. added a commit that references this issue on Aug 31, 2026
  8. Thrameos commented on Sep 1, 2026

    @Thrameos
    OwnerAuthor

    Partial progress, not closing (part 2 below is still open).

    Part 1 (CefRequest.setURL("") empty-string CHECK(!url.empty())) was already fixed in an earlier session (N_SetURL's empty-string guard predates this comment).

    This session (commit 92aed53) extended the identical guard pattern to the other call sites in the same bug class that had never been individually addressed: CefRequest.setMethod(), CefRequest.set() (both its url and method params), CefResponse.setHeaderByName(), and CefPostDataElement.setToFile() (filed separately as #28, now closed). All 6 of NullParameterEdgeCaseTest's previously-@Disabled tests covering this are now re-enabled and passing.

    Part 2 is still open and untouched: reading back a URL that was set to a malformed-but-non-empty string (e.g. "://missing-scheme") still hits GURL::spec()'s NOTREACHED on getURL()/toString(). Nothing in today's work addresses this — it needs either a JCEF-side URL-validity check before accepting setURL(), or upstream CEF discussion, per this issue's own "Fix sketch" section.

  9. added 4 commits that reference this issue on Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions