Open
Conversation
Replace the manually maintained SOURCES list with glob-tree-ex to auto-discover test .cpp files, matching the CMakeLists.txt approach. Files needing special flags (doc_grammar.cpp, doc_3_urls.cpp, example/) are excluded from the glob and handled by explicit run statements.
|
An automated preview of the documentation is available at https://982.url.prtest2.cppalliance.org/index.html If more commits are pushed to the pull request, the docs will rebuild at the same URL. 2026-03-02 19:45:25 UTC |
|
GCOVR code coverage report https://982.url.prtest2.cppalliance.org/gcovr/index.html Build time: 2026-03-02 19:57:08 UTC |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
BOOST_ASSERTpreconditions on internal APIs, non-owning view types, and raw pointer parsing routines).Summary
v1 (Feb 2, 2026)
v2 (Feb 17, 2026)
All Fixes (18 commits)
f0a80adaf227d461c8962bcd76d8fc51e83f4f723e217c954f1d59ab1c6e27dce4755d1f179140c22bcd7bcecccd304da80148a7a70b0e49c935b72422153cFinding Details
Per-finding triage with a verdict and a rationale for each individual finding.
CRITICAL (4 findings)
C1. Buffer overflow in format_args.cpp string formatting
src/detail/format_args.cpp:196char*fromctx.out()assuming sufficient capacity.C2. Buffer overflow in format_args.cpp integer formatting
src/detail/format_args.cpp:510C3. Buffer overflow in format_args.cpp unsigned integer formatting
src/detail/format_args.cpp:613C4. Out-of-bounds read in url_base.cpp loop condition
include/boost/url/impl/url_base.hpp:248,2092,2616*itbefore checkingit != end. Three instances.af227d4, "fix: url_base loop condition order"): Reordered conditions towhile (it != end && *it != '/').HIGH (185 v1 + 9 v2 = 194 findings)
Confirmed bugs fixed (12 fixes)
Format center-alignment padding heap overflow
src/detail/format_args.cpp:190lpad = w / 2used total width instead of padding amount, solpad + rpad > pad, causing writes past the pre-measured buffer.217c954, "fix: format center-alignment padding"): Changed tolpad = pad / 2.decode_view::ends_with infinite loop on empty string
src/decode_view.cpp:106-124sis empty,s.size()is 0, decrementing iterators andn - 1wraps around causing infinite loop/UB.f1d59ab, "fix: decode_view::ends_with with empty string"): Addedif(s.empty()) return true;early return.Stale n.path after colon-encoding in pattern.cpp
src/detail/pattern.cpp:268-291diff),n.pathwas not updated. The subsequent//prefix check used the stale value formemmove.1c6e27d, "fix: stale pattern n.path after colon-encoding"): Addedn.path += diff;after the colon-encoding block.ci_is_less OOB read on mismatched-length strings
src/grammar/ci_string.cpp:58-74s0.size()as bound but read from both strings. Whens0.size() > s1.size(), OOB read on s1. Also returned false (equal) when s0 is a proper prefix of s1. Unlikeci_is_equal, the publicci_is_less()does NOT check sizes before calling detail.ce4755d, "fix: ci_is_less OOB read"): Usemin(s0.size(), s1.size())as loop bound, fall through to size comparison.recycled_ptr copy assignment self-assignment UAF
include/boost/url/grammar/impl/recycled.hpp:1851f17914, "fix: recycled_ptr copy self-assignment"): Addedif(this == &other) return *this;guard.Signed integer overflow: LLONG_MIN negation (3 findings)
src/detail/format_args.cpp:367,src/detail/format_args.cpp:453,src/detail/format_args.cpp:51961c8962, "fix: LLONG_MIN negation UB in format"): Replaced with unsigned arithmetic throughout.ci_less::operator() incorrect return type
include/boost/url/grammar/ci_string.hpp:333std::size_tinstead ofbool.bcd76d8, "fix: ci_less::operator() return type"): Changed return type tobool.segments_base front()/back() incorrect noexcept
include/boost/url/segments_base.hpp:250front()andback()markednoexceptbut can throw.fc51e83, "fix: incorrect noexcept in segments_base::front() and back()"): Removed incorrectnoexcept.recycled_ptr::get() null dereference
include/boost/url/grammar/recycled.hpp:452get()dereferencedp_without null check.f4f723e, "fix: recycled_ptr::get() nullptr when empty"): Added null check to return nullptr when empty.Pointer arithmetic UB in encode() for small buffers
include/boost/url/impl/encode.hppf0a80ad, "fix: encode() UB pointer arithmetic for small buffers"): Avoid UB pointer arithmetic.False positives (v2)
Data race on recycled_ptr refcount
include/boost/url/grammar/recycled.hpp:97-102refsISstd::atomic<std::size_t>when threads enabled (BOOST_URL_DISABLE_THREADSguard). Same issue as v1 Theme 5.decode() output buffer insufficient
include/boost/url/detail/decode.hppdecode_unsafechecksdest == endat line 90 and returns early. Truncation is documented behavior.Theme: BOOST_ASSERT as sole bounds check (29 findings, v1)
TRIAGE: BY DESIGN. Internal
_unsafefunctions and detail routines. The public API validates all inputs before calling them. The_unsafesuffix explicitly signals the precondition contract. Adding redundant runtime checks would duplicate validation already performed at the public API boundary. Standard Boost/STL design pattern (cf.std::vector::operator[]vsat()).detail/encode.hpp:58%+ two hex digitsdetail/encode.hpp:77detail/encode.hpp:90detail/encode.hpp:121detail/segments_range.hpp:82detail/url_impl.hpp:110detail/normalize.cpp:318detail/normalize.cpp:362detail/over_allocator.hpp:95detail/params_iter_impl.cpp:89detail/pattern.cpp:75[/]pairingdetail/pattern.cpp:78host.substr(1, host.size()-2)detail/pattern.cpp:188detail/pattern.cpp:191detail/pct_format.cpp:54detail/pct_format.cpp:107detail/pct_format.cpp:152detail/pct_format.cpp:205detail/segments_iter_impl.cpp:113detail/segments_iter_impl.cpp:156detail/url_impl.cpp:205impl/decode_view.hpp:73impl/decode_view.hpp:84impl/encode.hpp:95impl/encode.hpp:194detail/format_args.cpp:134detail/format_args.cpp:346rfc/detail/query_part_rule.hpp:54detail/vformat.cpp:25Theme: Non-owning view/pointer lifetime safety (27 findings, v1)
TRIAGE: BY DESIGN. Non-owning views are fundamental to C++ (cf.
std::string_view,std::span). Callers responsible for ensuring referenced data outlives the view. Documented and inherent to the view-based design.authority_view.hpp:242param.hpp:427params_encoded_base.hpp:71params_encoded_view.hpp:166params_ref.hpp:91params_view.hpp:186params_view.hpp:253segments_encoded_base.hpp:39segments_encoded_ref.hpp:84segments_encoded_view.hpp:161segments_encoded_view.hpp:162segments_ref.hpp:80segments_view.hpp:160url_view.hpp:197url_view.cpp:48grammar/charset.hpp:207grammar/range_rule.hpp:235grammar/string_view_base.hpp:60detail/optional_string.hpp:38detail/optional_string.hpp:73detail/format_args.hpp:103detail/impl/format_args.hpp:70detail/impl/format_args.hpp:80params_encoded_ref.cpp:34segments_ref.cpp:32segments_encoded_view.cpp:29params_encoded_ref.hpp:82Theme: Raw pointer buffer APIs (45 findings, v1)
TRIAGE: BY DESIGN. Internal
_unsafefunctions accept raw pointers with documented preconditions. The public API handles buffer management.detail/any_params_iter.hpp:79detail/any_params_iter.hpp:80detail/any_segments_iter.hpp:70detail/decode.hpp:26detail/decode.hpp:34detail/decode.hpp:42detail/format_args.hpp:239detail/normalize.hpp:158detail/normalize.hpp:159detail/any_params_iter.cpp:115detail/any_params_iter.cpp:117detail/any_params_iter.cpp:210detail/any_params_iter.cpp:265detail/any_params_iter.cpp:329detail/any_params_iter.cpp:374detail/any_segments_iter.cpp:66detail/any_segments_iter.cpp:153detail/decode.cpp:25detail/move_chars.hpp:78detail/move_chars.hpp:81detail/normalize.cpp:33detail/normalize.cpp:40detail/url_impl.cpp:89url_view_base.cpp:76url_base.hpp:65url_base.hpp:82impl/decode.hpp:35impl/decode.hpp:43static_url.cpp:23static_url.cpp:28url_base.cpp:115url_base.cpp:138url_base.cpp:239af227d4)url.cpp:76params_view.cpp:41params_view.cpp:52ipv6_address.hpp:248ipv6_address.hpp:372ipv4_address.cpp:32ipv4_address.cpp:33ipv6_address.cpp:26authority_view.cpp:263rfc/detail/host_rule.cpp:55rfc/detail/host_rule.cpp:98url_view_base.cpp:91Theme: Unchecked percent-encoding assumptions (13 findings, v1)
TRIAGE: BY DESIGN. Internal decode/encode routines operate on data already validated by the public parsing API (RFC 3986 grammar).
pct_string_viewvalidates on construction.decode_view.cpp:27decode_view.cpp:32decode_view.cpp:53decode_view.cpp:69decode_view.hpp:473decode_view.hpp:496impl/decode_view.hpp:84pct_string_view.cpp:27pct_string_view.hpp:435pct_string_view.hpp:436rfc/impl/pct_encoded_rule.hpp:37detail/params_iter_impl.cpp:220detail/normalize.cpp:266Theme: Race conditions in recycled<T> (6 findings, v1)
TRIAGE: FALSE POSITIVE. The report missed
#if !defined(BOOST_URL_DISABLE_THREADS)guards. When threads are enabled,refsisstd::atomic<std::size_t>(recycled.hpp:98-99), and the freelist is protected bystd::mutex m_(recycled.hpp:119).grammar/impl/recycled.hpp:33grammar/impl/recycled.hpp:66grammar/impl/recycled.hpp:78grammar/impl/recycled.hpp:149grammar/impl/recycled.hpp:191grammar/recycled.hpp:78Theme: Incorrect noexcept specifications (5 findings, v1)
TRIAGE: FALSE POSITIVE. These functions take
pct_string_view, which validates percent-encoding on construction. By the time these functions are called, data is already validated.params_encoded_base.hpp:322params_encoded_base.hpp:414params_encoded_base.hpp:467params_encoded_base.hpp:514params_encoded_base.hpp:562Miscellaneous (42 findings, v1)
grammar/ci_string.hpp:333bcd76d8, "fix: ci_less::operator() return type")grammar/detail/charset.hpp:135_mm_loadu_si128is unaligned loadgrammar/detail/charset.hpp:163grammar/impl/not_empty_rule.hpp:29if(!rv)grammar/impl/range_rule.hpp:163grammar/recycled.hpp:440bin_set in ALL constructorsgrammar/recycled.hpp:452f4f723e, "fix: recycled_ptr::get() nullptr when empty")grammar/recycled.hpp:482not this->empty()grammar/string_token.hpp:254s_.resize(n)before&s_[0], n==0 unusedgrammar/string_token.hpp:306grammar/string_token.hpp:369grammar/string_token.hpp:436grammar/literal_rule.hpp:46grammar/lut_chars.hpp:90grammar/lut_chars.hpp:94grammar/ci_string.cpp:35ci_is_equalchecks sizes before detail callgrammar/ci_string.cpp:65FPFIXED (ce4755d, "fix: ci_is_less OOB read")ci_is_lessdoes NOT check sizes (corrected by v2-HIGH-8/9)grammar/literal_rule.cpp:32grammar/impl/tuple_rule.hpp:74grammar/token_rule.hpp:36empty_valueretrievalgrammar/tuple_rule.hpp:61if(!rv)impl/params_base.hpp:50impl/params_encoded_ref.hpp:31impl/segments_encoded_ref.hpp:143!this->empty()impl/segments_ref.hpp:144params_encoded_ref.cpp:86params_ref.cpp:70segments_base.hpp:250fc51e83, "fix: incorrect noexcept in segments_base::front() and back()")detail/format_args.hpp:103detail/impl/format_args.hpp:111detail/over_allocator.hpp:119authority_view.cpp:58rfc/absolute_uri_rule.cpp:77rfc/detail/hier_part_rule.cpp:55rfc/detail/ip_literal_rule.hpp:48it == endfirstrfc/detail/port_rule.cpp:47rfc/detail/port_rule.cpp:53it != endchecked firstrfc/origin_form_rule.cpp:26if(it == end || ...)rfc/query_rule.cpp:52scheme.cpp:29detail/format_args.cpp:39params_encoded_ref.hpp:230u_always valid (private ctor, friend of url_base)Signed integer overflow (3 findings, v1)
TRIAGE: FIXED (
61c8962). Negation of LLONG_MIN is undefined behavior. Three instances, all fixed.detail/format_args.cpp:367detail/format_args.cpp:453detail/format_args.cpp:519Scanner duplicates (15 findings, v1)
The v1 report merged two scanner runs (gpt-5.2 and claude-sonnet-4-5). These 15 findings are exact duplicates (same file and line) reported by both scanners. Each inherits the verdict of the original.
detail/encode.hpp:58grammar/impl/range_rule.hpp:163grammar/impl/recycled.hpp:78detail/decode.cpp:25detail/pct_format.cpp:54detail/pct_format.cpp:107detail/pct_format.cpp:152detail/pct_format.cpp:205detail/url_impl.cpp:89grammar/ci_string.cpp:35grammar/ci_string.cpp:65ipv6_address.cpp:26rfc/detail/host_rule.cpp:55segments_ref.hpp:80url_view.cpp:48MEDIUM (491 v1 + 10 v2 = 501 findings)
v2 MEDIUM (10 findings in report, 9 unique after deduplication)
MED-1. Signed char right-shift in encode_one
include/boost/url/detail/impl/format_args.hpp:2157bceccc, "fix: encode_one signed char right-shift"): Castctounsigned charbefore shift.MED-2. recycled_ptr::get() null dereference
include/boost/url/grammar/recycled.hpp:452f4f723e, "fix: recycled_ptr::get() nullptr when empty").MED-3. encode() noexcept but calls throwing prepare()
include/boost/url/impl/encode.hpp:281token.prepare(n)can throwstd::bad_alloc, butencode()was markednoexcept, causingstd::terminate.d304da8, "fix: encode() noexcept on throwing template"): Removednoexceptfrom both declaration and definition.MED-4. Unbounded remove_suffix on decode_view
src/decode_view.cpp:72BOOST_ASSERT(n <= dn_). Same precondition pattern asstd::string_view::remove_suffix.MED-5. LLONG_MIN negation UB in format
src/detail/format_args.cpp61c8962, "fix: LLONG_MIN negation UB in format").MED-6. OOB read in url_base loop condition
include/boost/url/impl/url_base.hppaf227d4, "fix: url_base loop condition order").MED-7. url::operator=(url&&) self-move-assignment UAF
include/boost/url/impl/url.hpp:63s_then assigned the dangling pointer back.0c22bcd, "fix: url move self-assignment"): Addedif(this == &u) return *this;guard.MED-8. recycled_ptr copy assignment self-assignment UAF
include/boost/url/grammar/impl/recycled.hpp:1871f17914, "fix: recycled_ptr copy self-assignment").MED-9. Unbounded remove_prefix on decode_view
src/decode_view.cpp:55BOOST_ASSERT(n <= dn_). Same as MED-4.MED-10. params_iter_impl decrement multi-equals
src/detail/params_iter_impl.cppa87998a, "fix(params): correct decoded_size in params_iter_impl::decrement() for values containing '='").v1 MEDIUM (491 findings)
No confirmed bugs among the 491 v1 MEDIUM items. All findings fall into the same patterns as the HIGH findings: by-design precondition-based APIs, non-owning view types, internal raw pointer operations, and false positives about thread safety, noexcept, and integer overflow.
LOW (358 v1 + 6 v2 = 364 findings)
v2 LOW (6 findings)
LOW-1. ci_less::operator() return type
include/boost/url/grammar/ci_string.hpp:333bcd76d8, "fix: ci_less::operator() return type").LOW-2. Pointer arithmetic UB in encode()
include/boost/url/impl/encode.hppf0a80ad, "fix: encode() UB pointer arithmetic for small buffers").LOW-3/4. front()/back() noexcept on segments
include/boost/url/segments_base.hpp:250fc51e83, "fix: incorrect noexcept in segments_base::front() and back()").LOW-5. port_rule has_number wrong for port zero at end of input
include/boost/url/rfc/detail/impl/port_rule.hpp:71it == end),has_numberwas incorrectly false because it checkedit != endinstead ofit != start.0148a7a, "fix: port_rule has_number for port zero at end of input"): Changed tot.has_number = it != start;.LOW-6. Static destruction order fiasco in recycled bin
include/boost/url/grammar/impl/recycled.hpp:66v1 LOW (358 findings)
Verdict totals: FIXED 2, FALSE POSITIVE 186, BY DESIGN 170
Two confirmed bugs, both the same underlying issue:
decode()withStringTokenis markednoexceptbuttoken.prepare(n)allocates and can throwstd::bad_alloc, causingstd::terminate. Fixed by removingnoexceptfromdecode()(commitc935b72, "fix: decode() noexcept on throwing template").INFORMATIONAL (169 v1 + 2 v2 = 171 findings)
v2 INFORMATIONAL (2 findings)
INFO-1. ci_equal pass-by-value
include/boost/url/grammar/ci_string.hpp:298-299operator()tookString0andString1by value, causing unnecessary copies for non-trivial string types.70b0e49, "fix: ci_equal arguments by const reference"): Changed toString0 const&andString1 const&.INFO-2. param self-move-assignment
v1 INFORMATIONAL (169 findings)
Confirmed bugs: 3 copy-paste doc bugs in error_types.hpp (FIXED
422153c), 1 missing BOOST_URL_DECL on format_spec_rule_t::parse, 1 duplicate header include. No critical security issues among the INFORMATIONAL findings.