fix: normalize_path overflow shielding "//" path#995
Conversation
|
An automated preview of the documentation is available at https://995.url.prtest2.cppalliance.org/index.html If more commits are pushed to the pull request, the docs will rebuild at the same URL. 2026-05-13 14:12:31 UTC |
|
GCOVR code coverage report https://995.url.prtest2.cppalliance.org/gcovr/index.html Build time: 2026-05-13 14:24:07 UTC |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #995 +/- ##
========================================
Coverage 99.12% 99.12%
========================================
Files 154 154
Lines 10091 10093 +2
========================================
+ Hits 10003 10005 +2
Misses 88 88
Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
Closes #992.
Problem
triggers
BOOST_ASSERT(n + 2 <= pn)inurl_base::normalize_path(include/boost/url/impl/url_base.hpp:2207). With assertions disabled the subsequentmemmovewrites past the end of the path region — a real heap buffer overflow.Root cause
When the URL has no authority and the normalized path starts with
//,normalize_pathprepends a 2-byte/.shield so the round-tripped string isn't re-parsed as an authority. The pre-existing comment claimed thismemmovealways has room because..cancellation consumes ≥ 5 bytes, and the shield only needs 2.That's true for the cancellation case (
/a/..//x→/x→/.//x, with slack from the canceled segments). It's not true for short inputs that hit the shield branch with no cancellation:"//"(pn = 2,n = 2) — wants 4 bytes for/.//"///"(pn = 3,n = 3) — wants 5 bytes for/.///parse_origin_formproduces exactly such paths (origin-form has no authority).Fix
include/boost/url/impl/url_base.hpp:2205-2222— before thememmove, grow the path region withresize_impl(id_path, n + 2, op)whenn + 2 > pn. Re-readp_destfrom the resize return value (the underlying storage may have moved) and updatepnso the laterif (n != pn)shrink branch behaves correctly.The surrounding comment was updated: the shield branch now requires either ≥ 2 bytes of cancellation slack or a buffer grow, instead of the previous overstated invariant.
Tests
test/unit/url.cpp— a new block in the existing normalize-path section asserts:The first case is the exact reproducer from the issue. The other two cover the same shieldless-
//family with extra trailing slashes.All 42324 unit-test assertions and 79 ctest entries pass locally under C++20 (
./test_all.shpatterns).