最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - std::string and default move constructor causing heap corruption - Stack Overflow

programmeradmin0浏览0评论

While refactoring some code, I've run into an issue with heap corruption.

namespace GPU
{
    struct ShaderStage
    {
    public:
        ShaderStage(ShaderStageType, const Path&);
        ShaderStage() = default;
        [Default copy/move constructors]

        ShaderStageType StageType = {};
        std::string Source = {};
        std::filesystem::path BasePath = {};
    };

    struct Shader
    {
    public:
        Shader(const Path& v, const Path& f);
        Shader() = default;
        [Default copy/move constructors]

        ShaderStage VertexStage = {};
        ShaderStage FragmentStage = {};
    };

    ShaderStage::ShaderStage(ShaderStageType type, const std::filesystem::path& path) : StageType(type), BasePath(path)
    {
        Source = [any string, loads file in this case];
    };

    Shader::Shader(const Path& v, const Path& f) :
        VertexStage(ShaderStageType::Vertex, v),
        FragmentStage(ShaderStageType::Fragment, f)
    {
    };
}

namespace GL
{
    class Shader final : protected GPU::Shader
    {
    public:
        Shader(gE::Window* window, GPU::Shader&&);
        Shader() = default;
    };

    Shader::Shader(gE::Window* window, GPU::Shader&& INTERNAL_SETTINGS) : GPU::Shader(move(INTERNAL_SETTINGS))
    {
                [Actually constructs GL::ShaderStage, but I can replicate the issue with just moving GPU::ShaderStage around]
        GPU::ShaderStage frag = move(FragmentStage);
        GPU::ShaderStage vert = move(VertexStage);

        FragmentStage = move(frag);
        VertexStage = move(vert);
    }
}

This is how I construct the object:

GPU::Shader shaderSettings("Resource/Shader/skybox.vert", "Resource/Shader/skybox.frag");

[GL::Shader _skyboxShader = {}]
_skyboxShader = GL::Shader(window, move(shaderSettings));
[SIGTRAP when _skyboxShader goes out of scope]

Placement new works:

GPU::Shader shaderSettings("Resource/Shader/skybox.vert", "Resource/Shader/skybox.frag");

[GL::Shader _skyboxShader = {}]
_skyboxShader.~Shader();
new(&_skyboxShader) GL::Shader(window, move(shaderSettings));
[No error]

I'd like to think I'm experienced with c++, and this whole thing is just bizzare. I've gone through multiple passes of debugging which yielded no results.

While refactoring some code, I've run into an issue with heap corruption.

namespace GPU
{
    struct ShaderStage
    {
    public:
        ShaderStage(ShaderStageType, const Path&);
        ShaderStage() = default;
        [Default copy/move constructors]

        ShaderStageType StageType = {};
        std::string Source = {};
        std::filesystem::path BasePath = {};
    };

    struct Shader
    {
    public:
        Shader(const Path& v, const Path& f);
        Shader() = default;
        [Default copy/move constructors]

        ShaderStage VertexStage = {};
        ShaderStage FragmentStage = {};
    };

    ShaderStage::ShaderStage(ShaderStageType type, const std::filesystem::path& path) : StageType(type), BasePath(path)
    {
        Source = [any string, loads file in this case];
    };

    Shader::Shader(const Path& v, const Path& f) :
        VertexStage(ShaderStageType::Vertex, v),
        FragmentStage(ShaderStageType::Fragment, f)
    {
    };
}

namespace GL
{
    class Shader final : protected GPU::Shader
    {
    public:
        Shader(gE::Window* window, GPU::Shader&&);
        Shader() = default;
    };

    Shader::Shader(gE::Window* window, GPU::Shader&& INTERNAL_SETTINGS) : GPU::Shader(move(INTERNAL_SETTINGS))
    {
                [Actually constructs GL::ShaderStage, but I can replicate the issue with just moving GPU::ShaderStage around]
        GPU::ShaderStage frag = move(FragmentStage);
        GPU::ShaderStage vert = move(VertexStage);

        FragmentStage = move(frag);
        VertexStage = move(vert);
    }
}

This is how I construct the object:

GPU::Shader shaderSettings("Resource/Shader/skybox.vert", "Resource/Shader/skybox.frag");

[GL::Shader _skyboxShader = {}]
_skyboxShader = GL::Shader(window, move(shaderSettings));
[SIGTRAP when _skyboxShader goes out of scope]

Placement new works:

GPU::Shader shaderSettings("Resource/Shader/skybox.vert", "Resource/Shader/skybox.frag");

[GL::Shader _skyboxShader = {}]
_skyboxShader.~Shader();
new(&_skyboxShader) GL::Shader(window, move(shaderSettings));
[No error]

I'd like to think I'm experienced with c++, and this whole thing is just bizzare. I've gone through multiple passes of debugging which yielded no results.

Share Improve this question edited Nov 20, 2024 at 3:03 John Kugelman 362k69 gold badges552 silver badges596 bronze badges asked Nov 20, 2024 at 3:00 garlfingarlfin 111 bronze badge 5
  • What does move do? – 3CxEZiVlQ Commented Nov 20, 2024 at 3:04
  • 3 Heap corruption issues frequently are caused by code far away from and not related to the code where the symptom turns up. You might try a memory analysis tool like valgrind. We're not likely to be able to help here unless you can post a minimal reproducible example. – aschepler Commented Nov 20, 2024 at 3:09
  • 2 From the code you've supplied, and symptoms you have described, it is impossible to say. There's a distinct possibility that the cause of heap corruption is in completely unrelated code, and your refactoring happens to have expose a symptom as a side effect (e.g. because of refactoring, anisation of memory used by your program as a whole has changed, and whatever is being tromped now gives an observable symptom). Even though it seems counter-intuitive, you may need to look for the cause in code that you haven't changed. – Peter Commented Nov 20, 2024 at 3:44
  • I agree to the prior comments, the symptoms look like out of bounds memory access that corrupts random data, those can be extremely difficult to detect manually. Any address sanitizer tool should be able to detect where the problem comes from. Search for one which fits to your build environment. GCC and Visual Studio provide address sanitizers (the GCC sanitizer is good, the visual studio one I did not test yet). Valgrind is/was a good tool but is unfortunately a bit outdated. – Thibe Commented Nov 20, 2024 at 13:57
  • I tried using Application Verifier which didn't seem to find anything. I'll try the GCC sanitizers. – garlfin Commented Nov 20, 2024 at 14:14
Add a comment  | 

1 Answer 1

Reset to default 0

I switched to MSVC and the issue seemingly disappeared; Address Sanitizer still finds no issues. Using my own array class in place of std::string and std::filesystem::path works too.

I don't know if I should trust my own findings (maybe a gcc bug?) or I just keep winning the heap corruption lottery after switching to MSVC.

发布评论

评论列表(0)

  1. 暂无评论