KhronosGroup / glslang

Khronos-reference front end for GLSL/ESSL, partial front end for HLSL, and a SPIR-V generator.
Other
2.98k stars 823 forks source link

Crash using below code #3136

Open preetishkakkar opened 1 year ago

preetishkakkar commented 1 year ago

Hello, I am using git tag version 11.13.0 and I have below code

std::vector<char> glslToSpirv(const std::vector<char>& data,
                              EShLanguage shaderStage, const char* entryPoint) {
  static bool glslangInitialized = false;

  if (!glslangInitialized) {
    glslang::InitializeProcess();
    glslangInitialized = true;
  }

  glslang::TShader tshader(shaderStage);
  const char* glslCStr = data.data();
  tshader.setStrings(&glslCStr, 1);

  glslang::EshTargetClientVersion clientVersion = glslang::EShTargetVulkan_1_1;
  glslang::EShTargetLanguageVersion langVersion = glslang::EShTargetSpv_1_3;

  tshader.setEnvInput(glslang::EShSourceGlsl, shaderStage,
                      glslang::EShClientVulkan,
                      460);  // 100 means version glsl version 1.0 (as defined
                             // by KHR_vulkan_glsl)

  tshader.setEnvClient(glslang::EShClientVulkan, clientVersion);
  tshader.setEnvTarget(glslang::EShTargetSpv, langVersion);

#ifdef _DEBUG
  tshader.setDebugInfo(true);
#endif

  tshader.setEntryPoint(entryPoint);
  tshader.setSourceEntryPoint(entryPoint);

  const TBuiltInResource* resources = GetDefaultResources();
  const EShMessages messages =
      static_cast<EShMessages>(EShMsgSpvRules | EShMsgVulkanRules);
  glslang::TShader::ForbidIncluder includer;

  std::string preprocessedGLSL;
  if (!tshader.preprocess(resources, 460, ENoProfile, false, false, messages,
                          &preprocessedGLSL, includer)) {
    std::cout << "Preprocessing failed for shader " << std::endl;
    std::cout << tshader.getInfoLog() << std::endl;
    std::cout << tshader.getInfoDebugLog() << std::endl;
    ASSERT(false, "preprocess failed");
    return std::vector<char>();
  }

  const char* preprocessedGLSLStr = preprocessedGLSL.c_str();
  tshader.setStrings(&preprocessedGLSLStr, 1);

  if (!tshader.parse(resources, 460, false, messages)) {
    std::cout << "Parsing failed for shader " << std::endl;
    std::cout << tshader.getInfoLog() << std::endl;
    std::cout << tshader.getInfoDebugLog() << std::endl;
    ASSERT(false, "parse failed");
    return std::vector<char>();
  }

  glslang::SpvOptions options;

#ifdef _DEBUG
  options.generateDebugInfo = false;
  options.disableOptimizer = false;
  options.optimizeSize = true;
  options.stripDebugInfo = true;
#else
  options.disableOptimizer = false;
  options.disableOptimizer = false;
  options.optimizeSize = true;
  options.stripDebugInfo = true;
#endif

  glslang::TProgram program;
  program.addShader(&tshader);
  if (!program.link(messages)) {
    std::cout << "Parsing failed for shader " << std::endl;
    std::cout << program.getInfoLog() << std::endl;
    std::cout << program.getInfoDebugLog() << std::endl;
    ASSERT(false, "link failed");
  }

  std::vector<uint32_t> spirvData;
  spv::SpvBuildLogger spvLogger;
  glslang::GlslangToSpv(*program.getIntermediate(shaderStage), spirvData,
                        &spvLogger, &options);

  std::vector<char> byteCode;
  byteCode.resize(spirvData.size() * (sizeof(uint32_t) / sizeof(char)));
  std::memcpy(byteCode.data(), spirvData.data(), byteCode.size());

  return byteCode;
}

As soon as I add if/else to my shader it crashes? Below is my shader code

#version 460

layout(location = 0) in vec4 inColor;
layout(location = 1) in vec2 texCoords;
layout(location = 0) out vec4 outColor;

layout (set = 0, binding = 0) uniform texture2D textureCheckered;
layout (set = 1, binding = 0) uniform sampler samplerTex;

void main() {
    float myval = 1.0;
    if(myval == 1.0) {
        const vec4 tex = texture(sampler2D(textureCheckered, samplerTex), texCoords) * inColor;
        outColor = tex;
    } else {
        vec4 tex = texture(sampler2D(textureCheckered, samplerTex), texCoords) * inColor;
        tex.r = 0.0;
        outColor = tex;
    }
}
preetishkakkar commented 1 year ago

looks like removing tshader.setDebugInfo(true); makes it works

preetishkakkar commented 1 year ago

setting it after parse also works fine, I guess may be it's not useful to tshader.setDebugInfo before parsing?

arcady-lunarg commented 1 year ago

I don't think glslang ought to be crashing even if you are passing the incorrect options. I'm going to take a look and see if I can reproduce this and get a backtrace. I've also reformatted your comment so the code doesn't get mangled, for future reference you can enclose code between triple-backticks to keep it from getting mangled by the HTML parser, or you can just attach the file as an attachment.

Jaisiero commented 9 months ago

Hi. How is this going? I've been experiencing the same issue.

[...]
 spv::SpvBuildLogger logger;
glslang::SpvOptions spv_options{};
spv_options.generateDebugInfo = true;      <-- make it crash
std::vector<u32> spv;
glslang::GlslangToSpv(*intermediary, spv, &logger, &spv_options);

This is the error that I got:

Assertion failed: !currentDebugScopeId.empty(), file C:\dev\utils\vcpkg\buildtrees\glslang\src\12.2.0-7aaf2a2782.clean\SPIRV\SpvBuilder.cpp, line 2131

I hope it'll be fixed soon. Cheers!

James2022-rgb commented 8 months ago

If we're using glslang::TShader::setDebugInfo with true, we seem to need to to set glslang::SpvOptions::emitNonSemanticShaderDebugInfo to true in order for the crash not to manifest itself.

I would have liked to tackle this further but I think an interface design decision needs to be made here.

Direct cause

When glslang::TShader::setDebugInfo is called with true, on glslang::TShader::parse, EOpScope instead of EOpSequence is emitted for LEFT_BRACE statement_list RIGHT_BRACE: https://github.com/KhronosGroup/glslang/blob/a91631b260cba3f22858d6c6827511e636c2458a/glslang/MachineIndependent/glslang.y#L3765-L3769

With glslang::SpvOptions::emitNonSemanticShaderDebugInfo set to false (the dafault value), spv::Builder::enterFunction doesn't initialize the top level debug scope: https://github.com/KhronosGroup/glslang/blob/a91631b260cba3f22858d6c6827511e636c2458a/SPIRV/SpvBuilder.cpp#L2272-L2285

So when TGlslangToSpvTraverser::visitAggregate gets to an EOpScope and calls spv::Builder::enterScope: https://github.com/KhronosGroup/glslang/blob/a91631b260cba3f22858d6c6827511e636c2458a/SPIRV/GlslangToSpv.cpp#L2896-L2897

spv::Builder::enterScope calls spv::Builder::makeDebugLexicalBlock, which fails the assertion assert(!currentDebugScopeId.empty()): https://github.com/KhronosGroup/glslang/blob/a91631b260cba3f22858d6c6827511e636c2458a/SPIRV/SpvBuilder.cpp#L2213-L2223