From df9436c51d06f3e1ed107378fea48552dc23e056 Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Fri, 1 May 2026 19:02:14 +0200 Subject: [PATCH] fixed error shader crash --- implementations/Crafter.Build-Clang.cpp | 16 +++++ implementations/Crafter.Build-Shader.cpp | 77 ++++++++++++++---------- interfaces/Crafter.Build-Clang.cppm | 5 ++ 3 files changed, 67 insertions(+), 31 deletions(-) diff --git a/implementations/Crafter.Build-Clang.cpp b/implementations/Crafter.Build-Clang.cpp index fe106bc..1de2264 100644 --- a/implementations/Crafter.Build-Clang.cpp +++ b/implementations/Crafter.Build-Clang.cpp @@ -417,6 +417,7 @@ BuildResult Crafter::Build(Configuration& config, std::unordered_map libSet; + std::unordered_set publicFlagSet; std::mutex fileMutex; std::vector depThreads; depThreads.reserve(config.dependencies.size()); @@ -477,6 +478,7 @@ BuildResult Crafter::Build(Configuration& config, std::unordered_map(EShMsgDefault | EShMsgVulkanRules | EShMsgSpvRules); std::ifstream fileStream(path, std::ios::in | std::ios::binary); if (!fileStream) { - throw std::ios_base::failure("Failed to open file: " + path.string()); + return fail("failed to open shader source", {}); } std::ostringstream contents; contents << fileStream.rdbuf(); std::string src = contents.str(); - const char *file_name_list[1] = {""}; - const char *shader_source = reinterpret_cast(src.data()); + std::string pathStr = path.string(); + const char* file_name_list[1] = { pathStr.c_str() }; + const char* shader_source = src.data(); + const int shader_source_len = static_cast(src.size()); glslang::TShader shader(glslangType); - shader.setStringsWithLengthsAndNames(&shader_source, nullptr, file_name_list, 1); + shader.setStringsWithLengthsAndNames(&shader_source, &shader_source_len, file_name_list, 1); shader.setEntryPoint(entrypoint.c_str()); shader.setSourceEntryPoint(entrypoint.c_str()); shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_4); DirStackFileIncluder includeDir; includeDir.pushExternalLocalDirectory(path.parent_path().generic_string()); - std::string info_log; - if (!shader.parse(GetDefaultResources(), 100, false, messages, includeDir)) - { - info_log = std::string(shader.getInfoLog()) + std::string(shader.getInfoDebugLog()); + + if (!shader.parse(GetDefaultResources(), 100, false, messages, includeDir)) { + return fail("GLSL parse failed", std::string(shader.getInfoLog()) + shader.getInfoDebugLog()); } - // Add shader to new program object. + glslang::TProgram program; program.addShader(&shader); - - // Link program. - if (!program.link(messages)) - { - info_log = std::string(program.getInfoLog()) + std::string(program.getInfoDebugLog()); - } - - // Save any info log that was generated. - if (shader.getInfoLog()) - { - info_log += std::string(shader.getInfoLog()) + std::string(shader.getInfoDebugLog()); - } - - if (program.getInfoLog()) - { - info_log += std::string(program.getInfoLog()) + std::string(program.getInfoDebugLog()); + if (!program.link(messages)) { + return fail("GLSL link failed", std::string(program.getInfoLog()) + program.getInfoDebugLog()); } glslang::TIntermediate* intermediate = program.getIntermediate(glslangType); - if (!intermediate) - { - info_log += "Failed to get shared intermediate code."; + if (!intermediate) { + // Defensive: parse+link succeeded above, so this should be + // unreachable. If glslang ever changes that contract we'd + // rather surface a clear error than dereference null (the + // pre-fix bug that masqueraded as a silent SIGSEGV). + return fail("glslang produced no intermediate code", {}); } spv::SpvBuildLogger logger; std::vector spirv; glslang::GlslangToSpv(*intermediate, spirv, &logger); - std::string errorLog = logger.getAllMessages(); - glslang::FinalizeProcess(); + std::string spvLog = logger.getAllMessages(); + fs::path filename = path.filename().replace_extension("spv"); std::ofstream file(outputDir/filename, std::ios::binary); + if (!file) { + return fail("failed to open SPIR-V output", (outputDir/filename).string()); + } file.write(reinterpret_cast(spirv.data()), spirv.size() * sizeof(std::uint32_t)); - return errorLog; + + if (!spvLog.empty()) { + return fail("SPIR-V codegen reported issues", std::move(spvLog)); + } + glslang::FinalizeProcess(); + return {}; } } diff --git a/interfaces/Crafter.Build-Clang.cppm b/interfaces/Crafter.Build-Clang.cppm index f988623..b483d91 100644 --- a/interfaces/Crafter.Build-Clang.cppm +++ b/interfaces/Crafter.Build-Clang.cppm @@ -32,6 +32,11 @@ export namespace Crafter { std::string result; bool repack; std::unordered_set libs; + // Compile flags (typically -I include paths) the dep wants its + // consumers to see — sourced from its external dependencies' include + // dirs so headers a dep exposes in its public modules are reachable + // when a consumer #includes them directly. Propagates transitively. + std::unordered_set publicCompileFlags; }; struct Define {