Related issue:
Issue 852: Core-dump after SandboxDestroyCallback on arm32 plateform with version 1.2.0
Description
In ApplyCallback, a detached worker thread is created to perform the async apply operation:
std::thread worker{ [token, workCompletionData, workflowData] {
const ADUC_Result result{ ADUC::ExceptionUtils::CallResultMethodAndHandleExceptions(
ADUC_Result_Failure, [&token, &workCompletionData, &workflowData]() -> ADUC_Result {
return static_cast<LinuxPlatformLayer*>(token)->Apply(workflowData);
}) };
workCompletionData->WorkCompletionCallback(
workCompletionData->WorkCompletionToken, result, true /* isAsync */);
} };
worker.detach();
However, this introduces a lifecycle issue:
- The thread is detached, meaning it runs independently of the caller.
- The lambda captures raw pointers (
workCompletionData, workflowData) which are not owned by the thread.
- If the main thread (or workflow) exits before the worker thread completes, these pointers may become invalid.
This contradicts the comment in the code:
// Pointers passed to this method are guaranteed to be valid until WorkCompletionCallback is called.
There is currently no mechanism enforcing this guarantee when using a detached thread.
Impact
This can lead to:
- Use-after-free
- Undefined behavior
- Crash / core dump during async apply
- Non-deterministic failures depending on timing
This is especially likely when:
- The agent shuts down during an ongoing apply
- The workflow lifecycle ends early
- Errors or reboots occur before callback execution
Expected Behavior
One of the following should be guaranteed:
- The lifetime of
workflowData and workCompletionData is extended until the worker thread completes and calls WorkCompletionCallback, or
- The worker thread must not outlive the owning context (i.e., should not be detached without lifecycle control)
Actual Behavior
- The worker thread is detached
- No ownership or lifetime management is enforced
- The thread may access invalid memory if the main thread exits early
Root Cause Analysis
- Use of
std::thread::detach() without lifecycle synchronization
- Capturing raw pointers into an async execution context
- Lack of ownership model (no
shared_ptr / ref-counting / cancellation)
Suggested Fixes
Possible approaches:
-
Avoid detach()
- Use joinable threads or a managed thread pool
-
Introduce shared ownership
- Use
std::shared_ptr for workflowData and related structures
-
Agent-managed async execution
- Let the agent manage thread lifecycle instead of handler
-
Shutdown / cancellation support
- Ensure worker threads are stopped or joined during agent shutdown
Additional Notes
This issue appears to be a general concurrency/lifecycle design flaw and may affect other async handlers using similar patterns.
Environment
- Component: LinuxPlatformLayer / ApplyCallback
- Version: (please fill in)
- Reproducibility: Intermittent (timing-dependent)
Summary
Detached threads combined with raw pointer capture can lead to use-after-free and crashes. This is a lifecycle management bug rather than intended behavior.
Related issue:
Issue 852: Core-dump after SandboxDestroyCallback on arm32 plateform with version 1.2.0
Description
In
ApplyCallback, a detached worker thread is created to perform the async apply operation:std::thread worker{ [token, workCompletionData, workflowData] { const ADUC_Result result{ ADUC::ExceptionUtils::CallResultMethodAndHandleExceptions( ADUC_Result_Failure, [&token, &workCompletionData, &workflowData]() -> ADUC_Result { return static_cast<LinuxPlatformLayer*>(token)->Apply(workflowData); }) }; workCompletionData->WorkCompletionCallback( workCompletionData->WorkCompletionToken, result, true /* isAsync */); } }; worker.detach();However, this introduces a lifecycle issue:
workCompletionData,workflowData) which are not owned by the thread.This contradicts the comment in the code:
// Pointers passed to this method are guaranteed to be valid until WorkCompletionCallback is called.There is currently no mechanism enforcing this guarantee when using a detached thread.
Impact
This can lead to:
This is especially likely when:
Expected Behavior
One of the following should be guaranteed:
workflowDataandworkCompletionDatais extended until the worker thread completes and callsWorkCompletionCallback, orActual Behavior
Root Cause Analysis
std::thread::detach()without lifecycle synchronizationshared_ptr/ ref-counting / cancellation)Suggested Fixes
Possible approaches:
Avoid
detach()Introduce shared ownership
std::shared_ptrforworkflowDataand related structuresAgent-managed async execution
Shutdown / cancellation support
Additional Notes
This issue appears to be a general concurrency/lifecycle design flaw and may affect other async handlers using similar patterns.
Environment
Summary
Detached threads combined with raw pointer capture can lead to use-after-free and crashes. This is a lifecycle management bug rather than intended behavior.