Skip to content

[pull] master from php:master#1089

Merged
pull[bot] merged 16 commits into
turkdevops:masterfrom
php:master
Jul 14, 2026
Merged

[pull] master from php:master#1089
pull[bot] merged 16 commits into
turkdevops:masterfrom
php:master

Conversation

@pull

@pull pull Bot commented Jul 14, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

LamentXU123 and others added 16 commits July 14, 2026 23:41
odbc_stmt_describe() binds a colsize+1 buffer for short columns and stores
that capacity in datalen, but odbc_stmt_get_col() built the result string
from the driver-reported fetched_len. A conforming driver truncates an
over-long value into the buffer yet reports the full length, so
ZVAL_STRINGL_FAST over-read past the allocation and returned adjacent heap to
userland. Clamp fetched_len to the bound capacity, guarded by !is_long so the
long-column SQLGetData path (whose fixed buffer is unrelated to datalen) is
left untouched.

Fixes GH-22667
Closes GH-22672
* PHP-8.4:
  Fix GH-22667: pdo_odbc heap over-read on oversized column value
* PHP-8.5:
  Fix GH-22667: pdo_odbc heap over-read on oversized column value
…port.phpt (#22724)

Fix flaky CI test:
\ext\sockets\tests\socket_recvfrom_afpacket_no_port.phpt

failed run example:
https://github.com/php/php-src/actions/runs/29266463698/job/86873055452
…22493)

phpdbg_add_watch_element() frees the passed element and returns the
existing one when the variable is already watched, but several callers
kept using the freed pointer, so re-watching a variable was a
use-after-free in more places than the two reported. Report the duplicate
back through the parse callback and register nothing, and reject a
recursive watch's hashtable element that collides with an existing watch,
at creation and recreation, rather than freeing a still-referenced one. A
recursive watch over an already-array-watched variable now watches only
the root and skips the shared hashtable.

Running the tests under ASAN exposed a second, latent use-after-free at
shutdown: the watch tables are module-scoped but hold request-pool memory,
so under the tracked allocator freeing a watched variable during executor
teardown re-queues an element after the last drain, tracked_free_all frees
the pool, and phpdbg_destroy_watchpoints reads it at module shutdown. Tear
the watch state down in a post_deactivate handler, which runs after the
executor frees values but before the memory manager is torn down.

Dropping watch_006's xfail surfaced a separate pre-existing bug on
large-page platforms: the fault handler rechecks every watchpoint on the
faulting page, so on 16 KB pages a value-only write to an element can
fault the page holding a watched hashtable's own struct and run the
recursive rescan, which re-reported existing elements as freshly added.
Only run that rescan when the element count actually changed.

Fixes GH-22480
Abstract unix domain socket addresses begin with a null byte, but the
persistent stream list is keyed by a NUL-terminated string. The key was
truncated at that null byte, so distinct abstract sockets collapsed onto
the same persistent resource in p(f)sockopen() and stream_socket_client().

Escape null bytes (and backslashes, to stay unambiguous) when building the
persistent hash key so the full address is preserved. The escaping helper
lives in ext/standard rather than the public streams header, since only
p(f)sockopen() and stream_socket_client() need it.

Fix #22617

close GH-22704
* PHP-8.4:
  GH-22617: avoid null byte truncation of persistent stream keys
* PHP-8.5:
  GH-22617: avoid null byte truncation of persistent stream keys
ext/odbc bound a displaysize+1 buffer per column but built the result
string from the driver-reported vallen. A conforming driver truncates an
over-long value into the buffer yet reports the full length, so the fetch
over-read past the allocation and returned adjacent heap bytes to userland.
Store the bound capacity in odbc_result_value and clamp the string length to
it at the three bound-buffer fetch sites (odbc_fetch_array/object,
odbc_fetch_into, odbc_result); the SQLGetData long-column paths stay bounded
by longreadlen.

Fixes GH-22668
Closes GH-22670
* PHP-8.4:
  Fix GH-22668: odbc heap over-read on oversized column value
* PHP-8.5:
  Fix GH-22668: odbc heap over-read on oversized column value
odbc_stmt_param_hook() sizes an output-param buffer from the declared maxlen
but then copies the runtime value into it using the value's own length, and
at fetch-back hands ZVAL_STRINGL the driver-reported length. Both trust a
length that can exceed the buffer: the input copy overflows the heap
(controlled write), and on a truncated OUTPUT value the driver reports the
full length via the shared indicator, so the readback over-reads. Record the
bound capacity in a new outbuflen field and clamp the copy and the readback to
it. LOB output is rejected at bind, so those copy sites stay unreachable.

Fixes GH-22666
Closes GH-22674
* PHP-8.4:
  Fix GH-22666: pdo_odbc heap overflow on oversized output param
* PHP-8.5:
  Fix GH-22666: pdo_odbc heap overflow on oversized output param
@pull pull Bot locked and limited conversation to collaborators Jul 14, 2026
@pull pull Bot added the ⤵️ pull label Jul 14, 2026
@pull pull Bot merged commit 3a40e29 into turkdevops:master Jul 14, 2026
1 of 3 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants