diff --git a/core/libs/prx/libc/include/FileStream.hpp b/core/libs/prx/libc/include/FileStream.hpp index 7a1b467be..9fff6280e 100644 --- a/core/libs/prx/libc/include/FileStream.hpp +++ b/core/libs/prx/libc/include/FileStream.hpp @@ -42,7 +42,7 @@ class FileStream { std::byte _reserved[256 - sizeof(GuestFilePrefix)]{}; std::FILE* _handle; bool _dynamic; - bool encodingError = false; + bool guestError = false; public: explicit FileStream(std::FILE* handle, bool dynamic = false) : _handle(handle), _dynamic(dynamic) { @@ -72,7 +72,7 @@ public: bool Reopen(const std::filesystem::path& filename, const char* mode) { auto* previous = GetHandle(); _guest = {}; - encodingError = false; + guestError = false; #ifdef _WIN32 std::wstring wideMode; for (const char character : std::string_view(mode)) wideMode.push_back(static_cast(character)); @@ -94,7 +94,7 @@ public: _guest.readRemaining = 0; _guest.writeRemaining = 0; _guest.flags = static_cast((_guest.flags & ~0x60) | - (std::feof(GetHandle()) ? 0x20 : 0) | (std::ferror(GetHandle()) || encodingError ? 0x40 : 0)); + (std::feof(GetHandle()) ? 0x20 : 0) | (std::ferror(GetHandle()) || guestError ? 0x40 : 0)); } void SyncUnlockedStatus() { @@ -108,17 +108,17 @@ public: const bool error = ::ferror_unlocked(GetHandle()) != 0; #endif _guest.flags = static_cast((_guest.flags & ~0x60) | - (endOfFile ? 0x20 : 0) | (error || encodingError ? 0x40 : 0)); + (endOfFile ? 0x20 : 0) | (error || guestError ? 0x40 : 0)); } - void SetEncodingError() { - encodingError = true; + void SetError() { + guestError = true; SyncStatus(); } void ClearError() { std::clearerr(GetHandle()); - encodingError = false; + guestError = false; SyncStatus(); } diff --git a/core/libs/prx/libc/src/StandardStreams.cpp b/core/libs/prx/libc/src/StandardStreams.cpp index 1d51cdb37..69e24de20 100644 --- a/core/libs/prx/libc/src/StandardStreams.cpp +++ b/core/libs/prx/libc/src/StandardStreams.cpp @@ -27,7 +27,7 @@ std::int32_t APS5_VABI ungetwc_nid_postfix(std::int32_t value, FileStream* strea if (value == -1) return -1; if (value < 0 || value > 255) { errno = 86; - stream->SetEncodingError(); + stream->SetError(); return -1; } const int result = std::ungetc(value, GetNativeStream(stream)); @@ -69,6 +69,11 @@ int APS5_VABI ungetc_nid_postfix(int value, FileStream* stream) { return result; } char* APS5_VABI fgets_nid_postfix(char* buffer, int size, FileStream* stream) { + if (size <= 0) { + stream->SetError(); + errno = 22; + return nullptr; + } auto* result = std::fgets(buffer, size, GetNativeStream(stream)); stream->SyncStatus(); return result; diff --git a/core/libs/tests/GuestStandardStreams.cpp b/core/libs/tests/GuestStandardStreams.cpp index 5de08e2cb..3173ea8d9 100644 --- a/core/libs/tests/GuestStandardStreams.cpp +++ b/core/libs/tests/GuestStandardStreams.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -121,7 +122,7 @@ static void CheckUnlockedStreams() { Require(std::ungetc('Q', stream.GetHandle()) == 'Q'); Require(getc_unlocked_nid_postfix(&stream) == 'Q' && !(guest.flags & 0x20)); std::rewind(stream.GetHandle()); - stream.SetEncodingError(); + stream.SetError(); Require(putc_unlocked_nid_postfix('R', &stream) == 'R' && (guest.flags & 0x40)); clearerr_nid_postfix(&stream); Require(!(guest.flags & 0x40)); @@ -229,6 +230,27 @@ static void CheckUnlockedStreamLock(bool write) { stream.Close(); } +static void CheckFgetsSize() { + FileStream stream(std::tmpfile()); + Require(fwrite_nid_postfix("line\n", 1, 5, &stream) == 5); + rewind_nid_postfix(&stream); + for (const int size : {0, -1, std::numeric_limits::min()}) { + char buffer[8]; + std::memset(buffer, '!', sizeof(buffer)); + *__error_nid_postfix() = 0; + Require(fgets_nid_postfix(buffer, size, &stream) == nullptr); + Require(*__error_nid_postfix() == 22 && ferror_nid_postfix(&stream) != 0 && feof_nid_postfix(&stream) == 0); + Require(buffer[0] == '!' && ftello_nid_postfix(&stream) == 0); + Require(ferror_nid_postfix(&stream) != 0); + clearerr_nid_postfix(&stream); + Require(ferror_nid_postfix(&stream) == 0); + } + char line[8]{}; + Require(fgets_nid_postfix(line, sizeof(line), &stream) == line && std::strcmp(line, "line\n") == 0); + Require(ferror_nid_postfix(&stream) == 0); + stream.Close(); +} + static void CheckRewind() { FileStream stream(std::tmpfile()); Require(fwrite_nid_postfix("ab", 1, 2, &stream) == 2); @@ -239,7 +261,7 @@ static void CheckRewind() { rewind_nid_postfix(&stream); Require(fgetc_nid_postfix(&stream) == 'a' && fgetc_nid_postfix(&stream) == 'b' && fgetc_nid_postfix(&stream) == EOF); Require(feof_nid_postfix(&stream) != 0); - stream.SetEncodingError(); + stream.SetError(); Require(ferror_nid_postfix(&stream) != 0); rewind_nid_postfix(&stream); Require(feof_nid_postfix(&stream) == 0 && ferror_nid_postfix(&stream) == 0 && fgetc_nid_postfix(&stream) == 'a'); @@ -511,6 +533,7 @@ int main() { Require(fgetc_nid_postfix(&locked) == 'A' && fgetc_nid_postfix(&locked) == 'B'); locked.Close(); CheckRewind(); + CheckFgetsSize(); CheckUnlockedStreams(); CheckUnlockedStreamLock(false); CheckUnlockedStreamLock(true);