Priority: P2: Important
Affects Version/s: 5.11.2, 5.13.0 Beta 1
Fix Version/s: None
Component/s: Core: I/O
Environment:Tested Linux 4.20.15, glibc 2.27, but should not be platform-specific
QSaveFile saves any write errors in its reimplementation of QSaveFile::writeData() to d->writeError so that QSaveFile::commit() can fail before the atomic file replacement.
However, there is no equivalent handling for QSaveFile::flush() ( = QFileDevice::flush()). Any errors from flush() are not reflected in d->writeError and commit() will proceed with the file replacement as usual.
This is a problem even if flush() is not called by the user, as QSaveFile::commit() calls QFileDevice::close() which calls QFileDevice::flush().
The above most severely breaks QSaveFile on filesystems that allow creation of files when the file system is full, e.g. common Linux filesystems ext4 and tmpfs, as a very simple testcase (write short file while FS full) causes the target file to be replaced with a zero-sized file:
Other filesystems are affected as well if there is enough space to create the file but not enough space to write all the data out. I did not check which group Win/NTFS falls on. The issue is in QSaveFile platform-agnostic code.
Any other write error encountered by flush() is also ignored by commit().
Attached is a full testcase application, the issue can be reproduced with it on Linux as follows:
File was truncated and QSaveFile reported no errors.
The issue is present in dev branch as well.
Handling full partition is explicitly mentioned in QSaveFile documentation as supported case.