We maintain a Native Module for React-Native that supports Apple platforms, and so we (and our users) have a dependency on Folly through the RN ecosystem.
Our module statically links with libc++, and some of our own C++ dependencies use std::steady_clock, which in recent versions of libc++ calls clock_gettime(CLOCK_MONOTONIC_RAW, &tp) on Apple platforms.
Our users have been reporting that std::steady_clock::now() throws after calling clock_gettime, resulting in an uncaught exception and a crash:
It turns out that Folly's fallback implementation exports its clock_gettime implementation globally, as a weak symbol! So when our native module is statically linked into the user's application, Folly's clock_gettime symbol will bind to libc++'s clock_gettime import, even on devices >= iOS 10 where the symbol would otherwise be loaded from libsystem_c.dylib at runtime.
That would be fine, except Folly's clock_gettime does not support CLOCK_MONOTONIC_RAW. It returns EINVAL, which causes steady_clock to throw, and our users get to keep both pieces. This is suboptimal :(
The macro in Time.h
The React-Native build system can be fairly complex, and as a native module we don't have control on all the other dependencies our users may have and on how Folly is compiled by those deps. However it is our understanding that the clock_gettime fallback can end up getting pulled in either when a dep supports iOS platforms < 10 (which triggers the macro in Time.h). (This can also happen if a dep is still using an older version of Folly where the macro was accidentally always true in some cases, but presumably these deps will update eventually).
Note that this is a different issue from https://github.com/facebook/folly/issues/1470, which results in breakage when that macro is false. Here things break when the macro is true.
Expected behavior
This incompatibility is caused by a combination of two things:
If anyone in a React-Native user's dependency tree imports Folly with support for iOS 9, the symbol will be global and affects all other dependencies, outside of Folly.
The clock_gettime fallback supports less features than the native Apple implementation, and in particular does not support CLOCK_MONOTONIC_RAW, which is required by libc++ on Apple platforms.
We are currently working around the bug by using a patched version of libc++ that unconditionally calls mach_absolute_time instead of clock_gettime, even when our target platforms have this support, however considering the above I think the bug can be fixed in one of three ways:
Ideally, Folly should not expose its clock_gettime polyfill to other dependencies. It seems there was a patch at some point that namespaced the symbol, though it was quickly reverted. There may be some other way to achieve the same result.
Consider dropping the compatibility macros entirely. It seems the clock_gettime situation is complicated enough on Apple platforms that by trying to support iOS 9 and lower, the macro is causing more incompatibilities for newer versions.
If Folly exports a polyfill globally, it should support CLOCK_MONOTONIC_RAW, which according to libc++ is "the only acceptable implementation of steady_clock".
Any one of these would fix this issue, though I think we would be happy with any solution that resolves the incompatibility between React-Native libraries that use Folly and libc++.
Thank you!
Hello,
We maintain a Native Module for React-Native that supports Apple platforms, and so we (and our users) have a dependency on Folly through the RN ecosystem.
Our module statically links with libc++, and some of our own C++ dependencies use
std::steady_clock
, which in recent versions of libc++ callsclock_gettime(CLOCK_MONOTONIC_RAW, &tp)
on Apple platforms. Our users have been reporting thatstd::steady_clock::now()
throws after callingclock_gettime
, resulting in an uncaught exception and a crash:Why do things break
It turns out that Folly's fallback implementation exports its
clock_gettime
implementation globally, as a weak symbol! So when our native module is statically linked into the user's application, Folly's clock_gettime symbol will bind to libc++'sclock_gettime
import, even on devices >= iOS 10 where the symbol would otherwise be loaded fromlibsystem_c.dylib
at runtime.That would be fine, except Folly's clock_gettime does not support CLOCK_MONOTONIC_RAW. It returns EINVAL, which causes steady_clock to throw, and our users get to keep both pieces. This is suboptimal :(
The macro in Time.h
The React-Native build system can be fairly complex, and as a native module we don't have control on all the other dependencies our users may have and on how Folly is compiled by those deps. However it is our understanding that the clock_gettime fallback can end up getting pulled in either when a dep supports iOS platforms < 10 (which triggers the macro in Time.h). (This can also happen if a dep is still using an older version of Folly where the macro was accidentally always true in some cases, but presumably these deps will update eventually).
Note that this is a different issue from https://github.com/facebook/folly/issues/1470, which results in breakage when that macro is false. Here things break when the macro is true.
Expected behavior
This incompatibility is caused by a combination of two things:
clock_gettime
fallback supports less features than the native Apple implementation, and in particular does not supportCLOCK_MONOTONIC_RAW
, which is required by libc++ on Apple platforms.We are currently working around the bug by using a patched version of libc++ that unconditionally calls
mach_absolute_time
instead ofclock_gettime
, even when our target platforms have this support, however considering the above I think the bug can be fixed in one of three ways:clock_gettime
polyfill to other dependencies. It seems there was a patch at some point that namespaced the symbol, though it was quickly reverted. There may be some other way to achieve the same result.clock_gettime
situation is complicated enough on Apple platforms that by trying to support iOS 9 and lower, the macro is causing more incompatibilities for newer versions.CLOCK_MONOTONIC_RAW
, which according to libc++ is "the only acceptable implementation of steady_clock".Any one of these would fix this issue, though I think we would be happy with any solution that resolves the incompatibility between React-Native libraries that use Folly and libc++.
Thank you!