Summary
AducIotAgent intermittently crashes with SIGSEGV inside the dynamic loader
(ld-linux.so) during shutdown. Exit-only — the agent restarts fine, but
systemd records the stop as core-dump. Seen on aarch64, 1.4.0.
Root cause
ExtensionManager::Uninit() runs twice during shutdown:
- via
AzureDeviceUpdateCoreInterface_Destroy (linux_adu_core_impl.cpp, from
ADUC_PnP_Components_Destroy), and
- via
ExtensionManager_Uninit() in the agent's ShutdownAgent (main.c).
ExtensionManager::UnloadAllExtensions() dlcloses the content-downloader
library (in _libs) and clears _libs, but never resets the static
_contentDownloader handle or _contentDownloaderContractVersion. So the second
call still sees _contentDownloader != nullptr and a V2 contract, and runs
dlsym(_contentDownloader, "Cleanup") on the freed handle. glibc's
do_lookup_x then walks a freed link_map → intermittent SEGV_MAPERR
(intermittent because the freed memory is sometimes still mapped).
Symbolized crashing stack (from a device core):
do_lookup_x (undef_name="Cleanup", undef_map=<freed link_map>) ld.so
_dl_lookup_symbol_x -> do_sym -> _dl_sym -> ___dlsym
ExtensionManager::UnloadAllExtensions() extension_manager.cpp:418
ShutdownAgent -> ExtensionManager_Uninit
Reproduces when
A V2-contract content downloader is loaded (curl is the default in 1.4.0) and
the agent is stopped (SIGTERM) — e.g. during an OS update. Intermittent.
Fix
Reset _contentDownloader and _contentDownloaderContractVersion after the
dlclose loop in UnloadAllExtensions() so a repeat Uninit is a no-op. PR
attached.
Summary
AducIotAgentintermittently crashes withSIGSEGVinside the dynamic loader(
ld-linux.so) during shutdown. Exit-only — the agent restarts fine, butsystemd records the stop as
core-dump. Seen on aarch64, 1.4.0.Root cause
ExtensionManager::Uninit()runs twice during shutdown:AzureDeviceUpdateCoreInterface_Destroy(linux_adu_core_impl.cpp, fromADUC_PnP_Components_Destroy), andExtensionManager_Uninit()in the agent'sShutdownAgent(main.c).ExtensionManager::UnloadAllExtensions()dlcloses the content-downloaderlibrary (in
_libs) and clears_libs, but never resets the static_contentDownloaderhandle or_contentDownloaderContractVersion. So the secondcall still sees
_contentDownloader != nullptrand a V2 contract, and runsdlsym(_contentDownloader, "Cleanup")on the freed handle. glibc'sdo_lookup_xthen walks a freedlink_map→ intermittentSEGV_MAPERR(intermittent because the freed memory is sometimes still mapped).
Symbolized crashing stack (from a device core):
Reproduces when
A V2-contract content downloader is loaded (curl is the default in 1.4.0) and
the agent is stopped (SIGTERM) — e.g. during an OS update. Intermittent.
Fix
Reset
_contentDownloaderand_contentDownloaderContractVersionafter thedlcloseloop inUnloadAllExtensions()so a repeatUninitis a no-op. PRattached.