From 42594eecd4bc181f196408679397f247df84f66e Mon Sep 17 00:00:00 2001 From: Darko Gjorgjijoski Date: Mon, 28 Sep 2026 00:25:42 +0200 Subject: [PATCH] fix(relinker): report buffered output write failures --- core/relinker/CMakeLists.txt | 13 +++++++ core/relinker/io/src/FileWriter.cpp | 2 + core/relinker/io/tests/FileWriterTests.cpp | 43 ++++++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 core/relinker/io/tests/FileWriterTests.cpp diff --git a/core/relinker/CMakeLists.txt b/core/relinker/CMakeLists.txt index 42ebb17ba..ee8aa80fc 100644 --- a/core/relinker/CMakeLists.txt +++ b/core/relinker/CMakeLists.txt @@ -106,6 +106,19 @@ endif() if(BUILD_TESTING) + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + add_executable(file_writer_tests + ${CMAKE_CURRENT_SOURCE_DIR}/io/tests/FileWriterTests.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/io/src/FileWriter.cpp + ) + target_include_directories(file_writer_tests PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/domain/include + ${CMAKE_CURRENT_SOURCE_DIR}/io/include + ) + add_test(NAME file_writer_binary COMMAND file_writer_tests binary) + add_test(NAME file_writer_text COMMAND file_writer_tests text) + endif() + add_executable(amd64_only_converter_tests ${CMAKE_CURRENT_SOURCE_DIR}/codegen/tests/Amd64OnlyConverterTests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/codegen/src/Amd64OnlyConverter.cpp diff --git a/core/relinker/io/src/FileWriter.cpp b/core/relinker/io/src/FileWriter.cpp index f30fdae52..a8c65fd63 100644 --- a/core/relinker/io/src/FileWriter.cpp +++ b/core/relinker/io/src/FileWriter.cpp @@ -9,6 +9,7 @@ void FileWriter::Write(const std::string& path, const std::vector& if (!f) throw Domain::RelinkerException("Cannot open output file: " + path); f.write(reinterpret_cast(data.data()), static_cast(data.size())); + f.close(); if (!f) throw Domain::RelinkerException("Failed to write file: " + path); } @@ -18,6 +19,7 @@ void FileWriter::Write(const std::string& path, const std::string& content) { if (!f) throw Domain::RelinkerException("Cannot open output file: " + path); f << content; + f.close(); if (!f) throw Domain::RelinkerException("Failed to write file: " + path); } diff --git a/core/relinker/io/tests/FileWriterTests.cpp b/core/relinker/io/tests/FileWriterTests.cpp new file mode 100644 index 000000000..8edc710d5 --- /dev/null +++ b/core/relinker/io/tests/FileWriterTests.cpp @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include + +namespace { + +template +void requireWriteFailure(const TValue& data) { + Io::FileWriter writer; + writer.Write("/dev/null", data); + try { + writer.Write("/dev/full", data); + } catch (const Domain::RelinkerException& e) { + if (std::string(e.what()) != "Failed to write file: /dev/full") + throw std::runtime_error("Unexpected write failure: " + std::string(e.what())); + return; + } + throw std::runtime_error("Write to /dev/full reported success"); +} + +} + +int main(int argc, char* argv[]) { + try { + if (argc != 2) throw std::runtime_error("Expected binary or text"); + const std::string mode = argv[1]; + for (const std::size_t size : {std::size_t{3}, std::size_t{65536}}) { + if (mode == "binary") + requireWriteFailure(std::vector(size, 0x41)); + else if (mode == "text") + requireWriteFailure(std::string(size, 'A')); + else + throw std::runtime_error("Unknown test mode: " + mode); + } + } catch (const std::exception& e) { + std::cerr << e.what() << '\n'; + return 1; + } + return 0; +}