aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/drivers/unix
diff options
context:
space:
mode:
authorMikael Pettersson <[email protected]>2014-05-14 16:23:02 +0200
committerMikael Pettersson <[email protected]>2014-05-14 16:51:15 +0200
commit78540afe8d4a15fe3d6c42208b82bde546e4c0c8 (patch)
tree471855440f987e13a8e4ba9efd6ad717ed7631eb /erts/emulator/drivers/unix
parent5ade234d37600ea80dbb309f431c615937ea253d (diff)
downloadotp-78540afe8d4a15fe3d6c42208b82bde546e4c0c8.tar.gz
otp-78540afe8d4a15fe3d6c42208b82bde546e4c0c8.tar.bz2
otp-78540afe8d4a15fe3d6c42208b82bde546e4c0c8.zip
Fix efile_openfile() to handle stat() failure
If the initial stat() fails then efile_openfile() will still proceed to open() the file. If that succeeds and the caller passed a non-NULL pSize, then it will copy bogus data from the statbuf into *pSize. This has been observed to cause file:read_file/1 to return truncated file data with no error indication. The use case involved a large file system mounted via NFS, with some directories containing large number of files, and NFS mount options that allow the NFS client to return EIO if the NFS server does not respond quickly enough. Depending on the caching state of the client and server machines, a few stat() calls (fewer than 1 per 10 million) would take long enough to trigger EIO errors, but subsequent open() calls would succeed, and read_file/1 would return truncated data. This sequence of events has been observed via "strace" on beam.smp. Signed-off-by: Mikael Pettersson <[email protected]>
Diffstat (limited to 'erts/emulator/drivers/unix')
-rw-r--r--erts/emulator/drivers/unix/unix_efile.c7
1 files changed, 6 insertions, 1 deletions
diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c
index 42f41c5f3d..878beb055b 100644
--- a/erts/emulator/drivers/unix/unix_efile.c
+++ b/erts/emulator/drivers/unix/unix_efile.c
@@ -360,7 +360,12 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */
int fd;
int mode; /* Open mode. */
- if (stat(name, &statbuf) >= 0 && !ISREG(statbuf)) {
+ if (stat(name, &statbuf) < 0) {
+ /* statbuf is undefined: if the caller depends on it,
+ i.e. invoke_read_file(), fail the call immediately */
+ if (pSize && flags == EFILE_MODE_READ)
+ return check_error(-1, errInfo);
+ } else if (!ISREG(statbuf)) {
/*
* For UNIX only, here is some ugly code to allow
* /dev/null to be opened as a file.