Skip to content

Commit ea1287b

Browse files
authored
Log the cause of error when opcache cannot write to file cache (#9258)
1 parent fb242f4 commit ea1287b

File tree

2 files changed

+83
-8
lines changed

2 files changed

+83
-8
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
--TEST--
2+
File cache error 001
3+
--EXTENSIONS--
4+
opcache
5+
posix
6+
pcntl
7+
--INI--
8+
opcache.enable_cli=1
9+
opcache.file_cache={TMP}
10+
opcache.log_verbosity_level=2
11+
--SKIPIF--
12+
<?php
13+
if (!posix_setrlimit(POSIX_RLIMIT_FSIZE, 1, 1)) die('skip Test requires setrlimit(RLIMIT_FSIZE) to work');
14+
if (ini_parse_quantity(ini_get('opcache.jit_buffer_size')) !== 0) die('skip File cache is disabled when JIT is on');
15+
?>
16+
--FILE--
17+
<?php
18+
19+
// Create new file to ensure that it's not cached accross test runs
20+
$file = tempnam(sys_get_temp_dir(), 'file_cache_error');
21+
register_shutdown_function(function () use ($file) {
22+
unlink($file);
23+
});
24+
file_put_contents($file, '<?php echo "OK";');
25+
touch($file, time() - 3600);
26+
27+
// Some systems will raise SIGXFSZ when RLIMIT_FSIZE is exceeded
28+
if (defined('SIGXFSZ')) {
29+
pcntl_signal(SIGXFSZ, SIG_IGN);
30+
}
31+
32+
// Should cause writing to cache file to fail
33+
var_dump(posix_setrlimit(POSIX_RLIMIT_FSIZE, 1, 1));
34+
35+
// Will attempt to write to cache file, and fail
36+
require $file;
37+
?>
38+
--EXPECTF--
39+
bool(true)
40+
%sWarning opcache cannot write to file %s: %s
41+
42+
OK

ext/opcache/zend_file_cache.c

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,23 +1004,56 @@ static char *zend_file_cache_get_bin_file_path(zend_string *script_path)
10041004
/**
10051005
* Helper function for zend_file_cache_script_store().
10061006
*
1007-
* @return true on success, false on error
1007+
* @return true on success, false on error and errno is set to indicate the cause of the error
10081008
*/
10091009
static bool zend_file_cache_script_write(int fd, const zend_persistent_script *script, const zend_file_cache_metainfo *info, const void *buf, const zend_string *s)
10101010
{
1011+
ssize_t written;
1012+
const ssize_t total_size = (ssize_t)(sizeof(*info) + script->size + info->str_size);
1013+
10111014
#ifdef HAVE_SYS_UIO_H
10121015
const struct iovec vec[] = {
10131016
{ .iov_base = (void *)info, .iov_len = sizeof(*info) },
10141017
{ .iov_base = (void *)buf, .iov_len = script->size },
10151018
{ .iov_base = (void *)ZSTR_VAL(s), .iov_len = info->str_size },
10161019
};
10171020

1018-
return writev(fd, vec, sizeof(vec) / sizeof(vec[0])) == (ssize_t)(sizeof(*info) + script->size + info->str_size);
1021+
written = writev(fd, vec, sizeof(vec) / sizeof(vec[0]));
1022+
if (EXPECTED(written == total_size)) {
1023+
return true;
1024+
}
1025+
1026+
errno = written == -1 ? errno : EAGAIN;
1027+
return false;
10191028
#else
1020-
return ZEND_LONG_MAX >= (zend_long)(sizeof(*info) + script->size + info->str_size) &&
1021-
write(fd, info, sizeof(*info)) == sizeof(*info) &&
1022-
write(fd, buf, script->size) == script->size &&
1023-
write(fd, ZSTR_VAL(s), info->str_size) == info->str_size;
1029+
if (UNEXPECTED(ZEND_LONG_MAX < (zend_long)total_size)) {
1030+
# ifdef EFBIG
1031+
errno = EFBIG;
1032+
# else
1033+
errno = ERANGE;
1034+
# endif
1035+
return false;
1036+
}
1037+
1038+
written = write(fd, info, sizeof(*info));
1039+
if (UNEXPECTED(written != sizeof(*info))) {
1040+
errno = written == -1 ? errno : EAGAIN;
1041+
return false;
1042+
}
1043+
1044+
written = write(fd, buf, script->size);
1045+
if (UNEXPECTED(written != script->size)) {
1046+
errno = written == -1 ? errno : EAGAIN;
1047+
return false;
1048+
}
1049+
1050+
written = write(fd, ZSTR_VAL(s), info->str_size);
1051+
if (UNEXPECTED(written != info->str_size)) {
1052+
errno = written == -1 ? errno : EAGAIN;
1053+
return false;
1054+
}
1055+
1056+
return true;
10241057
#endif
10251058
}
10261059

@@ -1095,7 +1128,7 @@ int zend_file_cache_script_store(zend_persistent_script *script, bool in_shm)
10951128
#endif
10961129

10971130
if (!zend_file_cache_script_write(fd, script, &info, buf, s)) {
1098-
zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot write to file '%s'\n", filename);
1131+
zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot write to file '%s': %s\n", filename, strerror(errno));
10991132
zend_string_release_ex(s, 0);
11001133
close(fd);
11011134
efree(mem);
@@ -1107,7 +1140,7 @@ int zend_file_cache_script_store(zend_persistent_script *script, bool in_shm)
11071140
zend_string_release_ex(s, 0);
11081141
efree(mem);
11091142
if (zend_file_cache_flock(fd, LOCK_UN) != 0) {
1110-
zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename);
1143+
zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s': %s\n", filename, strerror(errno));
11111144
}
11121145
close(fd);
11131146
efree(filename);

0 commit comments

Comments
 (0)