Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access violation when releasing a GlobalSession before other sessions #6344

Closed
ennis opened this issue Feb 12, 2025 · 5 comments · Fixed by #6479
Closed

Access violation when releasing a GlobalSession before other sessions #6344

ennis opened this issue Feb 12, 2025 · 5 comments · Fixed by #6479
Assignees
Labels
goal:quality & productivity Quality issues and issues that impact our productivity coding day to day inside slang kind:documentation areas where we can improve documentation in codebase

Comments

@ennis
Copy link
Contributor

ennis commented Feb 12, 2025

Setup: slang master on windows x64, vs2022

This example program crashes (adapted from reflection-api):

Code
#include "slang-com-ptr.h"
#include "slang.h"
typedef SlangResult Result;

#include "core/slang-basic.h"
#include "examples/example-base/example-base.h"
using Slang::ComPtr;
using Slang::String;
using Slang::List;

static const ExampleResources resourceBase("reflection-api");

static const char* kSourceFileNames[] = {
    "raster-simple.slang",
    "compute-simple.slang",
};

static const struct
{
    SlangCompileTarget format;
    const char* profile;
} kTargets[] = {
    {SLANG_DXIL, "sm_6_0"},
    {SLANG_SPIRV, "sm_6_0"},
};
static const int kTargetCount = SLANG_COUNT_OF(kTargets);

struct ExampleProgram : public TestBase
{
    Result execute(int argc, char* argv[])
    {
        parseOption(argc, argv);

        ComPtr<slang::IGlobalSession> globalSession;
        SLANG_RETURN_ON_FAIL(slang::createGlobalSession(globalSession.writeRef()));

        Slang::List<slang::TargetDesc> targetDescs;
        for (auto target : kTargets)
        {
            auto profile = globalSession->findProfile(target.profile);

            slang::TargetDesc targetDesc;
            targetDesc.format = target.format;
            targetDesc.profile = profile;
            targetDescs.add(targetDesc);
        }

        slang::SessionDesc sessionDesc;
        sessionDesc.targetCount = targetDescs.getCount();
        sessionDesc.targets = targetDescs.getBuffer();

        ComPtr<slang::ISession> session;
        SLANG_RETURN_ON_FAIL(globalSession->createSession(sessionDesc, session.writeRef()));

        // *** ADDED ***
        globalSession = nullptr;

        return SLANG_OK;
    }
};

int exampleMain(int argc, char** argv)
{
    ExampleProgram app;
    if (SLANG_FAILED(app.execute(argc, argv)))
    {
        return -1;
    }
    return 0;
}

Compared to the original example I added globalSession = nullptr; to release the reference early. It then crashes in the destructor of session at the end of the function:

