Sunday, September 13, 2026

devel/boost: backport a regression fix to 1.91.0

The current version of the Boost C++ library in OpenBSD ports (1.91.0) has an annoying regression in Boost.URL: https://github.com/boostorg/url/issues/989 The issue is fixed upstream and released in in 1.92.0: https://github.com/boostorg/url/commit/41b467a389a68321608138a432b15024b6c11918 After talking to Marc Espie at EuroBSDCon I understood that that updating boost to 1.92.0 is at this point in the release cycle is risky and will most likely be postponed until 8.0 is out. He suggested to try backporting the fix for the time being. Below is the patch taken as-is from the upstream and it luckily applies cleanly on top of 1.91.0. I have verified the fix on the resulting build from the port. Can we please apply this stopgap measure until we move to 1.92.0? Index: devel/boost/Makefile =================================================================== RCS file: /cvs/ports/devel/boost/Makefile,v diff -u -p -u -r1.163 Makefile --- devel/boost/Makefile    18 May 2026 05:48:17 -0000    1.163 +++ devel/boost/Makefile    13 Sep 2026 18:07:29 -0000 @@ -6,6 +6,7 @@ COMMENT-main=    free peer-reviewed portabl  COMMENT-md=    machine-dependent libraries for boost  VERSION=    1.91.0 +REVISION=    0  DISTNAME=    boost_${VERSION:S/./_/g}  PKGNAME=    boost-${VERSION}  EPOCH=        0 Index: devel/boost/patches/patch-libs_url_base_edit_params =================================================================== RCS file: devel/boost/patches/patch-libs_url_base_edit_params diff -N devel/boost/patches/patch-libs_url_base_edit_params --- /dev/null    1 Jan 1970 00:00:00 -0000 +++ devel/boost/patches/patch-libs_url_base_edit_params    13 Sep 2026 18:07:29 -0000 @@ -0,0 +1,140 @@ +Backport the fix for the URL corruption bug on url.params().append() in Boost 1.91.0 + +Fixed upstream in 1.92.0: 41b467a389a68321608138a432b15024b6c11918 +Index: boost/include/boost/url/impl/url_base.hpp +--- boost/url/impl/url_base.hpp.orig ++++ boost/url/impl/url_base.hpp +@@ -3159,7 +3159,12 @@ edit_params( +     BOOST_ASSERT(pos1 <= impl_.offset(id_frag)); + +     // calc decoded size of old range, +-    // minus one if '?' or '&' prefixed ++    // minus one for the leading '?' which is ++    // not counted in decoded_[id_query]. ++    // dn0 may be -1 here when the old range is ++    // empty and the query was non-empty; the ++    // matching subtraction on dn below cancels ++    // that out when the delta is taken. +     auto dn0 = +         static_cast<std::ptrdiff_t>( +             detail::decode_bytes_unsafe( +@@ -3168,8 +3173,6 @@ edit_params( +                     pos1 - pos0))); +     if(impl_.len(id_query) > 0) +         dn0 -= 1; +-    if(dn0 < 0) +-        dn0 = 0; + + //------------------------------------------------ + // +@@ -3267,16 +3270,13 @@ edit_params( +         } +     } + +-    // calc decoded size of new range, +-    // minus one if '?' or '&' prefixed ++    // calc decoded size of new range; see dn0. +     auto dn = +         static_cast<std::ptrdiff_t>( +             detail::decode_bytes_unsafe( +                 core::string_view(dest0, dest - dest0))); +     if(impl_.len(id_query) > 0) +         dn -= 1; +-    if(dn < 0) +-        dn = 0; + +     if(dn >= dn0) +         impl_.decoded_[id_query] += +Index: libs/url/test/unit/params_encoded_ref.cpp +--- libs/url/test/unit/params_encoded_ref.cpp.orig ++++ libs/url/test/unit/params_encoded_ref.cpp +@@ -121,6 +121,11 @@ struct params_encoded_ref_test +         params_encoded_ref ps(u.encoded_params()); +         f(ps); +         BOOST_TEST_EQ(u.encoded_query(), s1); ++        BOOST_TEST_EQ( ++            u.encoded_query().decoded_size(), ++            pct_string_view(s1).decoded_size()); ++        BOOST_TEST_NO_THROW(u.encoded_target()); ++        BOOST_TEST_NO_THROW(u.encoded_resource()); +         if(! BOOST_TEST_EQ( +                 ps.size(), init.size())) +             return; +Index: libs/url/test/unit/params_ref.cpp +--- libs/url/test/unit/params_ref.cpp.orig ++++ libs/url/test/unit/params_ref.cpp +@@ -142,6 +142,11 @@ struct params_ref_test +         params_ref ps(u.params()); +         f(ps); +         BOOST_TEST_EQ(u.encoded_query(), s1); ++        BOOST_TEST_EQ( ++            u.encoded_query().decoded_size(), ++            pct_string_view(s1).decoded_size()); ++        BOOST_TEST_NO_THROW(u.encoded_target()); ++        BOOST_TEST_NO_THROW(u.encoded_resource()); +         if(! BOOST_TEST_EQ( +                 ps.size(), init.size())) +             return; +@@ -814,6 +819,62 @@ struct params_ref_test +             check(f, "?k0&k1=&k2=key", "k0&k1=" BIGSTR "&k2=key", +                 { {"k0",no_value}, {"k1",BIGSTR}, {"k2","key"} }); +         } ++ ++        // issue #989: encoded_target() asserts after ++        // successive params().set() on a fresh url. ++        // Regression for broken decoded_[id_query] ++        // bookkeeping in url_base::edit_params. ++        { ++            url u; ++            u.params().set("a", "b"); ++            BOOST_TEST_EQ(u.encoded_query(), "a=b"); ++            BOOST_TEST_EQ(u.encoded_query().decoded_size(), 3u); ++            BOOST_TEST_EQ(u.encoded_target(), "?a=b"); ++ ++            u.params().set("c", "d"); ++            BOOST_TEST_EQ(u.encoded_query(), "a=b&c=d"); ++            BOOST_TEST_EQ(u.encoded_query().decoded_size(), 7u); ++            BOOST_TEST_EQ(u.encoded_target(), "?a=b&c=d"); ++        } ++ ++        // Related: erase first param must leave a ++        // consistent decoded_[id_query]. ++        { ++            url u("?a=b&c=d"); ++            BOOST_TEST_EQ(u.encoded_query().decoded_size(), 7u); ++            u.params().erase(u.params().begin()); ++            BOOST_TEST_EQ(u.encoded_query(), "c=d"); ++            BOOST_TEST_EQ(u.encoded_query().decoded_size(), 3u); ++            BOOST_TEST_EQ(u.encoded_target(), "?c=d"); ++        } ++ ++        // Related: erase last param must leave a ++        // consistent decoded_[id_query]. ++        { ++            url u("?a=b&c=d"); ++            u.params().erase(std::next(u.params().begin())); ++            BOOST_TEST_EQ(u.encoded_query(), "a=b"); ++            BOOST_TEST_EQ(u.encoded_query().decoded_size(), 3u); ++            BOOST_TEST_EQ(u.encoded_target(), "?a=b"); ++        } ++ ++        // Related: insert at front of non-empty query. ++        { ++            url u("?x=y"); ++            u.params().insert(u.params().begin(), {"a", "b"}); ++            BOOST_TEST_EQ(u.encoded_query(), "a=b&x=y"); ++            BOOST_TEST_EQ(u.encoded_query().decoded_size(), 7u); ++            BOOST_TEST_EQ(u.encoded_target(), "?a=b&x=y"); ++        } ++ ++        // Related: append to non-empty query. ++        { ++            url u("?x=y"); ++            u.params().append({"a", "b"}); ++            BOOST_TEST_EQ(u.encoded_query(), "x=y&a=b"); ++            BOOST_TEST_EQ(u.encoded_query().decoded_size(), 7u); ++            BOOST_TEST_EQ(u.encoded_target(), "?x=y&a=b"); ++        } +     } + +     static

No comments:

Post a Comment