From 870a4b24e73f5970dea1b5f3ba9c58393100c343 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Mon, 24 Aug 2026 12:45:45 -0400 Subject: [PATCH] [Session] Truncate session file after successful write The files save handler ftruncated the session file to 0 before writing, so a write that failed returned FAILURE with the previous session data already destroyed. Write first and truncate the old tail to the new length only after the full buffer was written successfully. Sibling audit: PS_WRITE_FUNC/PS_UPDATE_FUNC callers and the read path are unaffected; the empty-write destroy path truncates identically. --- NEWS | 4 ++ ext/session/mod_files.c | 9 ++- .../session_write_failure_keeps_data.phpt | 58 +++++++++++++++++++ 3 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 ext/session/tests/session_write_failure_keeps_data.phpt diff --git a/NEWS b/NEWS index 3346d38ea898..4410bfc0001a 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,10 @@ PHP NEWS registrations are freed while still reachable from the cycle collector. (Ilia Alshanetsky) +- Session: + . Fixed session data loss in the files save handler when writing the session + file fails after it was already truncated. (Ilia Alshanetsky) + 24 Sep 2026, PHP 8.4.26 diff --git a/ext/session/mod_files.c b/ext/session/mod_files.c index 74e77973405b..a751c8a4daf3 100644 --- a/ext/session/mod_files.c +++ b/ext/session/mod_files.c @@ -236,11 +236,6 @@ static zend_result ps_files_write(ps_files *data, zend_string *key, zend_string return FAILURE; } - /* Truncate file if the amount of new data is smaller than the existing data set. */ - if (ZSTR_LEN(val) < data->st_size) { - php_ignore_value(ftruncate(data->fd, 0)); - } - #ifdef HAVE_PWRITE n = pwrite(data->fd, ZSTR_VAL(val), ZSTR_LEN(val), 0); #else @@ -274,6 +269,10 @@ static zend_result ps_files_write(ps_files *data, zend_string *key, zend_string return FAILURE; } + if (ZSTR_LEN(val) < data->st_size) { + php_ignore_value(ftruncate(data->fd, ZSTR_LEN(val))); + } + return SUCCESS; } diff --git a/ext/session/tests/session_write_failure_keeps_data.phpt b/ext/session/tests/session_write_failure_keeps_data.phpt new file mode 100644 index 000000000000..e6ca96a4a776 --- /dev/null +++ b/ext/session/tests/session_write_failure_keeps_data.phpt @@ -0,0 +1,58 @@ +--TEST-- +Session files handler must not truncate session file when write fails +--EXTENSIONS-- +session +posix +pcntl +--INI-- +error_reporting=E_ALL +display_errors=1 +session.use_strict_mode=0 +--FILE-- + +--CLEAN-- + +--EXPECT-- +int(8207) +bool(true) +bool(true) +done