Call stack
>	slang.dll!std::_Atomic_integral<__int64,8>::operator++(int __formal) Line 1625	C++
 	slang.dll!Slang::ASTBuilder::incrementEpoch() Line 273	C++
 	slang.dll!Slang::ASTBuilder::~ASTBuilder() Line 263	C++
 	slang.dll!Slang::ASTBuilder::`scalar deleting destructor'(unsigned int)	C++
 	slang.dll!Slang::RefObject::releaseReference() Line 41	C++
 	slang.dll!Slang::releaseReference(Slang::RefObject * obj) Line 65	C++
 	slang.dll!Slang::RefPtr<Slang::ASTBuilder>::~RefPtr<Slang::ASTBuilder>() Line 197	C++
 	slang.dll!Slang::Module::~Module()	C++
 	slang.dll!Slang::Module::`scalar deleting destructor'(unsigned int)	C++
 	slang.dll!Slang::RefObject::releaseReference() Line 41	C++
 	slang.dll!Slang::releaseReference(Slang::RefObject * obj) Line 65	C++
 	slang.dll!Slang::RefPtr<Slang::Module>::~RefPtr<Slang::Module>() Line 197	C++
 	slang.dll!std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>>::~pair<Slang::Name *,Slang::RefPtr<Slang::Module>>()	C++
 	slang.dll!std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>>::`scalar deleting destructor'(unsigned int)	C++
 	slang.dll!std::_Default_allocator_traits<std::allocator<std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>>>>::destroy<std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>>>(std::allocator<std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>>> & __formal, std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>> * const _Ptr) Line 709	C++
 	slang.dll!std::_Destroy_range<std::allocator<std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>>>>(std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>> * _First, std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>> * const _Last, std::allocator<std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>>> & _Al) Line 1067	C++
 	slang.dll!std::vector<std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>>,std::allocator<std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>>>>::_Tidy() Line 2050	C++
 	slang.dll!std::vector<std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>>,std::allocator<std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>>>>::~vector<std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>>,std::allocator<std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>>>>() Line 761	C++
 	slang.dll!ankerl::unordered_dense::v4_0_4::detail::table<Slang::Name *,Slang::RefPtr<Slang::Module>,Slang::Hash<Slang::Name *>,std::equal_to<Slang::Name *>,std::allocator<std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>>>,ankerl::unordered_dense::v4_0_4::bucket_type::standard,0>::~table<Slang::Name *,Slang::RefPtr<Slang::Module>,Slang::Hash<Slang::Name *>,std::equal_to<Slang::Name *>,std::allocator<std::pair<Slang::Name *,Slang::RefPtr<Slang::Module>>>,ankerl::unordered_dense::v4_0_4::bucket_type::standard,0>() Line 1196	C++
 	slang.dll!Slang::Dictionary<Slang::Name *,Slang::RefPtr<Slang::Module>,Slang::Hash<Slang::Name *>,std::equal_to<Slang::Name *>>::~Dictionary<Slang::Name *,Slang::RefPtr<Slang::Module>,Slang::Hash<Slang::Name *>,std::equal_to<Slang::Name *>>()	C++
 	slang.dll!Slang::Linkage::~Linkage() Line 1301	C++
 	slang.dll!Slang::Linkage::`scalar deleting destructor'(unsigned int)	C++
 	slang.dll!Slang::RefObject::releaseReference() Line 41	C++
 	slang.dll!Slang::Linkage::release() Line 2088	C++
 	reflection-api.exe!Slang::ComPtr<slang::ISession>::~ComPtr<slang::ISession>() Line 113	C++
 	reflection-api.exe!ExampleProgram::execute(int argc, char * * argv) Line 57	C++

I'm not sure if it's a bug or if there's an implicit requirement of GlobalSession living at least as long as the objects returned by createSession. I didn't see any mention of that in the docs so I expected the sessions to hold a strong reference to GlobalSession.
For context I encountered this issue with slang-rs (rust bindings to slang). I stored both session & globalsession in the same struct and the globalsession was deleted first due to field destruction order.

@aleino-nv
Copy link
Collaborator

Agreed, there is some missing documentation for IGlobalSession.

It seems to me like it would be nice if objects like ISession kept internal references to IGlobalSession if they depend on it, but of course there may be problems with that as well.

@csyonghe Is this a bug or API misuse? Should "sub-objects" of IGlobalSession keep references to the global session?

@aleino-nv
Copy link
Collaborator

I don't see this mentioned in the user guide either.

@csyonghe
Copy link
Collaborator

ISession should keep strong references to IGlobalSession. Usually with COM API, users do expect objects can be released in any order.

One thing we need to be careful is that right now the reference counting of RefObject is not atomic, which can lead to surprising bugs if the user is freeing objects from different threads concurrently. We will have to make sure at least counter operations from ComPtr is atomic.

@bmillsNV
Copy link
Collaborator

@aleino-nv can you help to document this behavior in the user guide? Then, please create a new issue for the proper fix which we can target at a later time.

@bmillsNV bmillsNV added goal:quality & productivity Quality issues and issues that impact our productivity coding day to day inside slang kind:documentation areas where we can improve documentation in codebase labels Feb 13, 2025
aleino-nv added a commit that referenced this issue Feb 27, 2025
@aleino-nv
Copy link
Collaborator

@bmillsNV Here is the issue for the deferred fix: #6480

I didn't set a milestone for it yet, so please do that if you have one in mind.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
goal:quality & productivity Quality issues and issues that impact our productivity coding day to day inside slang kind:documentation areas where we can improve documentation in codebase
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants