Bug #120342 register_service_nolock() leaves stale interface_mapping entry if default-name map insertion throws
Submitted: 25 Apr 9:01 Modified: 4 May 5:40
Reporter: S F. Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Components / Services Severity:S3 (Non-critical)
Version:MySQL Server trunk @ 447eb26e094b444a88c OS:Ubuntu (Linux 5.4.0-216-generic)
Assigned to: CPU Architecture:x86 (x86_64)
Tags: components, dangling-pointer, exception-safety, libminchassis, registry

[25 Apr 9:01] S F.
Description:
mysql_registry_no_lock_imp::register_service_nolock() publishes
imp.get() into service_registry and interface_mapping before ownership
is released.

Relevant sequence:
1. service_registry.emplace(imp->name_c_str(), imp.get())
2. interface_mapping.emplace(imp->interface(), imp.get())
3. service_registry.emplace_hint(addition_result.first,
     imp->service_name_c_str(), imp.get())

If step 3 throws, the catch only erases the first service_registry
entry. The unique_ptr then destroys mysql_service_implementation, but
interface_mapping still contains the freed pointer.

The stale pointer can later be dereferenced during component unload:
dynamic_loader.cc:1338 calls
mysql_registry_imp::get_service_implementation_reference_count(...)
which reaches registry_no_lock.cc:82:
return iter->second->get_reference_count();

How to repeat:
I do not currently have a deterministic in-tree trigger without
allocation fault injection. The realistic throw point is std::bad_alloc
during the second service_registry insertion.

Suggested fix:
Either delay interface_mapping publication until all service_registry
insertions succeed, or roll back the interface_mapping entry in the
catch path before imp is destroyed.
[4 May 5:40] Miroslav Rajcic
Thank you for the report.