facebook / facebook/folly

Deadlock with SharedMutex across multiple DSOs and visibility=hidden

Open
#1,558 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
30.5k
Forks
5.9k
PR merge metrics
No merged PRs in 30d

Description

### Summary

When accessing a `folly::SharedMutex` instance from multiple DSOs and program and folly compiled with `-fvisibility=hidden`, a deadlock is seen when at least one thread is attempting to acquire a write lock. Backtraces suggest that the writer is waiting for some outstanding reader to unlock; but no such reader appears to have the lock acquired.

* Version: : v2021.04.12.00 and v2010.08.24.00 both affected.
* Environment: GCC 7.5.0, Ubuntu 18.04
* Reproducer at: https://github.com/daverigby/folly_SharedMutexIssue

Note: this is a similar issue to #1431.

### Details

From my limited understanding of `SharedMutex`, what seems to be occurring is that there's multiple copies of the `SharedMutex<>::deferredReaders` static array present in the process; and as such the tracking of which readers are outstanding is broken. I believe this is due to `deferredReaders` having local (hidden) visibility - for example examining the two DSOs in my test program, note the LOCAL visibility:

```
$ readelf -sW main | c++filt | grep 'folly::SharedMutexImpl::deferredReaders
$ readelf -sW libshared.so | c++filt | grep 'folly::SharedMutexImpl::deferredReaders
```

If I instantiate SharedMutex with it's own tag:
```
struct FOLLY_EXPORT MyTag {};
using Mutex = folly::SharedMutexImpl;
```

_and_ modify the declaration of `SharedMutexImpl` to mark it with `FOLLY_EXPORT` the test doesn't hang (run for > 1 hour with no issues):

```
diff --git a/folly/SharedMutex.h b/folly/SharedMutex.h
index 95faa76f5..44102168b 100644
--- a/folly/SharedMutex.h
+++ b/folly/SharedMutex.h
@@ -330,3 +330,3 @@ template <
bool TrackThreadId = false>
-class SharedMutexImpl : std::conditional_t<
+class FOLLY_EXPORT SharedMutexImpl : std::conditional_t<
TrackThreadId,
```

Symbol visibility after this change (MyTag version):

```
$ readelf -sW libshared.so | c++filt | grep 'folly::SharedMutexImpl::deferredReaders
```

Note both the change to `SharedMutexImpl`'s declaration _and_ the explicit tag is needed for the visibility to change (and test to pass) for me. I don't exactly understand why that is the case; given I only need to change the tag I assume that the default ``void`` tag has hidden visibility (possibly due to that being the default I set?) - but none of the other types used in the template instantiation need to be changed to fix the problem...

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.