From 4d5d06c3c05990705643792dd26024bae2a3160e Mon Sep 17 00:00:00 2001 From: dev0 Date: Mon, 15 Dec 2025 21:42:14 +0530 Subject: [PATCH] Fixes --- .gitignore | 2 +- CMakePresets.json | 27 +++++++++------------------ README.md | 4 +++- Src/IACore/CMakeLists.txt | 13 +++++++++++-- Src/IACore/imp/cpp/FileOps.cpp | 19 ++++++++++++------- Src/IACore/imp/cpp/IPC.cpp | 2 ++ Src/IACore/imp/cpp/ProcessOps.cpp | 21 +++++++++++++++++++-- Src/IACore/inc/IACore/IPC.hpp | 2 ++ Tests/Unit/ProcessOps.cpp | 31 +++++++++++++++++++++++++++++++ 9 files changed, 90 insertions(+), 31 deletions(-) diff --git a/.gitignore b/.gitignore index e7188e5..122ab5f 100644 --- a/.gitignore +++ b/.gitignore @@ -47,5 +47,5 @@ .cache/ .local/ -[Bb]uild out/ +[Bb]uild diff --git a/CMakePresets.json b/CMakePresets.json index c8cd0e5..3385ffe 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -26,6 +26,8 @@ "rhs": "Windows" }, "cacheVariables": { + "CMAKE_C_COMPILER": "clang-cl", + "CMAKE_CXX_COMPILER": "clang-cl", "CMAKE_TOOLCHAIN_FILE": "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", "VCPKG_TARGET_TRIPLET": "x64-windows" } @@ -42,14 +44,14 @@ }, { "name": "windows-default", - "displayName": "Windows (VCPKG)", - "description": "Windows build using VCPKG", + "displayName": "Windows (Clang-CL + VCPKG)", + "description": "Windows build using Clang-CL and VCPKG dependencies", "inherits": "windows-base" }, { "name": "linux-default", - "displayName": "Linux (System)", - "description": "Linux build using system compilers", + "displayName": "Linux (Clang)", + "description": "Linux build using Clang", "inherits": "linux-base" }, { @@ -58,7 +60,6 @@ "description": "Linux CI Build", "inherits": "linux-base", "cacheVariables": { - "SDL_UNIX_CONSOLE_BUILD": "ON", "IS_CI_BUILD": "ON" } } @@ -67,7 +68,7 @@ { "name": "windows-debug", "configurePreset": "windows-default", - "configuration": "debug", + "configuration": "Debug", "condition": { "type": "equals", "lhs": "${hostSystemName}", @@ -77,17 +78,7 @@ { "name": "linux-debug", "configurePreset": "linux-default", - "configuration": "debug", - "condition": { - "type": "notEquals", - "lhs": "${hostSystemName}", - "rhs": "Windows" - } - }, - { - "name": "linux-ci-debug", - "configurePreset": "linux-ci", - "configuration": "debug", + "configuration": "Debug", "condition": { "type": "notEquals", "lhs": "${hostSystemName}", @@ -97,7 +88,7 @@ { "name": "linux-ci-release", "configurePreset": "linux-ci", - "configuration": "release", + "configuration": "Release", "condition": { "type": "notEquals", "lhs": "${hostSystemName}", diff --git a/README.md b/README.md index 4106a26..aa1a37b 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Originally developed as the internal core for IASoft (PVT) LTD., it is now open- ## โœจ Features * **๐Ÿš€ High-Performance IPC:** Shared-Memory Ring Buffers with wait-free SPSC synchronization. -* **๐ŸŒ Networking:** Integrated HTTP/HTTPS client (wrapper around `cpp-httplib` with automatic Zlib/Gzip/Brotli handling). +* **๐ŸŒ Networking:** Integrated HTTP/HTTPS client (wrapper around `cpp-httplib` with automatic Zlib/Gzip handling). * **๐Ÿงต Async Scheduler:** A job system with high/normal priority queues and work stealing. * **๐Ÿ’พ File I/O:** Memory-mapped file operations and optimized binary stream readers/writers. * **๐Ÿ“ฆ Compression:** Unified API for Zlib, Gzip, and Zstd. @@ -22,6 +22,8 @@ Originally developed as the internal core for IASoft (PVT) LTD., it is now open- IACore is built with CMake. You can include it in your project via `FetchContent` or by adding it as a subdirectory. +Note: On Windows, you must have VCPKG installed and the VCPKG_ROOT environment variable set, for OpenSSL support. + ### CMake Example ```cmake add_subdirectory(IACore) diff --git a/Src/IACore/CMakeLists.txt b/Src/IACore/CMakeLists.txt index f67b46e..9076999 100644 --- a/Src/IACore/CMakeLists.txt +++ b/Src/IACore/CMakeLists.txt @@ -37,11 +37,20 @@ target_link_libraries(IACore PRIVATE target_link_libraries(IACore PUBLIC mimalloc-static) +if(WIN32) + if(MSVC) + target_link_options(IACore PUBLIC "/INCLUDE:mi_version") + else() + target_link_options(IACore PUBLIC "") + endif() +endif() + target_precompile_headers(IACore PUBLIC inc/IACore/PCH.hpp) -target_compile_options(IACore PRIVATE -fno-exceptions) +set(NO_EXCEPT_FLAG "$,/EHs-c-,-fno-exceptions>") +target_compile_options(IACore PRIVATE ${NO_EXCEPT_FLAG}) target_compile_options(IACore INTERFACE - $<$>>:-fno-exceptions> + $<$>>:${NO_EXCEPT_FLAG}> ) define_property(TARGET PROPERTY USE_EXCEPTIONS diff --git a/Src/IACore/imp/cpp/FileOps.cpp b/Src/IACore/imp/cpp/FileOps.cpp index 25c3dfd..0f418a4 100644 --- a/Src/IACore/imp/cpp/FileOps.cpp +++ b/Src/IACore/imp/cpp/FileOps.cpp @@ -228,11 +228,14 @@ namespace IACore Expected FileOps::WriteTextFile(IN CONST FilePath &path, IN CONST String &contents, IN BOOL overwrite) { - if (!overwrite && FileSystem::exists(path)) - return MakeUnexpected(std::format("File aready exists: {}", path.string().c_str())); - const auto f = fopen(path.string().c_str(), "w"); + const char *mode = overwrite ? "w" : "wx"; + const auto f = fopen(path.string().c_str(), mode); if (!f) + { + if (!overwrite && errno == EEXIST) + return MakeUnexpected(std::format("File already exists: {}", path.string().c_str())); return MakeUnexpected(std::format("Failed to write to file: {}", path.string().c_str())); + } const auto result = fwrite(contents.data(), 1, contents.size(), f); fputc(0, f); fclose(f); @@ -242,12 +245,14 @@ namespace IACore Expected FileOps::WriteBinaryFile(IN CONST FilePath &path, IN Span contents, IN BOOL overwrite) { - if (!overwrite && FileSystem::exists(path)) - return MakeUnexpected(std::format("File aready exists: {}", path.string().c_str())); - - const auto f = fopen(path.string().c_str(), "wb"); + const char *mode = overwrite ? "w" : "wx"; + const auto f = fopen(path.string().c_str(), mode); if (!f) + { + if (!overwrite && errno == EEXIST) + return MakeUnexpected(std::format("File already exists: {}", path.string().c_str())); return MakeUnexpected(std::format("Failed to write to file: {}", path.string().c_str())); + } const auto result = fwrite(contents.data(), 1, contents.size(), f); fclose(f); return result; diff --git a/Src/IACore/imp/cpp/IPC.cpp b/Src/IACore/imp/cpp/IPC.cpp index 6a3393c..71f6fa2 100644 --- a/Src/IACore/imp/cpp/IPC.cpp +++ b/Src/IACore/imp/cpp/IPC.cpp @@ -175,6 +175,8 @@ namespace IACore VOID IPC_Manager::NodeSession::SendPacket(IN UINT16 packetID, IN Span payload) { + // Protect the RingBuffer write cursor from concurrent threads + ScopedLock lock(SendMutex); MONI->Push(packetID, payload); } diff --git a/Src/IACore/imp/cpp/ProcessOps.cpp b/Src/IACore/imp/cpp/ProcessOps.cpp index b9ccc5b..172c851 100644 --- a/Src/IACore/imp/cpp/ProcessOps.cpp +++ b/Src/IACore/imp/cpp/ProcessOps.cpp @@ -206,19 +206,35 @@ namespace IACore // Manual Quote-Aware Splitter std::string currentToken; bool inQuotes = false; + bool isEscaped = false; for (char c : args) { + if (isEscaped) + { + // Previous char was '\', so we treat this char literally. + currentToken += c; + isEscaped = false; + continue; + } + + if (c == '\\') + { + // Escape sequence start + isEscaped = true; + continue; + } + if (c == '\"') { + // Toggle quote state inQuotes = !inQuotes; - // Determine if you want to keep the quotes or strip them. - // Usually for execvp, you strip them so the shell receives the raw content. continue; } if (c == ' ' && !inQuotes) { + // Token boundary if (!currentToken.empty()) { argStorage.push_back(currentToken); @@ -230,6 +246,7 @@ namespace IACore currentToken += c; } } + if (!currentToken.empty()) { argStorage.push_back(currentToken); diff --git a/Src/IACore/inc/IACore/IPC.hpp b/Src/IACore/inc/IACore/IPC.hpp index 331df5a..93c603f 100644 --- a/Src/IACore/inc/IACore/IPC.hpp +++ b/Src/IACore/inc/IACore/IPC.hpp @@ -104,6 +104,8 @@ namespace IACore SteadyTimePoint CreationTime{}; SharedPtr ProcessHandle; + Mutex SendMutex; + String SharedMemName; PUINT8 MappedPtr{}; diff --git a/Tests/Unit/ProcessOps.cpp b/Tests/Unit/ProcessOps.cpp index 959fbce..1050c55 100644 --- a/Tests/Unit/ProcessOps.cpp +++ b/Tests/Unit/ProcessOps.cpp @@ -212,6 +212,36 @@ BOOL TestMultiLine() return TRUE; } +// ------------------------------------------------------------------------- +// 6. Complex Command Line Arguments Handling +// ------------------------------------------------------------------------- +BOOL TestComplexArguments() +{ + // Should parse as 3 arguments: + // 1. -DDEFINED_MSG="Hello World" + // 2. -v + // 3. path/to/file + String complexArgs = "-DDEFINED_MSG=\\\"Hello World\\\" -v path/to/file"; + + // We can't easily inspect the child process argv in this unit test framework without + // writing a dedicated child program that prints its argv. + // However, for now, we ensure it doesn't crash or return error code 127. + + // Use "echo" to verify what it received. + // Expected output: -DDEFINED_MSG="Hello World" -v path/to/file + String cmd = "/bin/echo"; + + String captured; + auto result = ProcessOps::SpawnProcessSync(cmd, complexArgs, [&](StringView line) { captured += line; }); + + IAT_CHECK(result.has_value()); + IAT_CHECK_EQ(*result, 0); + + // Verify the quotes were preserved in the output if the shell handled them correctly + IAT_CHECK(captured.find("Hello World") != String::npos); + return TRUE; +} + // ------------------------------------------------------------------------- // Registration // ------------------------------------------------------------------------- @@ -222,6 +252,7 @@ IAT_ADD_TEST(TestExitCodes); IAT_ADD_TEST(TestMissingExe); IAT_ADD_TEST(TestLargeOutput); IAT_ADD_TEST(TestMultiLine); +IAT_ADD_TEST(TestComplexArguments); IAT_END_TEST_LIST() IAT_END_BLOCK()