-
Build fix for platforms without futex: Changed
sw_usleepto the standardusleepto fix compilation failure on that platform. -
WebSocket decoding validation: The decoder rejects CLOSE/PING/PONG control frames with RSV1 set before unmasking, preventing compressed control frames from entering the receive path.
-
WebSocket encoding validation: The encoder rejects fragmented control frames or control frames with payloads exceeding 125 bytes, and makes
ping()return false and setSWOOLE_ERROR_WEBSOCKET_PACK_FAILEDwhen encoding fails. -
Thread stdio fd leak: After a thread exits, manually close the STDIN/STDOUT/STDERR file descriptors that were not released due to
PHP_STREAM_FLAG_NO_CLOSE. -
Reactor unregistered fd lookup: When looking up an unregistered fd, return null instead of inserting an empty entry into the socket map, and change the accessor to const.
-
SOCKS5 target host length validation: The DNS tunnel now validates that the target host length does not exceed 255 bytes, and returns an error as a handshake failure when it is too long.
-
Thread scheduling policy preservation: When no policy is specified in
Thread::setPriority(), first read the current scheduling policy before setting the priority, fixing the issue of using the invalid-1policy. -
Buffered stream read fix: Under PHP 8.3, when the stream already has buffered data, use the non-waiting receive path so that hooked streams directly return buffered data without waiting for new events.
-
Atomic wait on systems without futex: Implement an atomic wait registry based on a shared-memory hash table, replace the mutex with a spinlock, and add timeout, generation notification, and entry reuse mechanisms.
-
Stream write timeout reporting: When
fwriteencounters ETIMEDOUT, no longer print an error notice, preserve thetimed_outmetadata and do not seteof; only set eof for genuine write errors. -
Stream read timeout error preservation: When
freadencounters ETIMEDOUT, return failure (false) instead of 0 so callers can identify the timeout through metadata, and do not mistakenly set eof. -
Poll dispatch socket identity preservation: The Poll reactor additionally stores the Socket pointer corresponding to each pollfd during
set_events, and directly uses that pointer during dispatch, avoiding events being dispatched to the wrong socket after the fd is reused in a handler. -
Process pool message bus reuse:
start()no longer recreates the message bus when it already exists, allowing the same process pool to be shut down and started again and still deliver messages normally. -
BASE event pool resource release: A multi-worker BASE server destroys the event process pool after the manager ends and reuses the message boxes already allocated by
create(), fixing resource leaks. -
TCP listener rebindability:
make_server_socket()enablesSO_REUSEADDRonly for TCP listeners, avoiding TIME_WAIT preventing immediate restart while not affecting Unix and UDP socket behavior. -
ProcessPool truncated packet handling: The stream/task protocol requires both the length prefix and the packet body to be read exactly in full; a short read is treated as an incomplete packet and the connection is closed, and old data in the reused buffer is no longer passed to the callback as a valid payload.
-
Message queue key range validation: The Process, ProcessPool, and Server entry points validate the range before narrowing a PHP integer to
key_t; keys outside the representable range ofkey_tare rejected, while unsigned 32-bit boundaries are still accepted. -
Multipart upload temporary file error: When a temporary file cannot be created for a multipart upload, mark
UPLOAD_ERR_NO_TMP_DIRin the file information, avoiding handing an empty upload to the handler as a successful file. -
Support HTTP QUERY method: Add QUERY to the HTTP/1 method table and let URL-encoded form bodies go through the existing request parsing path, keeping parsing consistent between normal servers and coroutine servers.
-
Apply stream timeout to hooked write operations: When
stream_set_timeout()sets a timeout, also update both the read and write coroutine socket deadlines, so that a blockingfwrite()no longer exceeds the configured stream timeout. -
Coroutine HTTP client socket initialization: Initialize the internal socket zval to null at construction so that calling
close()before connecting is safe and returnsSWOOLE_ERROR_CLIENT_NO_CONNECTION. -
Pass null for DNS when there is no service:
getaddrinfo()passes a null pointer instead of an empty string when no service is specified, fixing the issue on musl (Alpine Linux) where EAI_SERVICE caused resolution to always fail. -
Ignore external interrupts when preemption is disabled: Apply the scheduling deadline only when the preemptive scheduling thread is running, preventing signal interrupts triggered by other extensions from switching coroutines using stale context state when preemption is off.
-
CPU affinity ID validation: Each affinity entry is converted only once and used for validation, diagnostics, and
CPU_SET; negative IDs and IDs exceedingCPU_SETSIZEare rejected, andThread::setAffinity()treats any nonzero return value frompthread_setaffinity_npas failure. -
Validate affinity IDs by CPU count: On top of the previous commit, change the upper limit to
SW_CPU_NUM(also not exceedingCPU_SETSIZE), rejecting IDs outside the available CPU range before Linux silently trims the invalid mask. -
Prevent workers from executing manager-only signal handling: In signal handling, first verify that the current process PID equals the manager PID, avoiding a newly forked worker briefly inheriting the manager's signal handler and then repeatedly broadcasting SIGWINCH to itself.
-
Preserve native coroutine socket errors: After a socket call fails, immediately read errno and store it in a local variable;
shutdown()andcheck_liveness()no longer depend on the C runtime errno that may be overwritten. -
Initialize PHP hook after switching hooks: When switching from the native hook to the PHP hook, add the missing function cache initialization so that subsequent calls go through the
swoole_*PHP functions instead of an empty cache. -
Redis server packet receive buffer handling: Check the length before reading the trailing CRLF, expand only when the buffer is full, and perform the expansion calculation without narrowing and within
package_max_length, fixing fragmented request parsing. -
Preserve package length limit for partial settings: When
set()on a coroutine socket does not providepackage_max_length, no longer reset it to the default value, preserving the current limit. -
Crash when initiating PHP requests in non-Swoole threads:
sw_is_main_thread()now uses theZTScheck, and all reads and writes of the task temporary directory are protected bysw_thread_lock, avoiding crashes in threads not created by Swoole. -
Coroutine HTTP server request boundaries and 100 Continue: When the chunked request buffer is full, expand it to the limit and return 413 if exceeded; use llhttp completion events to precisely determine request end and preserve pipeline bytes, and send a 100 Continue once before waiting for the request body.
-
HTTP/1.0 ignores 100-continue: Send the 100 Continue interim response only for HTTP/1.1 (version 101) requests; HTTP/1.0 clients do not recognize informational responses, so wait directly for the request body.
-
Reject overly long HTTP Upgrade values: Accumulate the Upgrade header length across multiple parsing fragments, and return a parse error when it exceeds the thread temporary buffer capacity, avoiding out-of-bounds writes and heap corruption.
-
Server SSL context initialization: Always initialize the main context and register the SNI callback even when only SNI certificates are configured without a default certificate, and make
SSLContext::create()return failure and release the incompletely initialized context when certificate loading fails. -
Preserve request fields across parse calls: Standalone
Request::parse()now performs llhttp parsing of appended ranges on retained request storage, and rebuilds URL and header field spans across fragments, avoiding fragments being treated as complete fields or referencing freed pointers. -
Reject repeated calls to native resource constructors: The constructors of coroutine HTTP/HTTP2 clients, coroutine HTTP servers, Process Pool, Cookie, and Thread report an error on the second call, protecting the original native resources and object state from being replaced.
-
Server cpu_affinity_ignore handling: First validate that the option must be an array, then compute candidate CPUs based on the process's actual affinity mask, ignore invalid IDs, report an error when all available CPUs are excluded, and free that memory when the Server is destructed.
-
Terminate chunked responses after clearing trailers: Always append the trailing CRLF even if the public trailer property is empty or null, ensuring wire format integrity and connection reusability.
-
RSHUTDOWN cleanup of PHP timers: Use
std::vectorand a timer ID list instead of a pointer array allocated withemalloc, look up each one again before deleting it, avoiding timers remaining untilswoole_clean()due to a fatal error when request heap memory is exhausted. -
Register after-fork hook during MINIT: Move the registration of the after-fork hook from RINIT to MINIT, avoiding repeated mounting when requests are started and shut down repeatedly in thread mode.
-
curl multi preserves select readiness state:
curl_multi_execis driven bycurl_multi_socket_action, andselectis only responsible for waiting and recording readiness, covering polling, callback timing, removal, and reuse scenarios. -
HTTP/1 trailer completion fix: Determine whether sending is needed using the actual length of the built trailer buffer, preserve the trailing CRLF even for trailers containing only null values, and make
end()return false when trailer sending fails instead of being overwritten by a success result. -
Preserve incomplete packets on receive timeout: Under the length protocol, no longer clear the read buffer on timeout and do not set
offsetto the packet length, allowing subsequent reads to continue assembling the complete packet from the interruption point; HTTP/2 and socket fragmentation tests cover this behavior. -
Recognize PHP sockaddr length macros on BSD: Change the compilation condition for address traversal to
HAVE_SOCKADDR_SA_LENorHAVE_STRUCT_SOCKADDR_SA_LEN, fixing the check on BSD platforms. -
Coroutine exception delivery in SPL directory iteration: Save
EG(opline_before_exception)and the interrupt opline for each PHP coroutine, and restore the suspended user code through Zend's normal exception path on external cancellation; also support throw-style self-cancellation and reject non-coroutine main contexts. -
Reject global HTTP response headers in coroutines: At coroutine runtime, replace
http_get_last_response_headers()with a handler that indicates it is unsupported, and restore the native handler after runtime stops, avoiding request-level global headers polluting each other across coroutines. -
CPU affinity for worker application configuration: Extract
cpu_affinity_ignorevalidation into a separate helper function, and select CPU binding for event/task workers based on the actual allowed affinity mask before the worker startup callback; in THREAD mode bind the current pthread, and keep the master mask unchanged. -
Out-of-bounds read on empty PDO pgsql error message:
_pdo_pgsql_trim_message()first checks whether the length is 0 and directly returns an empty string, avoidingstrlen - 1underflowing toSIZE_MAXand then reading bytes before the buffer. -
Do not lose signals during signal handling: The sigaction fallback path fills
sa_maskfor non-safe handlers to block other signals, so that signals arriving during handling remain pending and are delivered after handling returns, fixing the issue where the master's SIGTERM is lost during SIGCHLD handling. -
Enforce EOF packet length limit: Immediately report
SW_ERROR_PACKAGE_LENGTH_TOO_LARGEwhen the first complete EOF packet exceedspackage_max_length, or when an unterminated buffer reaches/exceeds the limit; coroutine sockets, synchronous/asynchronous clients, split mode, and server protocols enforce this uniformly, preserving packets exactly equal to the limit and valid first packets in merged reads. -
Validate WebSocket handshake response headers: The coroutine HTTP client validates
Upgrade: websocket,Connection: Upgrade, andSec-WebSocket-Acceptin the 101 response (recomputed and compared using the request key); if invalid, the handshake fails and the connection is closed. -
UNIX datagram address ownership: When
recvfromhas no peer address, clear the cachedsun_path; during destruction, first refresh its own bound address withgetsocknamebefore unlinking, avoiding mistakenly deleting the peer socket file when releasing the receiver or exposing the previous peer address to PHP. -
write_func receives decompressed response body: Compressed responses are decompressed before being handed to
write_func; the callback receives plaintext chunks and the internal body buffer is cleared; covers gzip/deflate/br and compressed SSE streams. -
Safe buffer expansion for WebSocket compressed output:
Z_SYNC_FLUSHoutput may exceeddeflateBound(); change toextendfirst whenbytes_written + max_lengthexceeds capacity, and accumulatelengthaccording to the write position, avoiding out-of-bounds and length loss; add regression tests for incompressible payloads and control frames. -
Shared settings array isolation: Each
set()performsSEPARATE_ARRAYon thesettingproperty array before merging, avoiding in-place modification of a copy-on-write shared array, so that previously taken snapshots and caller-provided arrays remain unchanged; also remove the erroneous extra reference to the port object when inheriting settings across multiple ports. -
Preserve reload initiated in worker callbacks: The wait loop no longer deletes reload tasks during the
reload_initphase, and instead waits until the next initialization round fills in the worker snapshot before checking completion, avoiding reloads requested in callbacks being discarded prematurely. -
Backport adaptation for pending reload and regression cases: When there is already a pending reload in the queue, use
wait_processwithWNOHANGto avoid blocking, and fix thepid <= 0check; on the test side, reap child processes, drain accepted HTTP connections before closing listeners, and adapt the test runner's output limit handling. -
Free captured HTTP/1 Content-Type: Move the freeing of
content_typeout of the branch that only matches compressed types, so that it is also freed whenContent-Encodingis set and compression is disabled due to a mismatch, fixing a memory leak of about 1 KiB per request. -
无 futex 平台构建修复:把
sw_usleep改为标准usleep,解决该平台编译失败。 -
WebSocket 解码校验:解码器在解掩码前拒绝带 RSV1 的 CLOSE/PING/PONG 控制帧,阻止压缩控制帧进入接收流程。
-
WebSocket 编码校验:编码器拒绝分片或负载超过125字节的控制帧,并让
ping()在编码失败时返回 false 并设置SWOOLE_ERROR_WEBSOCKET_PACK_FAILED。 -
线程 stdio fd 泄漏:线程退出后手动关闭因
PHP_STREAM_FLAG_NO_CLOSE而未释放的 STDIN/STDOUT/STDERR 文件描述符。 -
Reactor 未注册 fd 查询:查询未注册 fd 时返回 null 而不再向 socket 映射插入空条目,并将访问器改为 const。
-
SOCKS5 目标主机长度校验:DNS 隧道改为校验目标主机长度不超过 255 字节,超长时按握手失败返回错误。
-
线程调度策略保持:
Thread::setPriority()未指定策略时先读取当前调度策略再设置优先级,修复使用非法-1策略的问题。 -
缓冲流读取修复:PHP 8.3 下当流已有缓冲数据时走非等待接收路径,让被 hook 的流直接返回缓冲数据而不等待新事件。
-
无 futex 系统原子等待:实现基于共享内存哈希表的原子等待注册表,用自旋锁替代互斥锁,并加入超时、代际通知和条目复用机制。
-
流写入超时上报:
fwrite遇 ETIMEDOUT 时不再打印错误通知,保留timed_out元数据且不置eof,仅对真正的写错误置 eof。 -
流读取超时错误保留:
fread遇 ETIMEDOUT 时返回失败(false)而非 0,使调用方能通过元数据识别超时,且不误置 eof。 -
Poll 分发 socket 身份保持:Poll reactor 在
set_events时额外保存每个 pollfd 对应的 Socket 指针,分发时直接使用该指针,避免 handler 中 fd 被复用后事件被派发给错误的 socket。 -
进程池消息总线复用:
start()在消息总线已存在时不再重复创建,使同一个进程池可以 shutdown 后再次 start 并正常投递消息。 -
BASE 事件池资源释放:多 worker BASE 服务器在 manager 结束后销毁事件进程池,并复用
create()已分配的消息箱,修复资源泄漏。 -
TCP 监听器可重绑定:
make_server_socket()只为 TCP 监听开启SO_REUSEADDR,避免 TIME_WAIT 阻止立即重启,同时不影响 Unix 和 UDP socket 行为。 -
ProcessPool 截断包处理:stream/task 协议要求长度前缀和包体都精确读满,短读视为不完整包并关闭连接,不再把复用缓冲区里的旧数据当作有效负载传给回调。
-
消息队列 key 范围校验:Process、ProcessPool、Server 三个入口在把 PHP 整数窄化为
key_t前先校验范围,超出key_t可表示范围的 key 被拒绝,无符号 32 位边界仍接受。 -
多部分上传临时文件错误:无法为 multipart 上传创建临时文件时,在文件信息中标记
UPLOAD_ERR_NO_TMP_DIR,避免把空上传当作成功文件交给 handler。 -
支持 HTTP QUERY 方法:在 HTTP/1 方法表中加入 QUERY,并让 URL 编码表单体走既有请求解析路径,普通服务器和协程服务器解析保持一致。
-
被 hook 的写操作应用流超时:
stream_set_timeout()设置超时时同时更新读和写两个协程 socket 截止时间,使阻塞的fwrite()不再超出配置的流超时。 -
协程 HTTP 客户端 socket 初始化:构造时把内部 socket zval 初始化为 null,使连接前调用
close()安全,并返回SWOOLE_ERROR_CLIENT_NO_CONNECTION。 -
DNS 无 service 时传 null:
getaddrinfo()在未指定 service 时传空指针而非空字符串,修复 musl(Alpine Linux)上返回 EAI_SERVICE 导致解析总是失败的问题。 -
禁用抢占时忽略外部中断:仅当抢占调度线程运行时才应用调度截止时间,防止其他扩展触发的信号中断在抢占关闭时使用过期上下文状态切换协程。
-
CPU 亲和性 ID 校验:每个亲和性条目只转换一次并用于校验、诊断和
CPU_SET,拒绝负 ID 和超出CPU_SETSIZE的 ID,Thread::setAffinity()把pthread_setaffinity_np的非零返回值都视为失败。 -
亲和性 ID 按 CPU 数量校验:在上一提交基础上把上限改为
SW_CPU_NUM(同时不超过CPU_SETSIZE),在 Linux 静默裁剪无效掩码前就拒绝超出可用 CPU 范围的 ID。 -
防止 worker 执行 manager 专属信号处理:信号处理中先校验当前进程 PID 等于 manager PID,避免新 fork 的 worker 短暂继承 manager 信号处理器后反复向自己广播 SIGWINCH。
-
保留协程 socket 原生错误:socket 调用失败后立即读取 errno 并保存在本地变量,
shutdown()和check_liveness()不再依赖可能被覆盖的 C 运行时 errno。 -
切换 hook 后初始化 PHP hook:从 native hook 切换到 PHP hook 时补上缺失的函数缓存初始化,使后续调用走
swoole_*PHP 函数而非空缓存。 -
Redis 服务器收包缓冲处理:读结尾 CRLF 前先检查长度,仅在缓冲区写满时才扩容,扩容计算不窄化并限制在
package_max_length内,修复分片请求解析。 -
部分设置保留包长度上限:协程 socket 的
set()未提供package_max_length时不再重置为默认值,保留当前上限。 -
非 Swoole 线程中发起 PHP 请求崩溃:
sw_is_main_thread()改用ZTS判断,并把任务临时目录的读写全部加sw_thread_lock保护,避免在非 Swoole 创建的线程中崩溃。 -
协程 HTTP 服务器请求边界与 100 Continue:分块请求缓冲区写满时扩容至上限、超限返回 413,改用 llhttp 完成事件精确判定请求结束并保留流水线字节,同时在等待请求体前发送一次 100 Continue。
-
HTTP/1.0 忽略 100-continue:只对 HTTP/1.1(version 101)请求发送 100 Continue 中间响应,HTTP/1.0 客户端不识别信息性响应故直接等请求体。
-
拒绝超长 HTTP Upgrade 值:跨多次解析片段累计 Upgrade 头长度,超过线程临时缓冲区容量时返回解析错误,避免写越界和堆损坏。
-
服务器 SSL 上下文初始化:仅配置 SNI 证书而无默认证书时也始终初始化主上下文并注册 SNI 回调,同时让
SSLContext::create()在证书加载失败时返回失败并释放未完成初始化的上下文。 -
跨解析调用保留请求字段:独立
Request::parse()改为在保留的请求存储上执行追加区间的 llhttp 解析,并跨片段重建 URL 和头部字段跨度,避免片段被当作完整字段或引用已释放的指针。 -
拒绝重复调用原生资源构造函数:协程 HTTP/HTTP2 客户端、协程 HTTP 服务器、Process Pool、Cookie、Thread 的构造函数第二次调用时报错,保护原有原生资源和对象状态不被替换。
-
Server 的 cpu_affinity_ignore 处理:先校验选项必须是数组,再基于进程实际亲和掩码计算候选 CPU,忽略无效 ID,排除全部可用 CPU 时报错,并在 Server 析构时释放该内存。
-
清理 trailer 后仍终止 chunked 响应:即使公开的 trailer 属性为空或为 null 也总是追加结尾 CRLF,保证 wire 格式完整和连接可复用。
-
RSHUTDOWN 清理 PHP 定时器:改用
std::vector和定时器 ID 列表而非emalloc的指针数组,逐个重新查找再删除,避免请求堆内存耗尽时致命错误导致定时器残留到swoole_clean()。 -
MINIT 阶段注册 fork 后 hook:把 after-fork hook 的注册从 RINIT 移到 MINIT,避免线程模式下重复请求启动/关闭时重复挂载。
-
curl multi 保留 select 就绪状态:
curl_multi_exec改用curl_multi_socket_action驱动,select只负责等待并记录就绪,并覆盖轮询、回调时序、移除和复用场景。 -
HTTP/1 trailer 完成修复:用已构建 trailer 缓冲区的实际长度判断是否需要发送,仅含 null 值的 trailer 也保留结尾 CRLF,且 trailer 发送失败时
end()返回 false 而不再被成功结果覆盖。 -
接收超时保留不完整包:length 协议下超时时不再清空读缓冲区,也不把
offset设为包长,让后续读取能从中断处继续拼出完整包;HTTP/2 和 socket 分片测试覆盖了该行为。 -
BSD 上识别 PHP sockaddr 长度宏:地址遍历的编译条件改为
HAVE_SOCKADDR_SA_LEN或HAVE_STRUCT_SOCKADDR_SA_LEN,修复 BSD 平台上的判断。 -
SPL 目录迭代中的协程异常投递:为每个 PHP 协程保存
EG(opline_before_exception)和中断 opline,外部取消时按 Zend 的正常异常路径恢复被挂起的用户代码;同时支持抛出式自我取消并拒绝非协程的主上下文。 -
协程中拒绝全局 HTTP 响应头:协程运行时把
http_get_last_response_headers()替换为提示不支持的处理函数,运行时停止后恢复原生处理,避免请求级全局头在协程间互相污染。 -
worker 应用配置的 CPU 亲和性:把
cpu_affinity_ignore校验抽成独立辅助函数,并在 worker 启动回调前按实际允许的亲和掩码为事件/任务 worker 选 CPU 绑定,THREAD 模式绑定当前 pthread,master 掩码保持不变。 -
空 PDO pgsql 错误消息越界读:
_pdo_pgsql_trim_message()先判断长度为 0 并直接返回空字符串,避免strlen - 1下溢成SIZE_MAX后读缓冲区之前的字节。 -
信号处理期间不丢信号:sigaction 回退路径为非安全处理器填充
sa_mask阻塞其他信号,使处理期间到达的信号保持 pending 并在处理返回后投递,修复 master 的 SIGTERM 在 SIGCHLD 处理中被丢弃的问题。 -
强制 EOF 包长度上限:首个完整 EOF 包超过
package_max_length、或未终止缓冲达到/超过上限时立即报SW_ERROR_PACKAGE_LENGTH_TOO_LARGE;协程 socket、同步/异步客户端、split 模式和 server 协议统一执行,保留恰好等于上限的包和合并读中的有效首包。 -
校验 WebSocket 握手响应头:协程 HTTP 客户端校验 101 响应中的
Upgrade: websocket、Connection: Upgrade及Sec-WebSocket-Accept(用请求 key 重新计算比对),不合法即握手失败并关闭连接。 -
UNIX datagram 地址归属:
recvfrom无对端地址时清空缓存的sun_path,析构时先用getsockname刷新自身绑定地址再 unlink,避免释放接收方时误删对端 socket 文件、或把上个对端地址暴露给 PHP。 -
write_func 收到解压后响应体:压缩响应在交给
write_func前先解压,回调拿到明文分块并清空内部 body 缓冲;覆盖 gzip/deflate/br 及压缩 SSE 流。 -
WebSocket 压缩输出缓冲安全扩容:
Z_SYNC_FLUSH输出可能超过deflateBound(),改为在bytes_written + max_length超出容量时先extend,并按写入位置累加length,避免越界和长度丢失;补充不可压缩负载与控制帧回归。 -
共享设置数组隔离:各
set()在合并前对setting属性数组执行SEPARATE_ARRAY,避免写时复制共享数组被就地修改,使之前取出的快照和调用方传入的数组保持不变;同时去掉多端口继承设置时对端口对象的误增引用。 -
保留 worker 回调中发起的 reload:wait 循环在
reload_init阶段不再删除 reload 任务,等下一轮初始化填好 worker 快照后再判断完成,避免回调中请求的重载被提前丢弃。 -
回移适配待处理 reload 与回归用例:队列中已有待处理 reload 时改用
WNOHANG的wait_process避免阻塞,并修正pid <= 0判断;测试侧回收子进程、在关闭监听前排空已接受的 HTTP 连接,测试运行器输出超限处理也做了适配。 -
释放捕获的 HTTP/1 Content-Type:把
content_type的释放移出仅压缩类型匹配的分支,在设置了Content-Encoding、因不匹配而禁用压缩时也会释放,修复每请求约 1 KiB 的内存泄漏。