godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.21k stars 21.04k forks source link

store_string can corrupt files on Windows #77398

Open tcoxon opened 1 year ago

tcoxon commented 1 year ago

Godot version

3.5.1.stable

System information

Windows

Issue description

A handful of Cassette Beasts players have reported their save files become corrupt on Windows.

In Cassette Beasts save files are written on a background thread using File.open_compressed and File.store_string. Files are first saved to a temporary path, then flushed and closed once the game has finished writing them. If no error codes were returned from the File methods, it then uses Directory.copy to replace the save file.

When corruption occurs, both the canonical save file and the temporary file are 0 bytes long. No error codes are returned from the File or Directory methods, and yet this message appears repeatedly in the player's logs:

ERROR: Condition "fwrite(p_src, 1, p_length, f) != (size_t)p_length" is true.
   at: FileAccessWindows::store_buffer (drivers\windows\file_access_windows.cpp:301) - Condition "fwrite(p_src, 1, p_length, f) != (size_t)p_length" is true.

Microsoft's documentation for fwrite says that the number of bytes written can be less than the number given if an error occurs. Godot should return an error code when this happens so that games can handle errors and attempt to recover, instead of logging an error and returning OK.

I'm not sure what the error is in these cases, so I don't know exactly how to reproduce this. I've checked the obvious stuff with players - disk space, etc. and haven't found any particular reason for it.

Steps to reproduce

As mentioned, I'm unsure of the reproduction steps. However I have attached a minimal project that recreates every step along the path that Cassette Beasts takes when it writes a save file.

Minimal reproduction project

file_corruption.zip

akien-mga commented 1 year ago

CC @bruvzg