Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion core/libs/prx/libc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -390,8 +390,9 @@ if(BUILD_TESTING)
target_link_libraries(guest_standard_stream_tests PRIVATE libc)
configure_windows_unwind(guest_standard_stream_tests)
add_test(NAME guest_standard_streams COMMAND guest_standard_stream_tests)
add_test(NAME guest_standard_streams_closed_stdout COMMAND guest_standard_stream_tests --closed-stdout)
if(WIN32)
set_tests_properties(guest_standard_streams PROPERTIES ENVIRONMENT_MODIFICATION
set_tests_properties(guest_standard_streams guest_standard_streams_closed_stdout PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
add_test_executable(file_streams_tests ${LIBS_INCLUDE_DIR}/tests/FileStreams.cpp)
Expand Down
7 changes: 7 additions & 0 deletions core/libs/prx/libc/include/FileStream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ class FileStream {
return _handle;
}

bool IsOpen() const {
return _handle != nullptr;
}

bool IsDynamic() const {
return _dynamic;
}
Expand Down Expand Up @@ -103,13 +107,15 @@ class FileStream {
return true;
}
void SyncStatus() {
if (!_handle) return;
_guest.readRemaining = 0;
_guest.writeRemaining = 0;
_guest.flags = static_cast<std::int16_t>((_guest.flags & ~0x60) |
(std::feof(GetHandle()) ? 0x20 : 0) | (std::ferror(GetHandle()) || guestError ? 0x40 : 0));
}

void SyncUnlockedStatus() {
if (!_handle) return;
_guest.readRemaining = 0;
_guest.writeRemaining = 0;
#ifdef _WIN32
Expand All @@ -129,6 +135,7 @@ class FileStream {
}

void ClearError() {
if (!_handle) return;
std::clearerr(GetHandle());
guestError = false;
SyncStatus();
Expand Down
11 changes: 11 additions & 0 deletions core/libs/prx/libc/src/FileAndHeap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,11 @@ int APS5_VABI fopen_s_nid_postfix(FileStream** result, const char* filename, con
}

int APS5_VABI fclose_nid_postfix(FileStream* stream) {
if (stream && !stream->IsOpen()) {
std::unique_ptr<FileStream> owner(stream->IsDynamic() ? stream : nullptr);
errno = 9;
return -1;
}
GetNativeStream(stream);
std::unique_ptr<FileStream> owner(stream->IsDynamic() ? stream : nullptr);
return stream->Close();
Expand Down Expand Up @@ -357,6 +362,7 @@ FileStream* APS5_VABI _ZSt7_FiopenPKcNSt5_IosbIiE9_OpenmodeEi_nid_postfix(const
}

size_t APS5_VABI fread_nid_postfix(void* buffer, size_t size, size_t count, FileStream* stream) {
if (stream && !stream->IsOpen()) { errno = 9; return 0; }
auto* handle = GetNativeStream(stream);
if (size == 0 || count == 0) return 0;
if (!buffer) throw std::runtime_error("fread: null buffer");
Expand All @@ -371,6 +377,7 @@ size_t APS5_VABI fread_nid_postfix(void* buffer, size_t size, size_t count, File
}

size_t APS5_VABI fwrite_nid_postfix(const void* buffer, size_t size, size_t count, FileStream* stream) {
if (stream && !stream->IsOpen()) { errno = 9; return 0; }
auto* handle = GetNativeStream(stream);
if (size == 0 || count == 0) return 0;
if (!buffer) throw std::runtime_error("fwrite: null buffer");
Expand All @@ -380,6 +387,7 @@ size_t APS5_VABI fwrite_nid_postfix(const void* buffer, size_t size, size_t coun
}

int APS5_VABI fseeko_nid_postfix(FileStream* stream, std::int64_t offset, int origin) {
if (stream && !stream->IsOpen()) { errno = 9; return -1; }
if (origin != SEEK_SET && origin != SEEK_CUR && origin != SEEK_END) { errno = 22; return -1; }
#ifdef _WIN32
auto* native = GetNativeStream(stream);
Expand All @@ -396,6 +404,7 @@ int APS5_VABI fseeko_nid_postfix(FileStream* stream, std::int64_t offset, int or
}

std::int64_t APS5_VABI ftello_nid_postfix(FileStream* stream) {
if (stream && !stream->IsOpen()) { errno = 9; return -1; }
#ifdef _WIN32
auto* native = GetNativeStream(stream);
if (IsPipeStream(native)) { errno = 29; return -1; }
Expand Down Expand Up @@ -435,12 +444,14 @@ void APS5_VABI rewind_nid_postfix(FileStream* stream) {

int APS5_VABI fputs_nid_postfix(const char* str, FileStream* stream) {
if (!str) throw std::runtime_error("fputs: null string");
if (stream && !stream->IsOpen()) { errno = 9; return -1; }
const int result = std::fputs(str, GetNativeStream(stream));
stream->SyncStatus();
return result;
}

int APS5_VABI fflush_nid_postfix(FileStream* stream) {
if (stream && !stream->IsOpen()) { errno = 9; return -1; }
std::FILE* native = stream ? GetNativeStream(stream) : nullptr;
#ifdef __linux__
if (native && !__fwriting(native)) return 0;
Expand Down
8 changes: 8 additions & 0 deletions core/libs/prx/libc/src/Formatting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ int APS5_VABI vasprintf_nid_postfix(char** destination, const char* format, VaLi
}

int APS5_VABI vfprintf_nid_postfix(FileStream* stream, const char* format, VaList* args) {
if (stream && !stream->IsOpen()) { errno = 9; return -1; }
auto* native = GetNativeStream(stream);
#ifdef _WIN32
std::string buffer;
Expand Down Expand Up @@ -280,6 +281,7 @@ int APS5_VABI fprintf_nid_postfix(FileStream* stream, const char* format, ...) {
}

int APS5_VABI fscanf_nid_postfix(FileStream* stream, const char* format, ...) {
if (stream && !stream->IsOpen()) { errno = 9; return -1; }
auto* native = GetNativeStream(stream);
#ifdef _WIN32
__builtin_sysv_va_list args;
Expand All @@ -300,6 +302,7 @@ int APS5_VABI fscanf_nid_postfix(FileStream* stream, const char* format, ...) {
#ifdef _WIN32

int APS5_VABI printf_nid_postfix(const char* format, ...) {
if (!_Stdout_nid_postfix.IsOpen()) { errno = 9; return -1; }
__builtin_sysv_va_list args;
__builtin_sysv_va_start(args, format);
const int result = LibcDetail::PrintWindows(format, args);
Expand All @@ -308,6 +311,7 @@ int APS5_VABI printf_nid_postfix(const char* format, ...) {
}

int APS5_VABI libc_printf_nid_postfix(const char* format, ...) {
if (!_Stdout_nid_postfix.IsOpen()) { errno = 9; return -1; }
__builtin_sysv_va_list args;
__builtin_sysv_va_start(args, format);
const int result = LibcDetail::PrintWindows(format, args);
Expand All @@ -334,6 +338,7 @@ int APS5_VABI sprintf_nid_postfix(char* buffer, const char* format, ...) {
#else

int APS5_VABI printf_nid_postfix(const char* format, ...) {
if (!_Stdout_nid_postfix.IsOpen()) { errno = 9; return -1; }
std::va_list args;
va_start(args, format);
const int result = HasGuestWideFormat(format) ? LibcDetail::PrintWindows(format, args) : std::vprintf(format, args);
Expand All @@ -342,6 +347,7 @@ int APS5_VABI printf_nid_postfix(const char* format, ...) {
}

int APS5_VABI libc_printf_nid_postfix(const char* format, ...) {
if (!_Stdout_nid_postfix.IsOpen()) { errno = 9; return -1; }
std::va_list args;
va_start(args, format);
const int result = HasGuestWideFormat(format) ? LibcDetail::PrintWindows(format, args) : std::vprintf(format, args);
Expand Down Expand Up @@ -423,6 +429,7 @@ int APS5_VABI sscanf_s_nid_postfix(const char* buffer, const char* format, ...)
#endif

int APS5_VABI vprintf_nid_postfix(const char* str, VaList* c) {
if (!_Stdout_nid_postfix.IsOpen()) { errno = 9; return -1; }
#ifdef _WIN32
return LibcDetail::PrintWindows(str, c);
#else
Expand Down Expand Up @@ -541,6 +548,7 @@ int APS5_VABI printf_s_nid_postfix(const char* format, ...) {
#endif

int APS5_VABI puts_nid_postfix(const char* s) {
if (!_Stdout_nid_postfix.IsOpen()) { errno = 9; return -1; }
return std::puts(s);
}

Expand Down
8 changes: 8 additions & 0 deletions core/libs/prx/libc/src/StandardStreams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ FileStream* __stderrp_nid_postfix = &_Stderr_nid_postfix;
int __isthreaded_nid_postfix = 1;

int APS5_VABI fgetc_nid_postfix(FileStream* stream) {
if (stream && !stream->IsOpen()) { errno = 9; return -1; }
const int result = std::fgetc(GetNativeStream(stream));
stream->SyncStatus();
return result;
Expand All @@ -36,6 +37,7 @@ std::int32_t APS5_VABI ungetwc_nid_postfix(std::int32_t value, FileStream* strea
}
int APS5_VABI getc_nid_postfix(FileStream* stream) { return fgetc_nid_postfix(stream); }
int APS5_VABI getc_unlocked_nid_postfix(FileStream* stream) {
if (stream && !stream->IsOpen()) { errno = 9; return -1; }
#ifdef _WIN32
const int result = _fgetc_nolock(GetNativeStream(stream));
#else
Expand All @@ -47,12 +49,14 @@ int APS5_VABI getc_unlocked_nid_postfix(FileStream* stream) {
int APS5_VABI __srget_nid_postfix(FileStream* stream) { return fgetc_nid_postfix(stream); }
int APS5_VABI getchar_nid_postfix() { return fgetc_nid_postfix(__stdinp_nid_postfix); }
int APS5_VABI fputc_nid_postfix(int value, FileStream* stream) {
if (stream && !stream->IsOpen()) { errno = 9; return -1; }
const int result = std::fputc(value, GetNativeStream(stream));
stream->SyncStatus();
return result;
}
int APS5_VABI putc_nid_postfix(int value, FileStream* stream) { return fputc_nid_postfix(value, stream); }
int APS5_VABI putc_unlocked_nid_postfix(int value, FileStream* stream) {
if (stream && !stream->IsOpen()) { errno = 9; return -1; }
#ifdef _WIN32
const int result = _fputc_nolock(value, GetNativeStream(stream));
#else
Expand All @@ -64,11 +68,13 @@ int APS5_VABI putc_unlocked_nid_postfix(int value, FileStream* stream) {
int APS5_VABI __swbuf_nid_postfix(int value, FileStream* stream) { return fputc_nid_postfix(value, stream); }
int APS5_VABI putchar_nid_postfix(int value) { return fputc_nid_postfix(value, __stdoutp_nid_postfix); }
int APS5_VABI ungetc_nid_postfix(int value, FileStream* stream) {
if (stream && !stream->IsOpen()) { errno = 9; return -1; }
const int result = std::ungetc(value, GetNativeStream(stream));
stream->SyncStatus();
return result;
}
char* APS5_VABI fgets_nid_postfix(char* buffer, int size, FileStream* stream) {
if (stream && !stream->IsOpen()) { errno = 9; return nullptr; }
if (size <= 0) {
stream->SetError();
errno = 22;
Expand All @@ -90,6 +96,7 @@ void APS5_VABI clearerr_nid_postfix(FileStream* stream) {
stream->ClearError();
}
int APS5_VABI fileno_nid_postfix(FileStream* stream) {
if (stream && !stream->IsOpen()) { errno = 9; return -1; }
#ifdef _WIN32
const int descriptor = _fileno(GetNativeStream(stream));
#else
Expand All @@ -99,6 +106,7 @@ int APS5_VABI fileno_nid_postfix(FileStream* stream) {
return descriptor;
}
int APS5_VABI setvbuf_nid_postfix(FileStream* stream, char* buffer, int mode, std::size_t size) {
if (stream && !stream->IsOpen()) { errno = 9; return -1; }
if (mode < 0 || mode > 2) return -1;
const int native = mode == 0 ? _IOFBF : mode == 1 ? _IOLBF : _IONBF;
if (native != _IONBF && size == 0) {
Expand Down
2 changes: 1 addition & 1 deletion core/libs/tests/FileStreams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ int main(int argc, char** argv) {
ExpectException([] { fopen_nid_postfix(nullptr, "r"); });
FileStream closed(std::tmpfile());
closed.Close();
ExpectException([&] { fflush_nid_postfix(&closed); });
Require(fflush_nid_postfix(&closed) == -1 && errno == 9);
Require(std::remove(argv[1]) == 0);
errno = 0;
Require(fopen_nid_postfix(argv[1], "rb") == nullptr);
Expand Down
54 changes: 53 additions & 1 deletion core/libs/tests/GuestStandardStreams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <cstring>
#include <cstdarg>
#include <cstdint>
#include <string_view>
#include <filesystem>
#include <fstream>
#include <iterator>
Expand Down Expand Up @@ -34,6 +35,10 @@ extern FileStream* __stdoutp_nid_postfix;
extern FileStream* __stderrp_nid_postfix;
extern int __isthreaded_nid_postfix;
int APS5_VABI fprintf_nid_postfix(FileStream*, const char*, ...);
int APS5_VABI fputs_nid_postfix(const char*, FileStream*);
int APS5_VABI printf_nid_postfix(const char*, ...);
int APS5_VABI vprintf_nid_postfix(const char*, void*);
int APS5_VABI puts_nid_postfix(const char*);
int APS5_VABI vfprintf_nid_postfix(FileStream*, const char*, void*);
int APS5_VABI vsprintf_nid_postfix(char*, const char*, void*);
int APS5_VABI fgetc_nid_postfix(FileStream*);
Expand Down Expand Up @@ -80,6 +85,22 @@ static int APS5_VABI WriteFormatted(FileStream* stream, const char* format, ...)
#endif
return result;
}
static int APS5_VABI PrintStandard(const char* format, ...) {
#ifdef _WIN32
__builtin_sysv_va_list args;
__builtin_sysv_va_start(args, format);
#else
std::va_list args;
va_start(args, format);
#endif
const int result = vprintf_nid_postfix(format, args);
#ifdef _WIN32
__builtin_sysv_va_end(args);
#else
va_end(args);
#endif
return result;
}
static int APS5_VABI FormatString(char* buffer, const char* format, ...) {
#ifdef _WIN32
__builtin_sysv_va_list args;
Expand Down Expand Up @@ -493,7 +514,38 @@ static void CheckDescriptorAccessModes() {
Require(std::filesystem::remove(filename));
}

int main() {
static void CheckClosedStreamWrites() {
FileStream stream(std::tmpfile());
Require(freopen_nid_postfix("missing-closed-stream-dir/out.log", "w", &stream) == nullptr);
Require(fputs_nid_postfix("text", &stream) == -1 && *__error_nid_postfix() == 9);
Require(fprintf_nid_postfix(&stream, "%d", 1) == -1 && *__error_nid_postfix() == 9);
Require(fwrite_nid_postfix("text", 1, 4, &stream) == 0 && *__error_nid_postfix() == 9);
Require(fputc_nid_postfix('t', &stream) == -1 && *__error_nid_postfix() == 9);
Require(putc_unlocked_nid_postfix('t', &stream) == -1 && *__error_nid_postfix() == 9);
Require(fflush_nid_postfix(&stream) == -1 && *__error_nid_postfix() == 9);
char buffer[8] = {};
Require(fread_nid_postfix(buffer, 1, sizeof(buffer), &stream) == 0 && *__error_nid_postfix() == 9);
Require(fgetc_nid_postfix(&stream) == -1 && *__error_nid_postfix() == 9);
Require(fgets_nid_postfix(buffer, sizeof(buffer), &stream) == nullptr && *__error_nid_postfix() == 9);
Require(fseeko_nid_postfix(&stream, 0, SEEK_SET) == -1 && *__error_nid_postfix() == 9);
Require(ftello_nid_postfix(&stream) == -1 && *__error_nid_postfix() == 9);
Require(fileno_nid_postfix(&stream) == -1 && *__error_nid_postfix() == 9);
Require(ferror_nid_postfix(&stream) == 0 && feof_nid_postfix(&stream) == 0);
Require(fclose_nid_postfix(&stream) == -1 && *__error_nid_postfix() == 9);
}

static int CheckClosedStandardOutput() {
Require(freopen_nid_postfix("missing-closed-stream-dir/out.log", "w", __stdoutp_nid_postfix) == nullptr);
Require(printf_nid_postfix("%d", 1) == -1 && *__error_nid_postfix() == 9);
Require(puts_nid_postfix("text") == -1 && *__error_nid_postfix() == 9);
Require(PrintStandard("%d", 1) == -1 && *__error_nid_postfix() == 9);
Require(fputs_nid_postfix("text", __stdoutp_nid_postfix) == -1 && *__error_nid_postfix() == 9);
return 0;
}

int main(int argc, char** argv) {
if (argc > 1 && std::string_view(argv[1]) == "--closed-stdout") return CheckClosedStandardOutput();
CheckClosedStreamWrites();
CheckDescriptorAccessModes();
Require(_Getmbcurmax_nid_postfix() == 1 && _Getmbcurmax_nid_postfix() == ___mb_cur_max_nid_postfix());
CheckFlushWhileReading();
Expand Down
Loading