From 560ca69ae833f8493e279c76859f57d915f6867b Mon Sep 17 00:00:00 2001 From: Tom Hempel Date: Fri, 12 Jun 2026 22:14:51 +0200 Subject: [PATCH] refactored memfd handling to use FFI for Linux, added qdb_close_fd function --- lib/read_db_cache.php | 55 +++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/lib/read_db_cache.php b/lib/read_db_cache.php index 09a1759..6936c8a 100644 --- a/lib/read_db_cache.php +++ b/lib/read_db_cache.php @@ -99,24 +99,53 @@ function qdb_read_materialize_decrypted_db(): array { return [$pdo, $fallback, -1]; } +/** + * @return FFI|null libc handle with memfd_create + close (Linux only) + */ +function qdb_linux_libc_ffi() { + static $ffi = null; + if ($ffi !== null) { + return $ffi; + } + if (PHP_OS_FAMILY !== 'Linux' || !extension_loaded('ffi')) { + return null; + } + try { + $ffi = FFI::cdef( + 'int memfd_create(const char *name, unsigned int flags); + int close(int fd);', + 'libc.so.6' + ); + } catch (Throwable $e) { + error_log('qdb_linux_libc_ffi: ' . $e->getMessage()); + return null; + } + return $ffi; +} + +function qdb_close_fd(int $fd): void { + if ($fd < 0) { + return; + } + if (function_exists('posix_close')) { + @posix_close($fd); + return; + } + $ffi = qdb_linux_libc_ffi(); + if ($ffi !== null) { + $ffi->close($fd); + } +} + /** * @return array{0: int, 1: string}|null [fd, /proc/self/fd/N] */ function qdb_memfd_write(string $bytes): ?array { - if (PHP_OS_FAMILY !== 'Linux') { + $ffi = qdb_linux_libc_ffi(); + if ($ffi === null) { return null; } - if (!extension_loaded('ffi')) { - return null; - } - static $ffi = null; try { - if ($ffi === null) { - $ffi = FFI::cdef( - 'int memfd_create(const char *name, unsigned int flags);', - 'libc.so.6' - ); - } $MFD_CLOEXEC = 1; $fd = (int)$ffi->memfd_create('qdb_read', $MFD_CLOEXEC); if ($fd < 0) { @@ -124,7 +153,7 @@ function qdb_memfd_write(string $bytes): ?array { } $written = @file_put_contents('/proc/self/fd/' . $fd, $bytes); if ($written === false || $written !== strlen($bytes)) { - @close($fd); + qdb_close_fd($fd); return null; } return [$fd, '/proc/self/fd/' . $fd]; @@ -204,7 +233,7 @@ function qdb_read_cache_reset(): void { $state['signature'] = ''; $state['pdo'] = null; if ($state['memfdFd'] >= 0) { - @close($state['memfdFd']); + qdb_close_fd($state['memfdFd']); } $state['memfdFd'] = -1; if ($state['memfdPath'] !== '' && is_file($state['memfdPath'])) {