Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

static function + dispatch_once in header file will cause the once logic executable more than once #4904

Open
Kyle-Ye opened this issue Mar 5, 2024 · 0 comments

Comments

@Kyle-Ye
Copy link
Collaborator

Kyle-Ye commented Mar 5, 2024

Background

https://github.com/ChengzhiHuang/__inline__Demo
Credits: @ChengzhiHuang

  1. static variables in the static function are shared by the same compile Unit, but not by different compile Units.
  2. static variables in normal functions share one copy.

The NS_INLINE is defined as follows

#if !defined(NS_INLINE)
    #if defined(__GNUC__)
        #define NS_INLINE static __inline__ __attribute__((always_inline))
    #elif defined(__MWERKS__) || defined(__cplusplus)
        #define NS_INLINE static inline
    #elif defined(_MSC_VER)
        #define NS_INLINE static __inline
    #endif
#endif

Issue

So for the following code snippet in this repo, if we include and use them in diff compile units(eg. different .m files) the block in dispatch_once will be executed once for each compile units.

eg.

NS_INLINE BOOL __NSCalendarIsAutoupdating(NS_NON_BRIDGED(NSCalendar *) calendar) {
static dispatch_once_t onceToken;
static Class autoCalendarClass;
static Class olderAutoCalendarClass; // Pre 10.12/10.0
dispatch_once(&onceToken, ^{
autoCalendarClass = (Class)objc_lookUpClass("_NSAutoCalendar");
olderAutoCalendarClass = (Class)objc_lookUpClass("NSAutoCalendar");
});
return (autoCalendarClass && [calendar isKindOfClass:autoCalendarClass]) || (olderAutoCalendarClass && [calendar isKindOfClass:olderAutoCalendarClass]);
}

NS_INLINE BOOL __NSLocaleIsAutoupdating(NS_NON_BRIDGED(NSLocale *)locale) {
static dispatch_once_t onceToken;
static Class autoLocaleClass;
dispatch_once(&onceToken, ^{
autoLocaleClass = (Class)objc_lookUpClass("NSAutoLocale");
});
return [locale isKindOfClass:autoLocaleClass];
}

NS_INLINE BOOL __NSTimeZoneIsAutoupdating(NS_NON_BRIDGED(NSTimeZone *)timeZone) {
static dispatch_once_t onceToken;
static Class autoTimeZoneClass;
dispatch_once(&onceToken, ^{
autoTimeZoneClass = (Class)objc_lookUpClass("__NSLocalTimeZone");
});
return [timeZone isKindOfClass:autoTimeZoneClass];
}

Example project

image

CDemoKit.zip

Solution

  1. Use __inline__ __attribute__((always_inline)) directly instead of using NS_INLINE
  2. To be discussed ...

Other info

https://forums.swift.org/t/potential-issue-for-ns-inline-dispatch-once-on-swift-corelibs-foundation/70439

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant