Skip to content
Closed
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
10 changes: 10 additions & 0 deletions core/libs/prx/libkernel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1189,6 +1189,16 @@ if(BUILD_TESTING)
set_tests_properties(guest_file_vector PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
endif()
add_test_executable(guest_pipe_closed_write_tests ${LIBS_INCLUDE_DIR}/tests/GuestPipeClosedWrite.cpp)
target_include_directories(guest_pipe_closed_write_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_pipe_closed_write_tests PRIVATE libkernel libc)
configure_windows_unwind(guest_pipe_closed_write_tests)
add_test(NAME guest_pipe_closed_write COMMAND guest_pipe_closed_write_tests)
set_tests_properties(guest_pipe_closed_write PROPERTIES TIMEOUT 15)
if(WIN32)
set_tests_properties(guest_pipe_closed_write PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
endif()
add_test_executable(guest_fstatfs_tests ${LIBS_INCLUDE_DIR}/tests/GuestFstatfs.cpp)
target_include_directories(guest_fstatfs_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_fstatfs_tests PRIVATE libkernel libc)
Expand Down
1 change: 1 addition & 0 deletions core/libs/prx/libkernel/File/src/Open.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ static int NativeWrite(int fd, const void* buf, std::size_t n) {
if (shared != -2) return static_cast<int>(shared);
const int result = ::_write(fd, buf, static_cast<unsigned int>(n));
if (result < 0 && errno == ENOSPC && _doserrno == 0 && ::GetFileType(reinterpret_cast<HANDLE>(::_get_osfhandle(fd))) == FILE_TYPE_PIPE) errno = EAGAIN;
if (result < 0 && errno == EINVAL && _doserrno == ERROR_NO_DATA) errno = EPIPE;
return result;
}
extern "C" _invalid_parameter_handler _set_thread_local_invalid_parameter_handler(_invalid_parameter_handler);
Expand Down
3 changes: 3 additions & 0 deletions core/libs/prx/libkernel/File/src/Stdio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,9 @@ static std::int64_t TransferIovecs(int d, const KernelIovec* iov, int iovcnt, co
for (std::size_t position = 0; position < iov[i].length;) {
const auto chunk = std::min<std::size_t>(iov[i].length - position, std::numeric_limits<int>::max());
const auto result = offset != nullptr ? NativePositioned_nid_no_patch(d, base + position, chunk, *offset + done, write) : NativeTransfer(d, base + position, chunk, write);
#ifdef _WIN32
if (result < 0 && offset == nullptr && write && errno == EINVAL && _doserrno == ERROR_NO_DATA) errno = EPIPE;
#endif
if (result < 0) return done != 0 ? done : SceErrorFromErrno(errno);
done += result;
position += static_cast<std::size_t>(result);
Expand Down
60 changes: 60 additions & 0 deletions core/libs/tests/GuestPipeClosedWrite.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdint>
#include <cstdlib>
#ifndef _WIN32
#include <csignal>
#endif

struct GuestIovec {
const void* base;
std::size_t length;
};

extern "C" {
int APS5_VABI pipe_nid_postfix(int*);
int APS5_VABI close_nid_postfix(int);
int APS5_VABI fcntl_nid_postfix(int, int, ...);
std::int64_t APS5_VABI write_nid_postfix(int, const char*, std::int64_t);
std::int64_t APS5_VABI writev_nid_postfix(int, const GuestIovec*, int);
std::int64_t APS5_VABI sceKernelWrite(int, const void*, std::size_t);
std::int64_t APS5_VABI sceKernelWritev(int, const GuestIovec*, int);
int* APS5_VABI __error_nid_postfix();
}

static void Require(bool value) { if (!value) std::abort(); }

constexpr int GuestEpipe = 32;
constexpr int SetFlags = 4;
constexpr int NonBlocking = 4;
constexpr std::int64_t SceEpipe = static_cast<int>(0x80020020u);

static void RequireBrokenWrites(int writer) {
const GuestIovec vector{"x", 1};
*__error_nid_postfix() = 0;
Require(write_nid_postfix(writer, "x", 1) == -1);
Require(*__error_nid_postfix() == GuestEpipe);
*__error_nid_postfix() = 0;
Require(writev_nid_postfix(writer, &vector, 1) == -1);
Require(*__error_nid_postfix() == GuestEpipe);
Require(sceKernelWrite(writer, "x", 1) == SceEpipe);
Require(sceKernelWritev(writer, &vector, 1) == SceEpipe);
}

int main() {
#ifndef _WIN32
std::signal(SIGPIPE, SIG_IGN);
#endif
int blocking[2];
Require(pipe_nid_postfix(blocking) == 0);
Require(close_nid_postfix(blocking[0]) == 0);
RequireBrokenWrites(blocking[1]);
Require(close_nid_postfix(blocking[1]) == 0);

int nonblocking[2];
Require(pipe_nid_postfix(nonblocking) == 0);
Require(fcntl_nid_postfix(nonblocking[1], SetFlags, NonBlocking) == 0);
Require(write_nid_postfix(nonblocking[1], "x", 1) == 1);
Require(close_nid_postfix(nonblocking[0]) == 0);
RequireBrokenWrites(nonblocking[1]);
Require(close_nid_postfix(nonblocking[1]) == 0);
}
Loading