Cherry-picks for 10.2.1 (2026-09-22) - #13720
Merged
Merged
Conversation
) Platforms without an inline 128-bit CAS, such as riscv64, fail the build with "unsupported processor". Neither GCC nor LLVM emit an inline 128-bit CAS on riscv64, even with the Zacas extension, so a hand-written pointer-packing branch would be the only alternative and would depend on the kernel's virtual address width. Fall back to the __atomic builtins instead. They lower to libatomic calls, which may take internal locks; that is correct because every access to a shared head_p goes through INK_QUEUE_LD and ink_atomic_cas. Also revive the orphaned atomic list stress test as Catch2 tests and remove the dead INK_QUEUE_NT code. Fixes: apache#13555 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 70c6b2c)
Ten guards in QPACK.cc read `xpack_decode_integer(...) < 0 && value > 0xFFFF`, so neither condition rejects anything: a decode failure falls through, and an oversized varint is silently narrowed into the surrounding uint16_t. The delta_base_index guard also had its comparison inverted. The unchecked failure matters more than the truncation. On failure xpack_decode_integer returns -1, and callers then do `read_len += ret`, giving SIZE_MAX. IOBufferReader::consume() takes that as -1, its release-assert passes because is_read_avail_more_than(-2) is true, and start_offset moves backwards. The helper returns 0 rather than a negative, so _on_encoder_stream_read_ready() does not abort and its `while (is_read_avail_more_than(0))` loop re-reads the same byte. Flip the ten operators and correct the inverted comparison. The value guard in _read_insert_with_name_ref also has its bound raised from 0xFF to 0xFFFF, matching the other nine sites. This is required rather than cosmetic: value_len is a size_t, so 0xFF bounds nothing, and under || a 0xFF bound would reject every header value longer than 255 bytes. At 0xFFFF the check is unreachable, since xpack_decode_string is already capped by _header_field_max_size. (cherry picked from commit bfe88e1)
* hrw4u: exit non-zero on compile errors The exit gate required `tree is None`, but ANTLR error recovery almost always yields a tree, so both syntax and semantic errors exited 0 while printing diagnostics and a partial .conf. Collecting every error and failing the build were mutually exclusive: only --stop-on-error exited 1. Sandbox denials were caught by the same gate, so the "denied" outcome the sandbox docs describe also exited 0. generate_output now reports failure by return value and run_main owns the exit, so a bad file in a bulk run no longer aborts the files after it. A failing compile still prints its partial .conf; the exit code now marks it untrustworthy. Suppressing those bytes would change behavior for existing pipelines and is left as a separate decision. * hrw4u: parse real input in generate_output return-value tests The failure test passed parser_obj=None, which only worked because a None tree short-circuits before the AST branch reads it. Parsing a real input instead also pins the regression: the input parses, so the tree is not None -- exactly what the old exit gate let through. * hrw4u: cover u4wrh in the exit-code tests, scope the doc claim u4wrh drives the same run_main(), so the contract regresses just as easily there; verified the new test exits 0 against the pre-fix code. The doc said every input is processed before the status is decided, which reads as covering the fatal argument and I/O paths too -- those still exit immediately. * hrw4u: document exit status 2 for usage errors run_main() lets argparse handle the command line, so an unknown option, a bad option value, or conflicting output modes exit 2, not the 1 the table claimed. Normalizing them to 1 would merge "you typed the command wrong" into "your rules did not compile", so the doc follows the code. Row 1 now lists only what actually exits 1; the mixed bulk/stdout rejection is caught after parsing and belongs there, not with argparse. (cherry picked from commit 915543f)
* hrw4u: add an AST round-trip test over the whole corpus
Render every corpus input's AST back to hrw4u and require the compiled
config to be unchanged: whatever the AST drops, the config loses too.
Unlike hand-written cases, nothing has to be enumerated in advance.
It found five losses, all fixed here:
- an empty `else { }` looked like no else clause, so a sandbox policy
denying 'else' was evaded by writing one
- comments were discarded, though five .conf goldens carry them
- a bool assignment lost the spelling the emitter echoes back
- parentheses were unwrapped, dropping the cond %{GROUP} they emit
- a set and an iprange both became a tuple of IPValue, though
in [1.2.3.4] emits (1.2.3.4) and in {1.2.3.4} emits {1.2.3.4}
IfBlock.has_else is required rather than defaulted, so a site that
rebuilds the node and forgets it fails instead of reopening the bypass.
A second test asserts the corpus reaches every grammar rule; a bare
$param value had no fixture, now added.
* hrw4u: keep bool spelling in every value context
The AST kept the source spelling only on an assignment RHS, so a TRUE
in a comparison or a function argument regenerated as true and changed
the emitted config. bool-spelling.input.txt witnesses both; the reverse
normalizes an argument's spelling, hence the exceptions.txt entry.
* hrw4u: keep number spelling in every value context
The AST parsed a NUMBER into a Python int, so a leading zero the emitter
echoes back was lost: 007 became 7 in a header value, three bytes
becoming one. number-spelling.input.txt witnesses all three value
contexts; the digits survive in each.
A plain int was a deliberate call, on the grounds that no corpus input
wrote a leading zero. It did not survive a semantic pass built on the
AST, which matches structurally over ValueExpr and has nowhere to put a
naked int.
* hrw4u: make the per-test sandbox fixture compile
Its body wrote inbound.req.X-Foo inside TXN_START, where that field does
not exist, so the input was rejected before the sandbox ran and the
round-trip test had to name it as the one corpus input that does not
compile. The fixture only ever asserted that a per-test sandbox.yaml is
preferred over the shared one, and a section denial fires whatever the
body is, so the body is now a rule TXN_START actually admits.
That retires DOES_NOT_COMPILE: an input meant to be rejected is named
.fail., and a corpus input that stops compiling should fail the test
rather than opt out of it.
(cherry picked from commit 2651038)
…#13675) * hrw4u: enforce sandbox NOT and in on their implicit spellings `modifiers: [NOT]` only caught an explicit `with NOT`, and `language: [in]` only caught the `[...]` value form, so `!expr`, `!=`, `!~`, `!in` and `in {10.0.0.0/8}` all compiled unchecked. AND and OR were already checked at `&&` and `||`; negation and IP-range membership are now consistent with that. The check sits at the two sites where the source introduces negation, not at `_make_condition`, whose `negate` argument is also true for the `[NOT]` the compiler synthesises for a bare header test. Denying `NOT` must not reject `if inbound.req.X-Foo`; allowed-implicit-not pins that. `modifiers` was undocumented, so the sandbox section gains it. * Address review: name the tag the compiler actually emits The modifiers example said `%{HEADER:X-Foo}`, but `inbound.req.X-Foo` lowers to CLIENT-HEADER, as allowed-implicit-not's golden output shows. Kept the literal on one line while here. * Address review: cover the !~ spelling of NOT NOT_TILDE is its own lexer token; without a case for it, dropping it from the negate tuple still passed. (cherry picked from commit ca13330)
Cachekey patterns with ten or more capture groups can crash ATS when building a cache key because a successful match leaves the capture vector empty. Replacement patterns also reject valid group references when the match buffer is too small or trailing optional groups do not participate in a match. This patch sizes match buffers from the validated pattern capture count and checks replacement references at initialization. Unmatched optional groups contribute empty strings. Unit and replay coverage verifies full cache keys across the capture limit and optional-group combinations. Fixes: apache#13638 Co-authored-by: GPT-6 Astra Light Co-authored-by: GPT-6 Astra Medium Co-authored-by: bneradt <bneradt@yahooinc.com> (cherry picked from commit f39ee5f)
Issue apache#12244 reported ATS aborting on the HttpTunnel skip_bytes assertion for Range requests of a small, cacheable 308. The fix in apache#12906 was tested only with a 100 Continue ahead of a compressed POST response, so the reported scenario had no coverage. 103 Early Hints take the same interim-response path as 100 Continue, and a Range miss with cache.range.write enabled caches the untransformed response behind the range transform, leaving the cache-write consumer with a stale header size to skip in a body-only buffer. This patch extends the regression test with a run in which the origin sends a 103 Early Hints and then a 65 byte, cacheable 308 that the client requests with "Range: bytes=0-64". Without the apache#12906 fix, this run hits the same assertion reported in the issue; with it, ATS keeps running. Fixes: apache#12244 Co-authored-by: Claude Opus 5.5 (Medium effort) <noreply@anthropic.com> (cherry picked from commit 0079038)
The non-direct-IO retry added in TS-1312 only fires when O_CREAT is set, and O_CREAT is set only when the span names a directory, so that cache.db can be created inside it. An explicit file span in storage.config therefore gets no retry: on a file system without O_DIRECT support the span open fails outright and the cache is disabled, even though the very same file system works when the span is written as a directory. Whether direct I/O is usable is a property of the file system, not of the form the span was written in. The cache_shm_* autests are the only ones configuring an explicit file span, so on a sandbox whose file system lacks O_DIRECT all of them fail with "must be placed on a file system that supports direct I/O" followed by "Cache Disabled". (cherry picked from commit 3e10681)
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.
Cherry-picks for the 10.2.1 release, taken from the items sitting at For v10.2.1 in the
ATS v10.2.x project.
Picked in master merge order:
70c6b2c4__atomicbuiltins as the freelist 128-bit CAS fallbackbfe88e10||in the varint decode range guards915543f92651038eca133303NOTandinon their implicit spellingsf39ee5f50079038a3e10681aAll eight are
MERGEDsquash merges with noIncompatiblelabel, and none were alreadypresent on 10.2.x (checked by both
(#NNN)subject and thecherry picked fromtrailer).Conflicts
Only one:
tools/hrw4u/tests/data/ops/exceptions.txtin #13699. Master's parent alreadycarried a
json-body.inputexception from a PR that was not picked here; 10.2.x has nojson-body.*fixture. Resolved to add only thebool-spelling.inputentry the commitactually introduces, which matches the original diff exactly.
Not picked
Three project items at For v10.2.1 are still
OPENon master and so were skipped:#12825, #13086, #13196. They stay at
For v10.2.1for the next pass.Local verification (macOS,
devpreset)cmake --build build-dev -- -k 0— clean.ctest -j4— 123/124; onlytest_jsonrpcserverfails, a known macOS-localunix-socket/restart timing issue, not related to these picks.
test_InkAtomicListfrom Use __atomic builtins as the freelist 128-bit CAS fallback #13571 passes (24008 assertions).this CI run is the gate for both.
Draft on purpose: to be landed by fast-forward once CI is green, not merged via the UI.