Fix unregister issue
This commit is contained in:
@@ -13,8 +13,12 @@
|
||||
|
||||
// Handle registry with refcount — prevents use-after-free when
|
||||
// ReleaseANSMOTHandle is called while an operation is still running.
|
||||
static std::unordered_map<ANSCENTER::ANSMOT*, int>& MOTHandleRegistry() {
|
||||
static std::unordered_map<ANSCENTER::ANSMOT*, int> s;
|
||||
// destructionStarted: set by the first Unregister caller; blocks new Acquires
|
||||
// and makes subsequent Unregister calls return false without deleting.
|
||||
// Prevents double-free when Release is raced on the same handle.
|
||||
struct MOTEntry { int refcount; bool destructionStarted; };
|
||||
static std::unordered_map<ANSCENTER::ANSMOT*, MOTEntry>& MOTHandleRegistry() {
|
||||
static std::unordered_map<ANSCENTER::ANSMOT*, MOTEntry> s;
|
||||
return s;
|
||||
}
|
||||
static std::mutex& MOTHandleRegistryMutex() {
|
||||
@@ -28,14 +32,15 @@ static std::condition_variable& MOTHandleRegistryCV() {
|
||||
|
||||
static void RegisterMOTHandle(ANSCENTER::ANSMOT* h) {
|
||||
std::lock_guard<std::mutex> lk(MOTHandleRegistryMutex());
|
||||
MOTHandleRegistry()[h] = 1;
|
||||
MOTHandleRegistry()[h] = { 1, false };
|
||||
}
|
||||
|
||||
static ANSCENTER::ANSMOT* AcquireMOTHandle(ANSCENTER::ANSMOT* h) {
|
||||
std::lock_guard<std::mutex> lk(MOTHandleRegistryMutex());
|
||||
auto it = MOTHandleRegistry().find(h);
|
||||
if (it == MOTHandleRegistry().end()) return nullptr;
|
||||
it->second++;
|
||||
if (it->second.destructionStarted) return nullptr;
|
||||
it->second.refcount++;
|
||||
return h;
|
||||
}
|
||||
|
||||
@@ -43,23 +48,25 @@ static bool ReleaseMOTHandleRef(ANSCENTER::ANSMOT* h) {
|
||||
std::lock_guard<std::mutex> lk(MOTHandleRegistryMutex());
|
||||
auto it = MOTHandleRegistry().find(h);
|
||||
if (it == MOTHandleRegistry().end()) return false;
|
||||
it->second--;
|
||||
if (it->second <= 0) {
|
||||
MOTHandleRegistry().erase(it);
|
||||
it->second.refcount--;
|
||||
if (it->second.refcount <= 0) {
|
||||
MOTHandleRegistryCV().notify_all();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return false; // Only Unregister deletes.
|
||||
}
|
||||
|
||||
static bool UnregisterMOTHandle(ANSCENTER::ANSMOT* h) {
|
||||
std::unique_lock<std::mutex> lk(MOTHandleRegistryMutex());
|
||||
auto it = MOTHandleRegistry().find(h);
|
||||
if (it == MOTHandleRegistry().end()) return false;
|
||||
it->second--;
|
||||
if (it->second.destructionStarted) {
|
||||
return false; // Another thread already owns the delete.
|
||||
}
|
||||
it->second.destructionStarted = true;
|
||||
it->second.refcount--;
|
||||
bool ok = MOTHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
|
||||
auto it2 = MOTHandleRegistry().find(h);
|
||||
return it2 == MOTHandleRegistry().end() || it2->second <= 0;
|
||||
return it2 == MOTHandleRegistry().end() || it2->second.refcount <= 0;
|
||||
});
|
||||
if (!ok) {
|
||||
OutputDebugStringA("WARNING: UnregisterMOTHandle timed out waiting for in-flight operations\n");
|
||||
@@ -106,14 +113,15 @@ BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
extern "C" __declspec(dllexport) int __cdecl CreateANSMOTHandle(ANSCENTER::ANSMOT **Handle, int motType) {
|
||||
if (Handle == nullptr) return 0;
|
||||
try {
|
||||
// Release existing handle if called twice (prevents leak from LabVIEW)
|
||||
if (*Handle) {
|
||||
if (UnregisterMOTHandle(*Handle)) {
|
||||
(*Handle)->Destroy();
|
||||
delete *Handle;
|
||||
}
|
||||
*Handle = nullptr;
|
||||
}
|
||||
// Pure constructor: ignore *Handle(in). LabVIEW's CLF Node marshalling
|
||||
// reuses the same temp buffer per call site, so *Handle(in) often holds
|
||||
// leftover bytes from the previous Create's output even when the actual
|
||||
// LabVIEW wire is a different, freshly-allocated instance. Inspecting
|
||||
// *Handle(in) and destroying what we "see" tears down legitimate
|
||||
// parallel instances. (Same reasoning as CreateANSAWSHandle.)
|
||||
// Trade-off: a true double-Create on the same wire leaks the prior
|
||||
// handle -- caller's bug; the alternative is far worse.
|
||||
*Handle = nullptr;
|
||||
|
||||
switch (motType) {
|
||||
case 0: //BYTETRACKNCNN =0
|
||||
|
||||
Reference in New Issue
Block a user