Repository navigation
Conversation
…same bit UWS_DISTINCT_FLAG_BITS declares the two flag enums of HttpResponseData. The build fails when two of their single-bit values are equal. Static asserts beside uws_res_state, uws_h2_res_state and uws_h3_res_state compare the HTTP/2 and HTTP/3 copies of the flags with HttpResponseData, and pin the values and the width that the Rust State repeats.
|
Updated 6:23 AM PT - Oct 29th, 2026
❌ @robobun, your commit d989656 has 3 failures in
🧪 To try this PR locally: bunx bun-pr 47147That installs a local version of the PR into your bun-47147 --bun |
|
Status: draft, stacked on #46528. It stays a draft until #46528 merges. Then I cut it again on How I reproduced it ( Platforms: CI builds the change on all 14 build lanes: Linux (x64, aarch64, musl, Android, ASAN, hardened), FreeBSD, macOS and Windows (x64 and aarch64 each). CI (build 135054): no failure comes from this diff. Three tests are red, and each is red without this change:
PR: #47147 |
…obobun/f75ebd5b/uws-state-distinct-flag-bits
Behaviour change: none
Draft, stacked on #46528.
Problem
HttpResponseData::statehas 29 hand-numbered flags and three hand copies of their values. C++ accepts two flags on one bit. Only comments keep the copies equal.1 << 26. Four commits of node:http: the server follows Node (request body, framing, response finish, lifecycle) #43557 had two on1 << 19.Fix
UWS_DISTINCT_FLAG_BITSdeclares the two flag enums ofHttpResponseData. No flag line changes. Two equal single-bit values fail the build:requirement 'noTwoFlagsAre1ShiftedLeftBy(26)': two flags of this enum have the same bit.uws_*_res_stateshims compare the HTTP/2 and HTTP/3 copies withHttpResponseData. They pin the values andu32width of the RustState.Background
State.static_assertover a second hand-written list does not see a flag that a merge adds. A source lint does not block a merge.Downsides
main.Notes
Why stacked. #46528 rewrites this enum and its three copies, and both changes touch the closing line of the enum. So this PR is cut on top of #46528 and stays a draft until #46528 merges. Then I cut it again on
main.The guard is preventive. No commit on
mainhas two flags on one bit, and no copy ever differed fromHttpResponseData(28 and 53 commits checked). The word grew from 8 flags on 2026-06-27 to 24 on 2026-10-21, and #46528 takes it to 29.Git wrote one duplicate already. Commits 43bce61, 816f734, cda2e43 and a307bdd of the #43557 branch have
HTTP_NODE_PEER_ENDED = 1 << 19(line 162) andHTTP_NODE_NOTIFY_READ_PARSED = 1 << 19(line 169). 781971d ("node:http: reconcile with main after the rebase") movedHTTP_NODE_PEER_ENDEDto1 << 22by hand.Replay: the header of each open PR merged onto this branch (
git merge-file, this file only, 21 open PRs change it).#44321 and #33871 leave a duplicate that no conflict marker points at.
Real translation unit (
UnifiedSource-src_uws_sys-0.cpp, debug flags, clang 23.1.2). The tree file is swapped, the unit is compiled with-fsyntax-only, and the file is restored.The whole header of #44321 merged onto the branch gives the same
noTwoFlagsAre1ShiftedLeftBy(26)error, plus 11 errors from the rest of that PR, which is not merged.The macro. The error has the bit, not the two names: find them with a search for
<< 26. A list without its trailing comma fails withexpected ';' at end of declaration listatlistEndsWithAComma. An enumerator without an initializer fails withconstexpr variable 'everyFlagHasAnInitializer' must be initialized by a constant expression. An intended second name for a bit goes in an enum of its own. The header passes under-std=gnu++23,-std=c++23,-std=c++20and in clang's MSVC mode (--target=x86_64-pc-windows-msvc -fms-compatibility, and theclang-cldriver, both with stand-in standard headers). CI builds the branch on all 14 build lanes: Linux (x64, aarch64, musl, Android, ASAN, hardened), FreeBSD, macOS and Windows (x64 and aarch64 each).Cost. User instructions of one clang run per unit (
perf_event_open, ASLR off,-fsyntax-only, debug flags, 2 runs, the tree before and after this commit).Two runs of one unit differ by at most 0.04 M. A comment line added to the header moves the total by 0.07 M. The uws unit is near a step: one empty function template in an otherwise empty new header costs +34 M there, and between -1 M and +6 M in two other units.
Object code: the 8 units compiled at
-O2 -g0without sanitizers, for this branch and for this branch with the guard taken out and every line number kept. All 8 objects have the same sha256.Conflicts.
git merge-fileof every open PR that changes one of the five existing files, this branch against #46528 alone: 0 new conflict hunks (21 PRs forHttpResponseData.h, 61 forlibuwsockets.cpp, 8 and 17 for the HTTP/2 and HTTP/3 shims, 29 forResponse.rs).Not covered.
Http2ResponseDataorHttp3ResponseData: no assert line lists it. Both words are full today (8 flags in auint8_t).State, and a change of a Rust value alone: the asserts see the C++ side.HTTP_BODY_CHUNKEDandHTTP_BODY_UNTIL_CLOSEare single bits, so bits 9 and 10 are taken.LIBUS_LISTEN_*inpackages/bun-usockets/src/libusockets.h(a C header, repeated insrc/uws_sys/lib.rs),packages/bun-uws/src/WebSocketProtocol.h, and Rustbitflags!sets (Addbun_core::assert_distinct_flag_bits!, a compile-time check that no two flags of a set share a bit #47097).Other designs.
#definehere.main).HttpResponseData<false>: that instantiates the class template in units that did not need it (+34 M instructions in one unit when measured onmain).Tests run on the debug build:
test/js/bun/http/http-server-chunking.test.ts(25 pass),node-http-pipeline-callbacks.test.ts(16 pass),node-http-halfclose-midupload.test.ts(2 pass),bun-server.test.ts(96 pass, 1 skip with--timeout 120000. With the default 5 s timeout, 7 to 9 tests that start a child process time out on my machine).clang-formatandrustfmtreport no change.no test proof · iteration 1 · the description declares no behaviour change, so there is no failing test to prove; the existing suite in CI is the check