Fix FreeBSD shm_unlink failure by adding '/' prefix in remove()

Problem: Tests fail on the second run on FreeBSD with ShmTest.RemoveByName failing.
After the first test run completes, subsequent runs fail because shared memory
objects are not properly removed.

Root cause: FreeBSD's shm_unlink() is stricter than Linux about POSIX compliance.
The remove(char const * name) function was calling shm_unlink() without the '/'
prefix, while acquire() was using '/'+name format. This inconsistency caused:
- Linux: Silently tolerates both /name and name formats
- FreeBSD: Strictly requires /name format, shm_unlink("name") fails

When shm_unlink() fails to remove the shared memory object:
1. First test run creates /remove_by_name_test_1
2. Test calls shm::remove("remove_by_name_test_1")
3. shm_unlink("remove_by_name_test_1") fails on FreeBSD (missing '/')
4. Shared memory object remains in the system
5. Second test run tries to reuse the same name -> conflict -> test fails

Solution:
1. Fix remove(char const * name) to prepend '/' to the name for consistency
   with acquire() function, ensuring POSIX compliance
2. Add error checking for all shm_unlink() calls to log failures with errno

This ensures proper cleanup on FreeBSD and maintains compatibility with Linux.

Changes:
- Modified remove(char const * name) to use '/'+name format
- Added error logging for all three shm_unlink() calls
- Now consistent with POSIX requirement: shared memory names must be /somename

Tested on FreeBSD 15: Multiple consecutive test runs now pass without failures.
This commit is contained in:
木头云 2025-12-06 07:12:39 +00:00
parent 37f16cea47
commit 2593213d9c

View File

@ -173,7 +173,10 @@ std::int32_t release(id_t id) noexcept {
else if ((ret = acc_of(ii->mem_, ii->size_).fetch_sub(1, std::memory_order_acq_rel)) <= 1) {
::munmap(ii->mem_, ii->size_);
if (!ii->name_.empty()) {
::shm_unlink(ii->name_.c_str());
int unlink_ret = ::shm_unlink(ii->name_.c_str());
if (unlink_ret == -1) {
ipc::error("fail shm_unlink[%d]: %s\n", errno, ii->name_.c_str());
}
}
}
else ::munmap(ii->mem_, ii->size_);
@ -190,7 +193,10 @@ void remove(id_t id) noexcept {
auto name = std::move(ii->name_);
release(id);
if (!name.empty()) {
::shm_unlink(name.c_str());
int unlink_ret = ::shm_unlink(name.c_str());
if (unlink_ret == -1) {
ipc::error("fail shm_unlink[%d]: %s\n", errno, name.c_str());
}
}
}
@ -199,7 +205,12 @@ void remove(char const * name) noexcept {
ipc::error("fail remove: name is empty\n");
return;
}
::shm_unlink(name);
// For portable use, a shared memory object should be identified by name of the form /somename.
ipc::string op_name = ipc::string{"/"} + name;
int unlink_ret = ::shm_unlink(op_name.c_str());
if (unlink_ret == -1) {
ipc::error("fail shm_unlink[%d]: %s\n", errno, op_name.c_str());
}
}
} // namespace shm