/ CoreFoundation / Base.subproj / CFUtilities.c
CFUtilities.c
   1  /*	CFUtilities.c
   2  	Copyright (c) 1998-2019, Apple Inc. and the Swift project authors
   3   
   4  	Portions Copyright (c) 2014-2019, Apple Inc. and the Swift project authors
   5  	Licensed under Apache License v2.0 with Runtime Library Exception
   6  	See http://swift.org/LICENSE.txt for license information
   7  	See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
   8  	Responsibility: Tony Parker
   9  */
  10  
  11  #if __has_include(<xpc/xpc_transaction_deprecate.h>)
  12  #import <xpc/xpc_transaction_deprecate.h>
  13  #undef XPC_TRANSACTION_DEPRECATED
  14  #define XPC_TRANSACTION_DEPRECATED
  15  #endif
  16  
  17  #include <CoreFoundation/CFBase.h>
  18  #include <CoreFoundation/CFPriv.h>
  19  #include "CFInternal.h"
  20  #include "CFLocaleInternal.h"
  21  #if !TARGET_OS_WASI
  22  #include "CFBundle_Internal.h"
  23  #endif
  24  #include <CoreFoundation/CFPriv.h>
  25  #if TARGET_OS_MAC || TARGET_OS_WIN32
  26  #include <CoreFoundation/CFBundle.h>
  27  #endif
  28  #include <CoreFoundation/CFURLAccess.h>
  29  #if !TARGET_OS_WASI
  30  #include <CoreFoundation/CFPropertyList.h>
  31  #endif
  32  #if TARGET_OS_WIN32
  33  #include <process.h>
  34  #endif
  35  #if TARGET_OS_ANDROID
  36  #include <android/log.h>
  37  #endif
  38  #include <math.h>
  39  #include <string.h>
  40  #include <stdio.h>
  41  #include <stdlib.h>
  42  #if TARGET_OS_MAC
  43  #include <asl.h>
  44  #else
  45  #define ASL_LEVEL_EMERG 0
  46  #define ASL_LEVEL_DEBUG 7
  47  #endif
  48  
  49  
  50  #if TARGET_OS_MAC
  51  #include <unistd.h>
  52  #include <sys/uio.h>
  53  #include <mach/mach.h>
  54  #include <mach-o/loader.h>
  55  #include <mach-o/dyld.h>
  56  #include <crt_externs.h>
  57  #include <dlfcn.h>
  58  #include <vproc.h>
  59  #include <libproc.h>
  60  #include <sys/sysctl.h>
  61  #include <sys/stat.h>
  62  #include <mach/mach.h>
  63  #include <mach/mach_vm.h>
  64  #include <sys/mman.h>
  65  #include <stdio.h>
  66  #include <sys/errno.h>
  67  #include <mach/mach_time.h>
  68  #include <Block.h>
  69  #include <os/lock.h>
  70  #endif
  71  
  72  #if TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_WASI
  73  #include <string.h>
  74  #include <sys/mman.h>
  75  #endif
  76  
  77  #if __has_include(<unistd.h>)
  78  #include <unistd.h>
  79  #endif
  80  #if _POSIX_THREADS
  81  #include <pthread.h>
  82  #endif
  83  
  84  #if TARGET_OS_LINUX
  85  #ifdef HAVE_SCHED_GETAFFINITY
  86  #include <sched.h>
  87  #endif
  88  #endif
  89  
  90  
  91  #if !defined(CF_HAVE_HW_CONFIG_COMMPAGE) && defined(_COMM_PAGE_LOGICAL_CPUS) && defined(_COMM_PAGE_PHYSICAL_CPUS) && defined(_COMM_PAGE_ACTIVE_CPUS) && !__has_feature(address_sanitizer)
  92  #define CF_HAVE_HW_CONFIG_COMMPAGE 1
  93  #else
  94  #define CF_HAVE_HW_CONFIG_COMMPAGE 0
  95  #endif
  96  
  97  CF_PRIVATE os_log_t _CFOSLog(void) {
  98      static os_log_t logger = NULL;
  99  
 100      static dispatch_once_t onceToken;
 101      dispatch_once(&onceToken, ^{
 102          logger = os_log_create("com.apple.foundation", "general");
 103      });
 104      return logger;
 105  }
 106  
 107  CF_PRIVATE os_log_t _CFMethodSignatureROMLog(void) {
 108      static os_log_t logger;
 109      static dispatch_once_t onceToken;
 110      dispatch_once(&onceToken, ^{
 111          logger = os_log_create("com.apple.foundation", "MethodSignatureROM");
 112      });
 113      return logger;
 114  }
 115  
 116  CF_PRIVATE os_log_t _CFRuntimeIssuesLog(void) {
 117      static os_log_t logger;
 118      static dispatch_once_t onceToken;
 119      dispatch_once(&onceToken, ^{
 120          logger = os_log_create(OS_LOG_SUBSYSTEM_RUNTIME_ISSUES, "CoreFoundation");
 121      });
 122      return logger;
 123  }
 124  
 125  CF_PRIVATE os_log_t _CFFoundationRuntimeIssuesLog(void) {
 126      static os_log_t logger;
 127      static dispatch_once_t onceToken;
 128      dispatch_once(&onceToken, ^{
 129          logger = os_log_create(OS_LOG_SUBSYSTEM_RUNTIME_ISSUES, "Foundation");
 130      });
 131      return logger;
 132  }
 133  
 134  /* Comparator is passed the address of the values. */
 135  /* Binary searches a sorted-increasing array of some type.
 136     Return value is either 1) the index of the element desired,
 137     if the target value exists in the list, 2) greater than or
 138     equal to count, if the element is greater than all the values
 139     in the list, or 3) the index of the element greater than the
 140     target value.
 141  
 142     For example, a search in the list of integers:
 143  	2 3 5 7 11 13 17
 144  
 145     For...		Will Return...
 146  	2		    0
 147     	5		    2
 148  	23		    7
 149  	1		    0
 150  	9		    4
 151  
 152     For instance, if you just care about found/not found:
 153     index = CFBSearch(list, count, elem);
 154     if (count <= index || list[index] != elem) {
 155     	* Not found *
 156     } else {
 157     	* Found *
 158     }
 159     
 160  */
 161  CF_PRIVATE CFIndex CFBSearch(const void *element, CFIndex elementSize, const void *list, CFIndex count, CFComparatorFunction comparator, void *context) {
 162      const char *ptr = (const char *)list;
 163      while (0 < count) {
 164          CFIndex half = count / 2;
 165          const char *probe = ptr + elementSize * half;
 166          CFComparisonResult cr = comparator(element, probe, context);
 167  	if (0 == cr) return (probe - (const char *)list) / elementSize;
 168          ptr = (cr < 0) ? ptr : probe + elementSize;
 169          count = (cr < 0) ? half : (half + (count & 1) - 1);
 170      }
 171      return (ptr - (const char *)list) / elementSize;
 172  }
 173  
 174  
 175  #define ELF_STEP(B) T1 = (H << 4) + B; T2 = T1 & 0xF0000000; if (T2) T1 ^= (T2 >> 24); T1 &= (~T2); H = T1;
 176  
 177  CFHashCode CFHashBytes(uint8_t *bytes, CFIndex length) {
 178      /* The ELF hash algorithm, used in the ELF object file format */
 179      UInt32 H = 0, T1, T2;
 180      SInt32 rem = length;
 181      while (3 < rem) {
 182  	ELF_STEP(bytes[length - rem]);
 183  	ELF_STEP(bytes[length - rem + 1]);
 184  	ELF_STEP(bytes[length - rem + 2]);
 185  	ELF_STEP(bytes[length - rem + 3]);
 186  	rem -= 4;
 187      }
 188      switch (rem) {
 189      case 3:  ELF_STEP(bytes[length - 3]);
 190      case 2:  ELF_STEP(bytes[length - 2]);
 191      case 1:  ELF_STEP(bytes[length - 1]);
 192      case 0:  ;
 193      }
 194      return H;
 195  }
 196  
 197  #undef ELF_STEP
 198  
 199  
 200  #if TARGET_OS_MAC
 201  CF_PRIVATE uintptr_t __CFFindPointer(uintptr_t ptr, uintptr_t start) {
 202      vm_map_t task = mach_task_self();
 203      mach_vm_address_t address = start;
 204      for (;;) {
 205  	mach_vm_size_t size = 0;
 206  	vm_region_basic_info_data_64_t info;
 207          mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
 208  	mach_port_t object_name;
 209          kern_return_t ret = mach_vm_region(task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &count, &object_name);
 210          if (KERN_SUCCESS != ret) break;
 211  	boolean_t scan = (info.protection & VM_PROT_WRITE) ? 1 : 0;
 212  	if (scan) {
 213  	    uintptr_t *addr = (uintptr_t *)((uintptr_t)address);
 214  	    uintptr_t *end = (uintptr_t *)((uintptr_t)address + (uintptr_t)size);
 215  	    while (addr < end) {
 216  	        if ((uintptr_t *)start <= addr && *addr == ptr) {
 217  		    return (uintptr_t)addr;
 218  	        }
 219  	        addr++;
 220  	    }
 221  	}
 222          address += size;
 223      }
 224      return 0;
 225  }
 226  
 227  CF_PRIVATE void __CFDumpAllPointerLocations(uintptr_t ptr) {
 228      uintptr_t addr = 0;
 229      do {
 230          addr = __CFFindPointer(ptr, sizeof(void *) + addr);
 231          printf("%p\n", (void *)addr);
 232      } while (addr != 0);
 233  }
 234  #endif
 235  
 236  CF_PRIVATE CFDataRef _CFDataCreateFromURL(CFURLRef resourceURL, CFErrorRef *error) {
 237      CFDataRef result = NULL;
 238  #pragma GCC diagnostic push
 239  #pragma GCC diagnostic ignored "-Wdeprecated"
 240      SInt32 errorCode = 0;
 241      if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, resourceURL, &result, NULL, NULL, &errorCode)) {
 242          if (error) {
 243              // This error domain is not quite right, but it's better than Cocoa
 244              *error = CFErrorCreate(kCFAllocatorSystemDefault, kCFErrorDomainOSStatus, errorCode, NULL);
 245              return NULL;
 246          }
 247      }
 248  #pragma GCC diagnostic pop
 249      return result;
 250  }
 251  
 252  static CFStringRef copySystemVersionPath(CFStringRef suffix) {
 253  #if TARGET_IPHONE_SIMULATOR
 254      const char *simulatorRoot = getenv("IPHONE_SIMULATOR_ROOT");
 255      if (!simulatorRoot) simulatorRoot = getenv("CFFIXED_USER_HOME");
 256      if (!simulatorRoot) simulatorRoot = "/";
 257      return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%s%@"), simulatorRoot, suffix);
 258  #else
 259      return CFStringCreateCopy(kCFAllocatorSystemDefault, suffix);
 260  #endif
 261  }
 262  
 263  // Looks for localized version of "nonLocalized" in the SystemVersion bundle
 264  // If not found, and returnNonLocalizedFlag == true, will return the non localized string (retained of course), otherwise NULL
 265  // If bundlePtr != NULL, will use *bundlePtr and will return the bundle in there; otherwise bundle is created and released
 266  #if TARGET_OS_MAC
 267  static CFStringRef _CFCopyLocalizedVersionKey(CFBundleRef *bundlePtr, CFStringRef nonLocalized) {
 268      CFStringRef localized = NULL;
 269      CFBundleRef locBundle = bundlePtr ? *bundlePtr : NULL;
 270      if (!locBundle) {
 271          CFStringRef path = copySystemVersionPath(CFSTR("/System/Library/CoreServices/SystemVersion.bundle"));
 272          CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, path, kCFURLPOSIXPathStyle, false);
 273          CFRelease(path);
 274          if (url) {
 275              locBundle = CFBundleCreate(kCFAllocatorSystemDefault, url);
 276              CFRelease(url);
 277          }
 278      }
 279      if (locBundle) {
 280  	localized = CFBundleCopyLocalizedString(locBundle, nonLocalized, nonLocalized, CFSTR("SystemVersion"));
 281  	if (bundlePtr) *bundlePtr = locBundle; else CFRelease(locBundle);
 282      }
 283      return localized ? localized : (CFStringRef)CFRetain(nonLocalized);
 284  }
 285  #endif
 286  
 287  #if TARGET_OS_WIN32
 288  static BOOL _CFGetWindowsSystemVersion(OSVERSIONINFOEX *osvi) {
 289      ZeroMemory(osvi, sizeof(OSVERSIONINFOEX));
 290      osvi->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
 291      return GetVersionEx((OSVERSIONINFO *)osvi);
 292  }
 293  #endif
 294  
 295  static CFDictionaryRef _CFCopyVersionDictionary(CFStringRef path) {
 296      CFPropertyListRef plist = NULL;
 297      
 298  #if TARGET_OS_MAC
 299      CFDataRef data;
 300      CFURLRef url;
 301      
 302      url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, path, kCFURLPOSIXPathStyle, false);
 303  #pragma GCC diagnostic push
 304  #pragma GCC diagnostic ignored "-Wdeprecated"
 305      if (url && CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, url, &data, NULL, NULL, NULL)) {
 306  #pragma GCC diagnostic pop
 307          plist = CFPropertyListCreateWithData(kCFAllocatorSystemDefault, data, kCFPropertyListMutableContainers, NULL, NULL);
 308  	CFRelease(data);
 309      }
 310      if (url) CFRelease(url);
 311  
 312      if (plist) {
 313  	CFBundleRef locBundle = NULL;
 314  	CFStringRef fullVersion, vers, versExtra, build;
 315  	CFStringRef versionString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionProductVersionStringKey);
 316  	CFStringRef buildString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionBuildStringKey);
 317  	CFStringRef fullVersionString = _CFCopyLocalizedVersionKey(&locBundle, CFSTR("FullVersionString"));
 318  	if (locBundle) CFRelease(locBundle);
 319  
 320          // Now build the full version string
 321          if (CFEqual(fullVersionString, CFSTR("FullVersionString"))) {
 322              CFRelease(fullVersionString);
 323              fullVersionString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@ %%@ (%@ %%@)"), versionString, buildString);
 324          }
 325          vers = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionProductVersionKey);
 326          versExtra = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionProductVersionExtraKey);
 327          if (vers && versExtra) vers = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@ %@"), vers, versExtra);
 328          build = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionBuildVersionKey);
 329          fullVersion = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, fullVersionString, (vers ? vers : CFSTR("?")), build ? build : CFSTR("?"));
 330          if (vers && versExtra) CFRelease(vers);
 331          
 332  	CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionProductVersionStringKey, versionString);
 333  	CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionBuildStringKey, buildString);
 334  	CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR("FullVersionString"), fullVersion);
 335   	CFRelease(versionString);
 336  	CFRelease(buildString);
 337  	CFRelease(fullVersionString);
 338          CFRelease(fullVersion);
 339      }
 340  #elif TARGET_OS_WIN32
 341      OSVERSIONINFOEX osvi;
 342      if (!_CFGetWindowsSystemVersion(&osvi)) return NULL;
 343  
 344      plist = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 10, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
 345      
 346      // e.g. 10.7
 347      CFStringRef versionString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%ld.%ld(%ld,%ld)"), osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.wServicePackMajor, osvi.wServicePackMinor);
 348      
 349      // e.g. 11A508
 350      CFStringRef buildString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%ld"), osvi.dwBuildNumber);
 351          
 352      CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionProductVersionKey, versionString);
 353      CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionBuildVersionKey, buildString);    
 354      CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionProductNameKey, CFSTR("Windows")); // hard coded for now
 355      
 356      CFRelease(versionString);
 357      CFRelease(buildString);
 358  #endif
 359      return (CFDictionaryRef)plist;
 360  }
 361  
 362  #if !TARGET_OS_WASI
 363  CFStringRef _CFCopySystemVersionDictionaryValue(CFStringRef key) {
 364      CFStringRef versionString;
 365      CFDictionaryRef dict = _CFCopyServerVersionDictionary();
 366      if (!dict) dict = _CFCopySystemVersionDictionary();
 367      if (!dict) return NULL;
 368      versionString = (CFStringRef)CFDictionaryGetValue(dict, key);
 369      if (versionString) CFRetain(versionString);
 370      CFRelease(dict);
 371      return versionString;
 372  }
 373  
 374  CFStringRef CFCopySystemVersionString(void) {
 375      return _CFCopySystemVersionDictionaryValue(CFSTR("FullVersionString"));
 376  }
 377  
 378  CFDictionaryRef _CFCopySystemVersionDictionary(void) {
 379      static dispatch_once_t onceToken;
 380      static CFDictionaryRef result = NULL;
 381      dispatch_once(&onceToken, ^{
 382          // TODO: Populate this dictionary differently on non-Darwin platforms
 383          CFStringRef path = copySystemVersionPath(CFSTR("/System/Library/CoreServices/SystemVersion.plist"));
 384          CFPropertyListRef plist = _CFCopyVersionDictionary(path);
 385          CFRelease(path);
 386          result = (CFDictionaryRef)plist;
 387      });
 388      if (result) {
 389          return CFRetain(result);
 390      } else {
 391          return NULL;
 392      }
 393  }
 394  
 395  CFDictionaryRef _CFCopySystemVersionPlatformDictionary(void) {
 396      static dispatch_once_t onceToken;
 397      static CFDictionaryRef result = NULL;
 398      dispatch_once(&onceToken, ^{
 399          CFStringRef path = copySystemVersionPath(CFSTR("/System/Library/CoreServices/.SystemVersionPlatform.plist"));
 400          CFPropertyListRef plist = _CFCopyVersionDictionary(path);
 401          CFRelease(path);
 402          if (!plist) {
 403              // Fall back to the normal one in case the .SystemVersionPlatform.plist symlink is missing
 404              plist = _CFCopySystemVersionDictionary();
 405          }
 406          result = (CFDictionaryRef)plist;
 407      });
 408      if (result) {
 409          return CFRetain(result);
 410      } else {
 411          return NULL;
 412      }
 413  }
 414  
 415  CFDictionaryRef _CFCopyServerVersionDictionary(void) {
 416      static dispatch_once_t onceToken;
 417      static CFDictionaryRef result = NULL;
 418      dispatch_once(&onceToken, ^{
 419          CFStringRef path = copySystemVersionPath(CFSTR("/System/Library/CoreServices/ServerVersion.plist"));
 420          CFPropertyListRef plist = _CFCopyVersionDictionary(path);
 421          CFRelease(path);
 422          result = (CFDictionaryRef)plist;
 423      });
 424      if (result) {
 425          return CFRetain(result);
 426      } else {
 427          return NULL;
 428      }
 429  }
 430  
 431  static CFOperatingSystemVersion _CFCalculateOSVersion(void) {
 432      CFOperatingSystemVersion versionStruct = {-1, 0, 0};
 433  #if TARGET_OS_WIN32
 434      OSVERSIONINFOEX windowsVersion;
 435      if (_CFGetWindowsSystemVersion(&windowsVersion)) {
 436          versionStruct.majorVersion = windowsVersion.dwMajorVersion;
 437          versionStruct.minorVersion = windowsVersion.dwMinorVersion;
 438          versionStruct.patchVersion = windowsVersion.dwBuildNumber;
 439      }
 440  #else
 441      CFStringRef resolvedProductVersionKey = _kCFSystemVersionProductVersionKey;
 442      CFStringRef productVersion = _CFCopySystemVersionDictionaryValue(resolvedProductVersionKey);
 443      if (productVersion) {
 444          CFArrayRef components = CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, productVersion, CFSTR("."));
 445          if (components) {
 446              const CFIndex cnt = CFArrayGetCount(components);
 447              if (0 < cnt) {
 448                  versionStruct.majorVersion = CFStringGetIntValue(CFArrayGetValueAtIndex(components, 0));
 449                  if (1 < cnt) {
 450                      versionStruct.minorVersion = CFStringGetIntValue(CFArrayGetValueAtIndex(components, 1));
 451                      if (2 < cnt) {
 452                          versionStruct.patchVersion = CFStringGetIntValue(CFArrayGetValueAtIndex(components, 2));
 453                      }
 454                  }
 455              }
 456              CFRelease(components);
 457          }
 458          CFRelease(productVersion);
 459      }
 460  #endif
 461      return versionStruct;
 462  }
 463  
 464  CFOperatingSystemVersion _CFOperatingSystemVersionGetCurrent(void) {
 465      static CFOperatingSystemVersion version;
 466      static dispatch_once_t onceToken;
 467      dispatch_once(&onceToken, ^{
 468          version = _CFCalculateOSVersion();
 469      });
 470      return version;
 471  }
 472  
 473  Boolean _CFOperatingSystemVersionIsAtLeastVersion(CFOperatingSystemVersion version) {
 474      const CFOperatingSystemVersion ourVersion = _CFOperatingSystemVersionGetCurrent();
 475      if (ourVersion.majorVersion < version.majorVersion) return false;
 476      if (ourVersion.majorVersion > version.majorVersion) return true;
 477      if (ourVersion.minorVersion < version.minorVersion) return false;
 478      if (ourVersion.minorVersion > version.minorVersion) return true;
 479      if (ourVersion.patchVersion < version.patchVersion) return false;
 480      if (ourVersion.patchVersion > version.patchVersion) return true;
 481      return true;
 482  }
 483  
 484  CONST_STRING_DECL(_kCFSystemVersionProductNameKey, "ProductName")
 485  CONST_STRING_DECL(_kCFSystemVersionProductCopyrightKey, "ProductCopyright")
 486  CONST_STRING_DECL(_kCFSystemVersionProductVersionKey, "ProductVersion")
 487  CONST_STRING_DECL(_kCFSystemVersionProductVersionExtraKey, "ProductVersionExtra")
 488  CONST_STRING_DECL(_kCFSystemVersionProductUserVisibleVersionKey, "ProductUserVisibleVersion")
 489  CONST_STRING_DECL(_kCFSystemVersionBuildVersionKey, "ProductBuildVersion")
 490  CONST_STRING_DECL(_kCFSystemVersionProductVersionStringKey, "Version")
 491  CONST_STRING_DECL(_kCFSystemVersionBuildStringKey, "Build")
 492  #endif
 493  
 494  CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) {
 495      return true;
 496  }
 497  
 498  #if TARGET_OS_OSX
 499  CF_PRIVATE void *__CFLookupCarbonCoreFunction(const char *name) {
 500      static void *image = NULL;
 501      static dispatch_once_t onceToken;
 502      dispatch_once(&onceToken, ^{
 503          image = dlopen("/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore", RTLD_LAZY | RTLD_LOCAL);
 504      });
 505      void *dyfunc = NULL;
 506      if (image) {
 507  	dyfunc = dlsym(image, name);
 508      }
 509      return dyfunc;
 510  }
 511  #endif
 512  
 513  #if TARGET_OS_MAC
 514  CF_PRIVATE void *__CFLookupCoreServicesInternalFunction(const char *name) {
 515      static void *image = NULL;
 516      static dispatch_once_t onceToken;
 517      dispatch_once(&onceToken, ^{
 518          image = dlopen("/System/Library/PrivateFrameworks/CoreServicesInternal.framework/CoreServicesInternal", RTLD_LAZY | RTLD_LOCAL);
 519      });
 520      void *dyfunc = NULL;
 521      if (image) {
 522          dyfunc = dlsym(image, name);
 523      }
 524      return dyfunc;
 525  }
 526  
 527  CF_PRIVATE void *__CFLookupCFNetworkFunction(const char *name) {
 528      static void *image = NULL;
 529      static dispatch_once_t onceToken;
 530      dispatch_once(&onceToken, ^{
 531          const char *path = __CFgetenvIfNotRestricted("CFNETWORK_LIBRARY_PATH");
 532          if (!path) {
 533              path = "/System/Library/Frameworks/CFNetwork.framework/CFNetwork";
 534          }
 535          image = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
 536      });
 537      void *dyfunc = NULL;
 538      if (image) {
 539  	dyfunc = dlsym(image, name);
 540      }
 541      return dyfunc;
 542  }
 543  #endif
 544  
 545  // TSAN does not know about the commpage: [39153032]
 546  __attribute__((no_sanitize_thread))
 547  CF_PRIVATE CFIndex __CFActiveProcessorCount(void) {
 548  #if CF_HAVE_HW_CONFIG_COMMPAGE
 549      static const uintptr_t p = _COMM_PAGE_ACTIVE_CPUS;
 550      return (CFIndex)(*(uint8_t*)p);
 551  #else
 552      
 553      int32_t pcnt;
 554  #if TARGET_OS_WIN32
 555      SYSTEM_INFO sysInfo;
 556      GetSystemInfo(&sysInfo);
 557      DWORD_PTR activeProcessorMask = sysInfo.dwActiveProcessorMask;
 558      // assumes sizeof(DWORD_PTR) is 64 bits or less
 559      uint64_t v = activeProcessorMask;
 560      v = v - ((v >> 1) & 0x5555555555555555ULL);
 561      v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL);
 562      v = (v + (v >> 4)) & 0xf0f0f0f0f0f0f0fULL;
 563      pcnt = (v * 0x0101010101010101ULL) >> ((sizeof(v) - 1) * 8);
 564  #elif TARGET_OS_MAC
 565      int32_t mib[] = {CTL_HW, HW_AVAILCPU};
 566      size_t len = sizeof(pcnt);
 567      int32_t result = sysctl(mib, sizeof(mib) / sizeof(int32_t), &pcnt, &len, NULL, 0);
 568      if (result != 0) {
 569          pcnt = 0;
 570      }
 571  #elif TARGET_OS_LINUX || TARGET_OS_BSD
 572  
 573  #ifdef HAVE_SCHED_GETAFFINITY
 574      cpu_set_t set;
 575      if (sched_getaffinity (getpid(), sizeof(set), &set) == 0) {
 576          return CPU_COUNT (&set);
 577      }
 578  #endif
 579  
 580      pcnt = sysconf(_SC_NPROCESSORS_ONLN);
 581  #else
 582      // Assume the worst
 583      pcnt = 1;
 584  #endif
 585      return pcnt;
 586  #endif
 587  }
 588  
 589  CF_PRIVATE CFIndex __CFProcessorCount() {
 590      int32_t pcnt;
 591  #if TARGET_OS_MAC
 592      int32_t mib[] = {CTL_HW, HW_NCPU};
 593      size_t len = sizeof(pcnt);
 594      int32_t result = sysctl(mib, sizeof(mib) / sizeof(int32_t), &pcnt, &len, NULL, 0);
 595      if (result != 0) {
 596          pcnt = 0;
 597      }
 598  #elif TARGET_OS_LINUX || TARGET_OS_BSD
 599      pcnt = sysconf(_SC_NPROCESSORS_CONF);
 600  #else
 601      // Assume the worst
 602      pcnt = 1;
 603  #endif
 604      return pcnt;
 605  }
 606  
 607  CF_PRIVATE uint64_t __CFMemorySize() {
 608      uint64_t memsize = 0;
 609  #if TARGET_OS_MAC
 610      int32_t mib[] = {CTL_HW, HW_MEMSIZE};
 611      size_t len = sizeof(memsize);
 612      int32_t result = sysctl(mib, sizeof(mib) / sizeof(int32_t), &memsize, &len, NULL, 0);
 613      if (result != 0) {
 614          memsize = 0;
 615      }
 616  #elif TARGET_OS_LINUX || TARGET_OS_BSD
 617      memsize = sysconf(_SC_PHYS_PAGES);
 618      memsize *= sysconf(_SC_PAGESIZE);
 619  #endif
 620      return memsize;
 621  }
 622  
 623  #if TARGET_OS_MAC
 624  static uid_t _CFGetSVUID(BOOL *successful) {
 625      uid_t uid = -1;
 626      struct kinfo_proc kinfo;
 627      u_int miblen = 4;
 628      size_t  len;
 629      int mib[miblen];
 630      int ret;
 631      mib[0] = CTL_KERN;
 632      mib[1] = KERN_PROC;
 633      mib[2] = KERN_PROC_PID;
 634      mib[3] = getpid();
 635      len = sizeof(struct kinfo_proc);
 636      ret = sysctl(mib, miblen, &kinfo, &len, NULL, 0);
 637      if (ret != 0) {
 638          uid = -1;
 639          *successful = NO;
 640      } else {
 641          uid = kinfo.kp_eproc.e_pcred.p_svuid;
 642          *successful = YES;
 643      }
 644      return uid;
 645  }
 646  #endif
 647  
 648  CF_INLINE BOOL _CFCanChangeEUIDs(void) {
 649  #if TARGET_OS_MAC
 650      static BOOL canChangeEUIDs;
 651      static dispatch_once_t onceToken;
 652      dispatch_once(&onceToken, ^{
 653          uid_t euid = geteuid();
 654          uid_t uid = getuid();
 655          BOOL gotSVUID = NO;
 656          uid_t svuid = _CFGetSVUID(&gotSVUID);
 657          canChangeEUIDs = (uid == 0 || uid != euid || svuid != euid || !gotSVUID);
 658      });
 659      return canChangeEUIDs;
 660  #else
 661      return true;
 662  #endif
 663  }
 664  
 665  #if !TARGET_OS_WASI
 666  typedef struct _ugids {
 667      uid_t _euid;
 668      uid_t _egid;
 669  } ugids;
 670  
 671  // work around 33477678 by making these file-level globals
 672  static ugids __CFGetUGIDs_cachedUGIDs = { -1, -1 };
 673  static dispatch_once_t __CFGetUGIDs_onceToken;
 674  
 675  CF_PRIVATE void __CFGetUGIDs(uid_t *euid, gid_t *egid) {
 676      ugids(^lookup)(void) = ^{
 677          ugids ids;
 678  #if 1 && TARGET_OS_MAC
 679          if (0 != pthread_getugid_np(&ids._euid, &ids._egid))
 680  #endif
 681          {
 682              ids._euid = geteuid();
 683              ids._egid = getegid();
 684          }
 685          return ids;
 686      };
 687      
 688      ugids ids;
 689      
 690      if (_CFCanChangeEUIDs()) {
 691          ids = lookup();
 692      } else {
 693          dispatch_once(&__CFGetUGIDs_onceToken, ^{
 694              __CFGetUGIDs_cachedUGIDs = lookup();
 695          });
 696          ids = __CFGetUGIDs_cachedUGIDs;
 697      }
 698      
 699      if (euid) *euid = ids._euid;
 700      if (egid) *egid = ids._egid;
 701  }
 702      
 703  CF_EXPORT void _CFGetUGIDs(uid_t *euid, gid_t *egid) {
 704      __CFGetUGIDs(euid, egid);
 705  }
 706      
 707  CF_EXPORT uid_t _CFGetEUID(void) {
 708      uid_t euid;
 709      __CFGetUGIDs(&euid, NULL);
 710      return euid;
 711  }
 712  
 713  CF_EXPORT uid_t _CFGetEGID(void) {
 714      uid_t egid;
 715      __CFGetUGIDs(NULL, &egid);
 716      return egid;
 717  }
 718  #endif
 719  
 720  const char *_CFPrintForDebugger(const void *obj) {
 721  	static char *result = NULL;
 722  	CFStringRef str;
 723  	CFIndex cnt = 0;
 724  
 725  	free(result);	// Let go of result from previous call.
 726  	result = NULL;
 727  	if (obj) {
 728  		if (CFGetTypeID(obj) == CFStringGetTypeID()) {
 729  			// Makes Ali marginally happier
 730  			str = __CFCopyFormattingDescription(obj, NULL);
 731  			if (!str) str = CFCopyDescription(obj);
 732  		} else {
 733  			str = CFCopyDescription(obj);
 734  		}
 735  	} else {
 736  		str = (CFStringRef)CFRetain(CFSTR("(null)"));
 737  	}
 738  	
 739  	if (str != NULL) {
 740  		CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, 0, FALSE, NULL, 0, &cnt);
 741  	}
 742  	result = (char *) malloc(cnt + 2);	// 1 for '\0', 1 for an optional '\n'
 743  	if (str != NULL) {
 744  		CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, 0, FALSE, (UInt8 *) result, cnt, &cnt);
 745  	}
 746  	result[cnt] = '\0';
 747  
 748  	if (str) CFRelease(str);
 749  	return result;
 750  }
 751  
 752  static void _CFShowToFile(FILE *file, Boolean flush, const void *obj) {
 753       CFStringRef str;
 754       CFIndex idx, cnt;
 755       CFStringInlineBuffer buffer;
 756       bool lastNL = false;
 757  
 758       if (obj) {
 759  	if (CFGetTypeID(obj) == CFStringGetTypeID()) {
 760  	    // Makes Ali marginally happier
 761  	    str = __CFCopyFormattingDescription(obj, NULL);
 762  	    if (!str) str = CFCopyDescription(obj);
 763  	} else {
 764  	    str = CFCopyDescription(obj);
 765  	}
 766       } else {
 767  	str = (CFStringRef)CFRetain(CFSTR("(null)"));
 768       }
 769       cnt = CFStringGetLength(str);
 770  
 771  #if TARGET_OS_WIN32
 772      UniChar *ptr = (UniChar *)CFStringGetCharactersPtr(str);
 773      BOOL freePtr = false;
 774      if (!ptr) {
 775  	CFIndex strLen = CFStringGetLength(str);
 776  	// +2, 1 for newline, 1 for null
 777  	CFIndex bufSize = sizeof(UniChar *) * (CFStringGetMaximumSizeForEncoding(strLen, kCFStringEncodingUnicode) + 2);
 778  	CFIndex bytesUsed = 0;
 779  	ptr = (UniChar *)malloc(bufSize);
 780  	CFStringGetCharacters(str, CFRangeMake(0, strLen), ptr);
 781  	ptr[strLen] = L'\n';
 782  	ptr[strLen+1] = 0;
 783  	freePtr = true;
 784      }
 785      OutputDebugStringW((wchar_t *)ptr);
 786      if (freePtr) free(ptr);
 787  #else
 788       CFStringInitInlineBuffer(str, &buffer, CFRangeMake(0, cnt));
 789       for (idx = 0; idx < cnt; idx++) {
 790           UniChar ch = __CFStringGetCharacterFromInlineBufferQuick(&buffer, idx);
 791           if (ch < 128) {
 792               fprintf_l(file, NULL, "%c", ch);
 793               lastNL = (ch == '\n');
 794           } else {
 795               fprintf_l(file, NULL, "\\u%04x", ch);
 796           }
 797       }
 798       if (!lastNL) {
 799  #if TARGET_OS_MAC
 800           fprintf_l(file, NULL, "\n");
 801  #else
 802           fprintf(file, "\n");
 803  #endif
 804           if (flush) fflush(file);
 805       }
 806  #endif
 807  
 808       if (str) CFRelease(str);
 809  }
 810  
 811  void CFShow(const void *obj) {
 812       _CFShowToFile(stderr, true, obj);
 813  }
 814  
 815  
 816  // message must be a UTF8-encoded, null-terminated, byte buffer with at least length bytes
 817  typedef void (*CFLogFunc)(int32_t lev, const char *message, size_t length, char withBanner);
 818  
 819  #if TARGET_OS_MAC
 820  static Boolean debugger_attached() {
 821      BOOL debuggerAttached = NO;
 822      struct proc_bsdshortinfo info;
 823      const int size = proc_pidinfo(getpid(), PROC_PIDT_SHORTBSDINFO, 0, &info, sizeof(info));
 824      if (size == PROC_PIDT_SHORTBSDINFO_SIZE) {
 825          debuggerAttached = (info.pbsi_flags & PROC_FLAG_TRACED);
 826      }
 827      return debuggerAttached;
 828  }
 829  #endif
 830  
 831  // We need to support both the 'modern' os_log focused approach to logging and the previous implementation. This enumeration gives us a way to distinguish between the two more verbosely than a boolean.
 832  typedef enum {
 833      _cf_logging_style_os_log,
 834      _cf_logging_style_legacy
 835  } _cf_logging_style;
 836  
 837  static bool also_do_stderr(const _cf_logging_style style) {
 838      bool result = false;
 839  #if TARGET_OS_LINUX || TARGET_OS_WIN32
 840      // just log to stderr, other logging facilities are out
 841      result = true;
 842  #elif TARGET_OS_MAC
 843      if (style == _cf_logging_style_os_log) {
 844          //
 845          // This might seem a bit odd, so an explanation is in order:
 846          //
 847          // If a debugger is attached we defer to os_log to do all logging for us. This
 848          // happens many frames up/sideways from here.
 849          //
 850          // Otherwise, we check for the force flag as we always have.
 851          //
 852          // That failing, we'll stat STDERR and see if its sxomething we like.
 853          //
 854          // NOTE: As nice as it would be to dispatch_once this, all of these things
 855          // can and do change at runtime under certain circumstances, so we need to
 856          // keep it dynamic.
 857          //
 858          if (debugger_attached() || __CFgetenv("OS_ACTIVITY_DT_MODE")) {
 859              return false;
 860          }
 861  
 862          if (!__CFProcessIsRestricted() && __CFgetenv("CFLOG_FORCE_STDERR")) {
 863              return true;
 864          }
 865  
 866          struct stat sb;
 867          int ret = fstat(STDERR_FILENO, &sb);
 868          if (ret < 0) {
 869              return false;
 870          }
 871  
 872          const mode_t m = sb.st_mode & S_IFMT;
 873          if (S_IFCHR == m || S_IFREG == m || S_IFIFO == m ||  S_IFSOCK == m) {
 874              return true;
 875          }
 876          // NOTE: we return false now, as the expectation is that os_log path owns all logging
 877          result = false;
 878      } else if (style == _cf_logging_style_legacy) {
 879          // compatibility path
 880          if (!issetugid() && __CFgetenv("CFLOG_FORCE_STDERR")) {
 881              return true;
 882          }
 883          struct stat sb;
 884          int ret = fstat(STDERR_FILENO, &sb);
 885          if (ret < 0) return false;
 886          mode_t m = sb.st_mode & S_IFMT;
 887          if (S_IFREG == m || S_IFSOCK == m) return true;
 888          if (!(S_IFIFO == m || S_IFCHR == m)) return false; // disallow any whacky stuff
 889          result = true;
 890      }
 891  #else
 892      // just log to stderr, other logging facilities are out
 893      result = true;
 894  #endif
 895      return result;
 896  }
 897  
 898  #if TARGET_OS_WIN32
 899  static struct tm *localtime_r(time_t *tv, struct tm *result) {
 900    struct tm *tm = localtime(tv);
 901    if (tm) {
 902      *result = *tm;
 903    }
 904    return tm;
 905  }
 906  #endif
 907  
 908  static void _populateBanner(char **banner, char **time, char **thread, int *bannerLen) {
 909      double dummy;
 910      CFAbsoluteTime at = CFAbsoluteTimeGetCurrent();
 911      time_t tv = (time_t)floor(at + kCFAbsoluteTimeIntervalSince1970);
 912      struct tm mine;
 913      localtime_r(&tv, &mine);
 914      int32_t year = mine.tm_year + 1900;
 915      int32_t month = mine.tm_mon + 1;
 916      int32_t day = mine.tm_mday;
 917      int32_t hour = mine.tm_hour;
 918      int32_t minute = mine.tm_min;
 919      int32_t second = mine.tm_sec;
 920      int32_t ms = (int32_t)floor(1000.0 * modf(at, &dummy));
 921  #if TARGET_OS_MAC
 922      uint64_t tid = 0;
 923      if (0 != pthread_threadid_np(NULL, &tid)) tid = pthread_mach_thread_np(pthread_self());
 924      asprintf(banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s[%d:%llu] ", year, month, day, hour, minute, second, ms, *_CFGetProgname(), getpid(), tid);
 925      asprintf(thread, "%x", pthread_mach_thread_np(pthread_self()));
 926  #elif TARGET_OS_WIN32
 927      bannerLen = asprintf(banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s[%d:%lx] ", year, month, day, hour, minute, second, ms, *_CFGetProgname(), getpid(), GetCurrentThreadId());
 928      asprintf(thread, "%lx", GetCurrentThreadId());
 929  #elif TARGET_OS_WASI
 930      bannerLen = asprintf(banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d [%x] ", year, month, day, hour, minute, second, ms, (unsigned int)pthread_self());
 931      asprintf(thread, "%lx", pthread_self());
 932  #else
 933      bannerLen = asprintf(banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s[%d:%x] ", year, month, day, hour, minute, second, ms, *_CFGetProgname(), getpid(), (unsigned int)pthread_self());
 934      asprintf(thread, "%lx", pthread_self());
 935  #endif
 936      asprintf(time, "%04d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, minute, second, ms);
 937  }
 938  
 939  static void _logToStderr(char *banner, const char *message, size_t length) {
 940  #if TARGET_OS_MAC
 941      struct iovec v[3];
 942      v[0].iov_base = banner;
 943      v[0].iov_len = banner ? strlen(banner) : 0;
 944      v[1].iov_base = (char *)message;
 945      v[1].iov_len = length;
 946      v[2].iov_base = "\n";
 947      v[2].iov_len = (message[length - 1] != '\n') ? 1 : 0;
 948      int nv = (v[0].iov_base ? 1 : 0) + 1 + (v[2].iov_len ? 1 : 0);
 949      static os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
 950      os_unfair_lock_lock(&lock);
 951      writev(STDERR_FILENO, v[0].iov_base ? v : v + 1, nv);
 952      os_unfair_lock_unlock(&lock);
 953  #elif TARGET_OS_WIN32
 954      size_t bannerLen = strlen(banner);
 955      size_t bufLen = bannerLen + length + 1;
 956      char *buf = (char *)malloc(sizeof(char) * bufLen);
 957      if (banner) {
 958          // Copy the banner into the debug string
 959          memmove_s(buf, bufLen, banner, bannerLen);
 960          
 961          // Copy the message into the debug string
 962          strcpy_s(buf + bannerLen, bufLen - bannerLen, message);
 963      } else {
 964          strcpy_s(buf, bufLen, message);
 965      }
 966      buf[bufLen - 1] = '\0';
 967      fprintf_s(stderr, "%s\n", buf);
 968      // This Win32 API call only prints when a debugger is active
 969      // OutputDebugStringA(buf);
 970      free(buf);
 971  #else
 972      size_t bannerLen = strlen(banner);
 973      size_t bufLen = bannerLen + length + 1;
 974      char *buf = (char *)malloc(sizeof(char) * bufLen);
 975      if (banner) {
 976          // Copy the banner into the debug string
 977          memmove(buf, banner, bannerLen);
 978          
 979          // Copy the message into the debug string
 980          strncpy(buf + bannerLen, message, bufLen - bannerLen);
 981      } else {
 982          strncpy(buf, message, bufLen);
 983      }
 984      buf[bufLen - 1] = '\0';
 985      fprintf(stderr, "%s\n", buf);
 986      free(buf);
 987  #endif
 988  }
 989  
 990  static void __CFLogCString(int32_t lev, const char *message, size_t length, char withBanner) {
 991      char *banner = NULL;
 992      char *time = NULL;
 993      char *thread = NULL;
 994      int bannerLen;
 995      bannerLen = 0;
 996  
 997      // The banner path may use CF functions, but the rest of this function should not. It may be called at times when CF is not fully setup or torn down.
 998      if (withBanner) {
 999          _populateBanner(&banner, &time, &thread, &bannerLen);
1000      }
1001      
1002      _logToStderr(banner, message, length);
1003  
1004      if (thread) free(thread);
1005      if (time) free(time);
1006      if (banner) free(banner);
1007  }
1008  
1009  static void __CFLogCStringLegacy(int32_t lev, const char *message, size_t length, char withBanner) {
1010      char *banner = NULL;
1011      char *time = NULL;
1012      char *uid = NULL;
1013      char *thread = NULL;
1014      int bannerLen;
1015      bannerLen = 0;
1016      
1017      // The banner path may use CF functions, but the rest of this function should not. It may be called at times when CF is not fully setup or torn down.
1018      if (withBanner) {
1019          _populateBanner(&banner, &time, &thread, &bannerLen);
1020      }
1021      
1022  #if TARGET_OS_MAC
1023  #pragma GCC diagnostic push
1024  #pragma GCC diagnostic ignored "-Wdeprecated"
1025      uid_t euid;
1026      __CFGetUGIDs(&euid, NULL);
1027      asprintf(&uid, "%d", euid);
1028      aslclient asl = asl_open(NULL, (__CFBundleMainID && __CFBundleMainID[0]) ? __CFBundleMainID : "com.apple.console", ASL_OPT_NO_DELAY);
1029      aslmsg msg = asl_new(ASL_TYPE_MSG);
1030      asl_set(msg, "CFLog Local Time", time); // not to be documented, not public API
1031      asl_set(msg, "CFLog Thread", thread);   // not to be documented, not public API
1032      asl_set(msg, "ReadUID", uid);
1033      static const char * const levstr[] = {"0", "1", "2", "3", "4", "5", "6", "7"};
1034      asl_set(msg, ASL_KEY_LEVEL, levstr[lev]);
1035      asl_set(msg, ASL_KEY_MSG, message);
1036      asl_send(asl, msg);
1037      asl_free(msg);
1038      asl_close(asl);
1039  #pragma GCC diagnostic pop
1040  #endif // DEPLOYMENT_TARGET
1041      
1042      if (also_do_stderr(_cf_logging_style_legacy)) {
1043          _logToStderr(banner, message, length);
1044      }
1045      
1046      if (thread) free(thread);
1047      if (time) free(time);
1048      if (banner) free(banner);
1049      if (uid) free(uid);
1050  }
1051  
1052  
1053  static void _CFLogvEx2Predicate(CFLogFunc logit, CFStringRef (*copyDescFunc)(void *, const void *), CFStringRef (*contextDescFunc)(void *, const void *, const void *, bool, bool *), CFDictionaryRef formatOptions, int32_t lev, CFStringRef format, va_list args, _cf_logging_style loggingStyle) {
1054  #if TARGET_OS_MAC
1055      uintptr_t val = (uintptr_t)_CFGetTSD(__CFTSDKeyIsInCFLog);
1056      if (3 < val) return; // allow up to 4 nested invocations
1057      _CFSetTSD(__CFTSDKeyIsInCFLog, (void *)(val + 1), NULL);
1058  #endif
1059      CFStringRef str = format ? _CFStringCreateWithFormatAndArgumentsAux2(kCFAllocatorSystemDefault, copyDescFunc, contextDescFunc, formatOptions, (CFStringRef)format, args) : 0;
1060      CFIndex blen = str ? CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1 : 0;
1061      char *buf = str ? (char *)malloc(blen) : 0;
1062      if (str && buf) {
1063  	Boolean converted = CFStringGetCString(str, buf, blen, kCFStringEncodingUTF8);
1064  	size_t len = strlen(buf);
1065  	// silently ignore 0-length or really large messages, and levels outside the valid range
1066  	if (converted && !(len <= 0 || (1 << 24) < len) && !(lev < ASL_LEVEL_EMERG || ASL_LEVEL_DEBUG < lev)) {
1067              if (logit) {
1068                  logit(lev, buf, len, 1);
1069              }
1070              else if (loggingStyle == _cf_logging_style_os_log) {
1071                  __CFLogCString(lev, buf, len, 1);
1072              }
1073              else if (loggingStyle == _cf_logging_style_legacy) {
1074                  __CFLogCStringLegacy(lev, buf, len, 1);
1075              }
1076  	}
1077      }
1078      if (buf) free(buf);
1079      if (str) CFRelease(str);
1080  #if TARGET_OS_MAC
1081      _CFSetTSD(__CFTSDKeyIsInCFLog, (void *)val, NULL);
1082  #endif
1083  }
1084      
1085  CF_EXPORT void _CFLogvEx2(CFLogFunc logit, CFStringRef (*copyDescFunc)(void *, const void *), CFStringRef (*contextDescFunc)(void *, const void *, const void *, bool, bool *), CFDictionaryRef formatOptions, int32_t lev, CFStringRef format, va_list args) {
1086      _CFLogvEx2Predicate(logit, copyDescFunc, contextDescFunc, formatOptions, lev, format, args, _cf_logging_style_legacy);
1087  }
1088      
1089  CF_EXPORT void _CFLogvEx3(CFLogFunc logit, CFStringRef (*copyDescFunc)(void *, const void *), CFStringRef (*contextDescFunc)(void *, const void *, const void *, bool, bool *), CFDictionaryRef formatOptions, int32_t lev, CFStringRef format, va_list args, void *addr) {
1090      _CFLogvEx2Predicate(logit, copyDescFunc, contextDescFunc, formatOptions, lev, format, args, _cf_logging_style_legacy);
1091      
1092  }
1093  
1094  CF_EXPORT void _CFLogvEx(CFLogFunc logit, CFStringRef (*copyDescFunc)(void *, const void *), CFDictionaryRef formatOptions, int32_t lev, CFStringRef format, va_list args) {
1095      _CFLogvEx2(logit, copyDescFunc, NULL, formatOptions, lev, format, args);
1096  }
1097  
1098  // This CF-only log function uses no CF functionality, so it may be called anywhere within CF - including thread teardown or prior to full CF setup
1099  CF_PRIVATE void _CFLogSimple(int32_t lev, char *format, ...) {
1100      va_list args;
1101      va_start(args, format);
1102      char formattedMessage[1024];
1103      int length = vsnprintf(formattedMessage, 1024, format, args);
1104      if (length > 0) {
1105          __CFLogCStringLegacy(lev, formattedMessage, length, 0);
1106      }
1107      va_end(args);
1108  }
1109  
1110  void CFLog(int32_t lev, CFStringRef format, ...) {
1111      va_list args;
1112      va_start(args, format); 
1113      
1114      #if !TARGET_OS_WASI
1115      _CFLogvEx3(NULL, NULL, NULL, NULL, lev, format, args, __builtin_return_address(0));
1116      #else
1117      _CFLogvEx3(NULL, NULL, NULL, NULL, lev, format, args, NULL);
1118      #endif
1119      va_end(args);
1120  }
1121      
1122  #if DEPLOYMENT_RUNTIME_SWIFT
1123  // Temporary as Swift cannot import varag C functions
1124  void CFLog1(CFLogLevel lev, CFStringRef message) {
1125  #if TARGET_OS_ANDROID
1126      android_LogPriority priority = ANDROID_LOG_UNKNOWN;
1127      switch (lev) {
1128          case kCFLogLevelEmergency: priority = ANDROID_LOG_FATAL; break;
1129          case kCFLogLevelAlert:     priority = ANDROID_LOG_ERROR; break;
1130          case kCFLogLevelCritical:  priority = ANDROID_LOG_ERROR; break;
1131          case kCFLogLevelError:     priority = ANDROID_LOG_ERROR; break;
1132          case kCFLogLevelWarning:   priority = ANDROID_LOG_WARN;  break;
1133          case kCFLogLevelNotice:    priority = ANDROID_LOG_WARN;  break;
1134          case kCFLogLevelInfo:      priority = ANDROID_LOG_INFO;  break;
1135          case kCFLogLevelDebug:     priority = ANDROID_LOG_DEBUG; break;
1136      }
1137      
1138      if (message == NULL) message = CFSTR("NULL");
1139      
1140      char stack_buffer[1024] = { 0 };
1141      char *buffer = &stack_buffer[0];
1142      CFStringEncoding encoding = kCFStringEncodingUTF8;
1143      CFIndex maxLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(message), encoding) + 1;
1144      const char *tag = "Swift"; // process name not available from NDK
1145      
1146      if (maxLength > sizeof(stack_buffer) / sizeof(stack_buffer[0])) {
1147          buffer = calloc(sizeof(char), maxLength);
1148          if (!buffer) {
1149              maxLength = sizeof(stack_buffer) / sizeof(stack_buffer[0]);
1150              buffer = &stack_buffer[0];
1151              buffer[maxLength-1] = '\000';
1152          }
1153      }
1154      
1155      if (maxLength == 1) {
1156          // was crashing with zero length strings
1157          // https://bugs.swift.org/browse/SR-2666
1158          strcpy(buffer, " "); // log empty string
1159      }
1160      else
1161          CFStringGetCString(message, buffer, maxLength, encoding);
1162      
1163      __android_log_print(priority, tag, "%s", buffer);
1164      fprintf(stderr, "%s\n", buffer);
1165      
1166      if (buffer != &stack_buffer[0]) free(buffer);
1167  #else
1168      CFLog(lev, CFSTR("%@"), message);
1169  #endif
1170  }
1171  #endif
1172  
1173  
1174  
1175  #if TARGET_OS_MAC
1176  
1177  kern_return_t _CFDiscorporateMemoryAllocate(CFDiscorporateMemory *hm, size_t size, bool purgeable) {
1178      kern_return_t ret = KERN_SUCCESS;
1179      size = round_page(size);
1180      if (0 == size) size = vm_page_size;
1181      memset(hm, 0, sizeof(CFDiscorporateMemory));
1182  
1183      ret = mach_vm_allocate(mach_task_self(), &hm->map_address, size, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_FOUNDATION) |  (purgeable ? VM_FLAGS_PURGABLE : 0));
1184      if (KERN_SUCCESS != ret) {
1185          hm->map_address = 0;
1186          return ret;
1187      }
1188  
1189      hm->address = hm->map_address;
1190      hm->size = (mach_vm_size_t)size;
1191      hm->purgeable = purgeable;
1192      return ret;
1193  }
1194  
1195  kern_return_t _CFDiscorporateMemoryDeallocate(CFDiscorporateMemory *hm) {
1196      kern_return_t ret = KERN_SUCCESS;
1197      if (hm->map_address != 0) ret = mach_vm_deallocate(mach_task_self(), hm->map_address, hm->size);
1198      if (KERN_SUCCESS != ret)
1199          CFLog(kCFLogLevelError, CFSTR("CFDiscorporateMemoryDeallocate: mach_vm_deallocate returned %s"), mach_error_string(ret));
1200      hm->address = 0;
1201      hm->size = 0;
1202      hm->map_address = 0;
1203      hm->purgeable = false;
1204      return ret;
1205  }
1206  
1207  kern_return_t _CFDiscorporateMemoryDematerialize(CFDiscorporateMemory *hm) {
1208      kern_return_t ret = KERN_SUCCESS;
1209      if (hm->address == 0) ret = KERN_INVALID_MEMORY_CONTROL;
1210      int state = VM_PURGABLE_VOLATILE;
1211      if (KERN_SUCCESS == ret) vm_purgable_control(mach_task_self(), (vm_address_t)hm->address, VM_PURGABLE_SET_STATE, &state);
1212      if (KERN_SUCCESS == ret) hm->address = 0;
1213      return ret;
1214  }
1215  
1216  kern_return_t _CFDiscorporateMemoryMaterialize(CFDiscorporateMemory *hm) {
1217      kern_return_t ret = KERN_SUCCESS;
1218      if (hm->address != 0) ret = KERN_INVALID_MEMORY_CONTROL;
1219      int state = VM_PURGABLE_NONVOLATILE;
1220      if (KERN_SUCCESS == ret) ret = vm_purgable_control(mach_task_self(), (vm_address_t)hm->map_address, VM_PURGABLE_SET_STATE, &state);
1221      if (KERN_SUCCESS == ret) hm->address = hm->map_address;
1222      if (KERN_SUCCESS == ret) if (VM_PURGABLE_EMPTY == state) ret = KERN_PROTECTION_FAILURE; // same as VM_PURGABLE_EMPTY
1223      return ret;
1224  }
1225  
1226  #endif
1227  
1228  #if TARGET_OS_OSX
1229  static os_unfair_lock __CFProcessKillingLock = OS_UNFAIR_LOCK_INIT;
1230  static CFIndex __CFProcessKillingDisablingCount = 1;
1231  static Boolean __CFProcessKillingWasTurnedOn = false;
1232  #endif
1233  
1234  void _CFSuddenTerminationDisable(void) {
1235  #if TARGET_OS_OSX
1236      os_unfair_lock_lock(&__CFProcessKillingLock);
1237      __CFProcessKillingDisablingCount++;
1238      os_unfair_lock_unlock(&__CFProcessKillingLock);
1239  #else
1240      // Do nothing
1241  #endif
1242  }
1243  
1244  void _CFSuddenTerminationEnable(void) {
1245  #if TARGET_OS_OSX
1246      // In our model the first call of _CFSuddenTerminationEnable() that does not balance a previous call of _CFSuddenTerminationDisable() actually enables sudden termination so we have to keep a count that's almost redundant with vproc's.
1247      os_unfair_lock_lock(&__CFProcessKillingLock);
1248      __CFProcessKillingDisablingCount--;
1249      if (__CFProcessKillingDisablingCount==0 && !__CFProcessKillingWasTurnedOn) {
1250  	__CFProcessKillingWasTurnedOn = true;
1251      } else {
1252      }
1253      os_unfair_lock_unlock(&__CFProcessKillingLock);
1254  #else
1255      // Do nothing
1256  #endif
1257  }
1258  
1259  void _CFSuddenTerminationExitIfTerminationEnabled(int exitStatus) {
1260  #if TARGET_OS_OSX
1261      // This is for when the caller wants to try to exit quickly if possible but not automatically exit the process when it next becomes clean, because quitting might still be cancelled by the user.
1262      os_unfair_lock_lock(&__CFProcessKillingLock);
1263      os_unfair_lock_unlock(&__CFProcessKillingLock);
1264  #else
1265      // Elsewhere, sudden termination is always disabled
1266  #endif
1267  }
1268  
1269  void _CFSuddenTerminationExitWhenTerminationEnabled(int exitStatus) {
1270  #if TARGET_OS_OSX
1271      // The user has had their final opportunity to cancel quitting. Exit as soon as the process is clean. Same carefulness as in _CFSuddenTerminationExitIfTerminationEnabled().
1272      os_unfair_lock_lock(&__CFProcessKillingLock);
1273      if (__CFProcessKillingWasTurnedOn) {
1274      }
1275      os_unfair_lock_unlock(&__CFProcessKillingLock);
1276  #else
1277      // Elsewhere, sudden termination is always disabled
1278  #endif
1279  }
1280  
1281  size_t _CFSuddenTerminationDisablingCount(void) {
1282  #if TARGET_OS_OSX
1283      return (__CFProcessKillingWasTurnedOn ? 0 : 1);
1284  #else
1285      // Elsewhere, sudden termination is always disabled
1286      return 1;
1287  #endif
1288  }
1289  
1290  #pragma mark File Reading
1291      
1292  #include <sys/stat.h>
1293  #include <fcntl.h>
1294  #include <errno.h>
1295  #if TARGET_OS_WIN32
1296  #include <io.h>
1297  #include <direct.h>
1298  #define close _close
1299  #define write _write
1300  #define read _read
1301  #define open _NS_open
1302  #define stat _NS_stat
1303  #define fstat _fstat
1304  #define statinfo _stat
1305      
1306  #define mach_task_self() 0
1307  
1308  #else
1309  #define statinfo stat
1310  #endif
1311      
1312  static CFErrorRef _CFErrorWithFilePathCodeDomain(CFStringRef domain, CFIndex code, CFStringRef path) {
1313      CFStringRef key = CFSTR("NSFilePath");
1314      CFDictionaryRef userInfo = CFDictionaryCreate(kCFAllocatorSystemDefault, (const void **)&key, (const void **)&path, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1315      CFErrorRef result = CFErrorCreate(kCFAllocatorSystemDefault, domain, code, userInfo);
1316      CFRelease(userInfo);
1317      return result;
1318  }
1319  
1320  // Caller is responsible for freeing memory. munmap() if map == true, else malloc().
1321  CF_PRIVATE Boolean _CFReadMappedFromFile(CFStringRef path, Boolean map, Boolean uncached, void **outBytes, CFIndex *outLength, CFErrorRef *errorPtr) {
1322      void *bytes = NULL;
1323      unsigned long length;
1324      char cpath[CFMaxPathSize];
1325      if (!CFStringGetFileSystemRepresentation(path, cpath, CFMaxPathSize)) {
1326          // TODO: real error codes
1327          if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainCocoa, -1, path);
1328  	return false;
1329      }
1330  
1331      struct statinfo statBuf;
1332      int32_t fd = -1;
1333  
1334      fd = open(cpath, O_RDONLY|CF_OPENFLGS, 0666);
1335      if (fd < 0) {
1336          if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, errno, path);
1337          return false;
1338      }
1339  #if TARGET_OS_MAC
1340      if (uncached) (void)fcntl(fd, F_NOCACHE, 1);  // Non-zero arg turns off caching; we ignore error as uncached is just a hint
1341  #endif
1342      if (fstat(fd, &statBuf) < 0) {
1343          int32_t savederrno = errno;
1344          close(fd);
1345          if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, savederrno, path);
1346          return false;
1347      }
1348      if ((statBuf.st_mode & S_IFMT) != S_IFREG) {
1349          close(fd);
1350          if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, EACCES, path);
1351          return false;
1352      }
1353      if (statBuf.st_size < 0LL) {	// too small
1354          close(fd);
1355          if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, ENOMEM, path);
1356          return false;
1357      }
1358  #if TARGET_RT_64_BIT
1359  #else
1360      if (statBuf.st_size > (1ull << 31)) {	// refuse to do more than 2GB
1361          close(fd);
1362          if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, EFBIG, path);
1363          return false;
1364      }
1365  #endif
1366  
1367      if (0LL == statBuf.st_size) {
1368          bytes = malloc(8); // don't return constant string -- it's freed!
1369  	length = 0;
1370  #if TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_WASI
1371      } else if (map) {
1372          if((void *)-1 == (bytes = mmap(0, (size_t)statBuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0))) {
1373  	    int32_t savederrno = errno;
1374  	    close(fd);
1375              if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, savederrno, path);
1376  	    return false;
1377  	}
1378  	length = (unsigned long)statBuf.st_size;
1379      } else {
1380          bytes = malloc(statBuf.st_size);
1381          if (bytes == NULL) {
1382              close(fd);
1383              if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, ENOMEM, path);
1384              return false;
1385          }
1386  	size_t numBytesRemaining = (size_t)statBuf.st_size;
1387  	void *readLocation = bytes;
1388  	while (numBytesRemaining > 0) {
1389  	    size_t numBytesRequested = (numBytesRemaining < (1LL << 31)) ? numBytesRemaining : ((1LL << 31) - 1);	// This loop is basically a workaround for 4870206 
1390  	    ssize_t numBytesRead = read(fd, readLocation, numBytesRequested);
1391  	    if (numBytesRead <= 0) {
1392  		if (numBytesRead < 0) {
1393  		    int32_t savederrno = errno;
1394                      free(bytes);
1395  		    close(fd);
1396                      if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, savederrno, path);
1397  		    bytes = NULL;
1398  		    return false;
1399  		} else {
1400  		    // This is a bizarre case; 0 bytes read. Might indicate end-of-file?
1401  		    break;
1402  		}
1403  	    } else {
1404  		readLocation += numBytesRead;
1405  		numBytesRemaining -= numBytesRead;
1406  	    }
1407  	}
1408  	length = (unsigned long)statBuf.st_size - numBytesRemaining;
1409      }
1410  #elif TARGET_OS_WIN32
1411      } else {
1412          bytes = malloc(statBuf.st_size);
1413          DWORD numBytesRead;
1414          if (!ReadFile((HANDLE)_get_osfhandle(fd), bytes, statBuf.st_size, &numBytesRead, NULL)) {
1415              DWORD lastError = GetLastError();
1416              if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, lastError, path);
1417  	    free(bytes);
1418  	    close(fd);
1419  	    errno = lastError;
1420  	    bytes = NULL;
1421  	    return false;
1422          }
1423  	length = numBytesRead;
1424      }
1425  #endif
1426      close(fd);
1427      *outBytes = bytes;
1428      *outLength = length;
1429      return true;
1430  }
1431  
1432  /* __CFStringGetCharacterFromInlineBufferQuickReverse is the same as __CFStringGetCharacterFromInlineBufferQuick(), but expects idx to be decremented
1433   */
1434  CF_INLINE UniChar __CFStringGetCharacterFromInlineBufferQuickReverse(CFStringInlineBuffer *buf, CFIndex idx) {
1435      if (buf->directUniCharBuffer) return buf->directUniCharBuffer[idx + buf->rangeToBuffer.location];
1436      if (buf->directCStringBuffer) return (UniChar)(buf->directCStringBuffer[idx + buf->rangeToBuffer.location]);
1437      if (idx >= buf->bufferedRangeEnd || idx < buf->bufferedRangeStart) {
1438          if ((buf->bufferedRangeStart = idx - __kCFStringInlineBufferLength + 1) < 0) buf->bufferedRangeStart = 0;
1439          buf->bufferedRangeEnd = buf->bufferedRangeStart + __kCFStringInlineBufferLength;
1440          if (buf->bufferedRangeEnd > buf->rangeToBuffer.length) buf->bufferedRangeEnd = buf->rangeToBuffer.length;
1441          CFStringGetCharacters(buf->theString, CFRangeMake(buf->rangeToBuffer.location + buf->bufferedRangeStart, buf->bufferedRangeEnd - buf->bufferedRangeStart), buf->buffer);
1442      }
1443      return buf->buffer[idx - buf->bufferedRangeStart];
1444  }
1445  
1446  /* UniCharInitInlineBuffer initializes an in-line buffer to use an array of UniChar with CFStringGetCharacterFromInlineBuffer (and related SPI that use CFStringInlineBuffer).
1447   */
1448  CF_INLINE void UniCharInitInlineBuffer(const UniChar *uchars, CFIndex ucharsLength, CFStringInlineBuffer *buf) {
1449      buf->theString = NULL;
1450      buf->rangeToBuffer = CFRangeMake(0, ucharsLength);
1451      buf->directUniCharBuffer = uchars;
1452      buf->directCStringBuffer = NULL;
1453      buf->bufferedRangeStart = buf->bufferedRangeEnd = 0;
1454  }
1455  
1456  // __IsInvalidExtensionCharacter returns true if C is a space, a path separator, or a unicode directional control character
1457  CF_INLINE Boolean __IsInvalidExtensionCharacter(UniChar c)
1458  {
1459      // Unicode directional control characters
1460      enum {
1461          UNICHAR_ARABIC_LETTER_MARK          = 0x061c,
1462          UNICHAR_LEFT_TO_RIGHT_MARK          = 0x200e,
1463          UNICHAR_RIGHT_TO_LEFT_MARK          = 0x200f,
1464          UNICHAR_LEFT_TO_RIGHT_EMBEDDING     = 0x202a,
1465          UNICHAR_RIGHT_TO_LEFT_EMBEDDING     = 0x202b,
1466          UNICHAR_POP_DIRECTIONAL_FORMATTING  = 0x202c,
1467          UNICHAR_LEFT_TO_RIGHT_OVERRIDE      = 0x202d,
1468          UNICHAR_RIGHT_TO_LEFT_OVERRIDE      = 0x202e,
1469          UNICHAR_LEFT_TO_RIGHT_ISOLATE       = 0x2066,
1470          UNICHAR_RIGHT_TO_LEFT_ISOLATE       = 0x2067,
1471          UNICHAR_FIRST_STRONG_ISOLATE        = 0x2068,
1472          UNICHAR_POP_DIRECTIONAL_ISOLATE     = 0x2069,
1473      };
1474      
1475      Boolean result;
1476      switch ( c ) {
1477          case (UniChar)' ':
1478          case (UniChar)'/':
1479          case UNICHAR_ARABIC_LETTER_MARK:
1480          case UNICHAR_LEFT_TO_RIGHT_MARK:
1481          case UNICHAR_RIGHT_TO_LEFT_MARK:
1482          case UNICHAR_LEFT_TO_RIGHT_EMBEDDING:
1483          case UNICHAR_RIGHT_TO_LEFT_EMBEDDING:
1484          case UNICHAR_POP_DIRECTIONAL_FORMATTING:
1485          case UNICHAR_LEFT_TO_RIGHT_OVERRIDE:
1486          case UNICHAR_RIGHT_TO_LEFT_OVERRIDE:
1487          case UNICHAR_LEFT_TO_RIGHT_ISOLATE:
1488          case UNICHAR_RIGHT_TO_LEFT_ISOLATE:
1489          case UNICHAR_FIRST_STRONG_ISOLATE:
1490          case UNICHAR_POP_DIRECTIONAL_ISOLATE:
1491              result = true;
1492              break;
1493              
1494          default:
1495              result = false;
1496              break;
1497      }
1498      return ( result );
1499  }
1500  
1501  /*  __GetPathExtensionRangesFromPathComponentBuffer finds the range of the primary path extension (if any) for the given path component. If requested, __GetPathExtensionRangesFromPathComponentBuffer also finds the secondary path extension (if any) for the given path component.
1502   */
1503  CF_INLINE void __GetPathExtensionRangesFromPathComponentBuffer(CFStringInlineBuffer *buffer, CFRange *outPrimaryExtRange, CFRange *outSecondaryExtRange) {
1504      CFRange primaryExtRange = CFRangeMake(kCFNotFound, 0);
1505      CFRange secondaryExtRange = CFRangeMake(kCFNotFound, 0);
1506      
1507      if ( buffer && (outPrimaryExtRange || outSecondaryExtRange) ) {
1508          //
1509          // Look backwards for a period. The period may not be the first or last character of the path component,
1510          // but otherwise the extension may be of any length and contain any characters
1511          // except space, a path separator, or any unicode directional control character.
1512          //
1513          // The secondary extension is the "apparent" extension the user would see if
1514          // the primary extension is hidden. Since this is a security concern, the
1515          // rules for the secondary extension are looser. Leading and trailing spaces
1516          // are ignored, since the user might think "foo.txt .app" is a text file if
1517          // ".app" is hidden.
1518          
1519          CFIndex nameLen = buffer->rangeToBuffer.length;
1520          
1521          for ( CFIndex i = nameLen - 1; i > 0; i-- ) {
1522              UniChar c = __CFStringGetCharacterFromInlineBufferQuickReverse(buffer, i);
1523              if ( (UniChar)'.' == c ) {
1524                  // Found a dot
1525                  CFIndex e2i = 0;
1526                  if ( i == (nameLen - 1) ) {
1527                      // Last char disqualified
1528                      break;
1529                  }
1530                  
1531                  primaryExtRange = CFRangeMake(i + 1, nameLen - (i + 1));
1532                  
1533                  if ( outSecondaryExtRange == NULL ) {
1534                      break;
1535                  }
1536                  
1537                  // Look for an "apparent" secondary extension, using modified rules.
1538                  CFIndex e2len = 0;
1539                  
1540                  // Skip trailing space (one-liner):
1541                  for ( --i; (i > 0) && (__CFStringGetCharacterFromInlineBufferQuickReverse(buffer, i) == (UniChar)' '); i-- );
1542                  
1543                  // Scan apparent extension text
1544                  for ( ; i > 0; i-- ) {
1545                      c = __CFStringGetCharacterFromInlineBufferQuickReverse(buffer, i);
1546                      if ( ((UniChar)'.' == c) || ((UniChar)' ' == c) ) {
1547                          break;
1548                      }
1549                      e2len++;
1550                  }
1551                  
1552                  e2i = i + 1;
1553                  
1554                  // Skip leading space (one-liner):
1555                  for ( ; (i > 0) && (__CFStringGetCharacterFromInlineBufferQuickReverse(buffer, i) == (UniChar)' '); i-- );
1556                  
1557                  if ( (i > 0) && (__CFStringGetCharacterFromInlineBufferQuickReverse(buffer, i) == (UniChar)'.') && (e2len > 0) ) {
1558                      secondaryExtRange = CFRangeMake( e2i, e2len );
1559                  }
1560                  
1561                  break;
1562              }
1563              else if ( __IsInvalidExtensionCharacter(c) ) {
1564                  // Found a space, a path separator, or a unicode directional control character -- terminate the loop
1565                  break;
1566              }
1567          }
1568      }
1569      
1570      if ( outPrimaryExtRange ) {
1571          *outPrimaryExtRange = primaryExtRange;
1572      }
1573      
1574      if ( outSecondaryExtRange ) {
1575          *outSecondaryExtRange = secondaryExtRange;
1576      }
1577  }
1578  
1579  /*  __ExtensionIsValidToAppend determines if the characters in extension are valid to be appended as an extension.
1580   */
1581  CF_INLINE Boolean __ExtensionIsValidToAppend(CFStringInlineBuffer *buffer) {
1582      Boolean result;
1583      
1584      if ( buffer && buffer->rangeToBuffer.length ) {
1585          //
1586          // Look backwards for a period. If a period is found, it must not be the
1587          // last character and any characters after the period must be valid in an
1588          // extension, and all characters before the period are considered valid
1589          // except for the path separator character '/' (this allow strings like
1590          // "tar.gz" to be appended as an extension). The path separator
1591          // character '/' isn't allowed anywhere in the extension. If there's no
1592          // period, the entire string must be characters valid in an extension.
1593          // The extension may be of any length.
1594          
1595          CFIndex nameLen = buffer->rangeToBuffer.length;
1596          if ( nameLen ) {
1597              result = true;  // assume the best
1598              
1599              for ( CFIndex i = nameLen - 1; i >= 0; i-- ) {
1600                  UniChar c = __CFStringGetCharacterFromInlineBufferQuickReverse(buffer, i);
1601                  if ( (UniChar)'.' == c ) {
1602                      // Found a period. If it's  the last character, then return false; otherwise true
1603                      result = i < nameLen - 1;
1604                      if ( result ) {
1605                          // check the rest of the string before the period for '/'
1606                          for ( CFIndex j = i - 1; j >= 0; j-- ) {
1607                              c = __CFStringGetCharacterFromInlineBufferQuickReverse(buffer, j);
1608                              if ( c == (UniChar)'/'){
1609                                  result = false;
1610                                  break;
1611                              }
1612                          }
1613                      }
1614                      break;
1615                  }
1616                  else if ( __IsInvalidExtensionCharacter(c) ) {
1617                      // Found an invalid extension character. Return false.
1618                      result = false;
1619                      break;
1620                  }
1621              }
1622          }
1623          else {
1624              // NOTE: The implementation before we switched to _CFGetPathExtensionRangesFromPathComponent
1625              // allowed an empty string to be appended as an extension. That is not a valid extension.
1626              result = false;
1627          }
1628      }
1629      else {
1630          // no buffer or no extension
1631          result = false;
1632      }
1633      return ( result );
1634  }
1635  
1636  /*  _CFGetExtensionInfoFromPathComponent/_CFGetPathExtensionRangesFromPathComponentUniChars finds the range of the primary path extension (if any) for the given path component. If requested, _CFGetExtensionInfoFromPathComponent/_CFGetPathExtensionRangesFromPathComponentUniChars also finds the secondary path extension (if any) for the given path component.
1637   */
1638  CF_EXPORT void _CFGetPathExtensionRangesFromPathComponentUniChars(const UniChar *uchars, CFIndex ucharsLength, CFRange *outPrimaryExtRange, CFRange *outSecondaryExtRange) {
1639      CFStringInlineBuffer buffer;
1640      UniCharInitInlineBuffer(uchars, ucharsLength, &buffer);
1641      __GetPathExtensionRangesFromPathComponentBuffer(&buffer, outPrimaryExtRange, outSecondaryExtRange);
1642  }
1643  
1644  CF_EXPORT void _CFGetPathExtensionRangesFromPathComponent(CFStringRef inName, CFRange *outPrimaryExtRange, CFRange *outSecondaryExtRange) {
1645      CFStringInlineBuffer buffer;
1646      CFStringInitInlineBuffer(inName, &buffer, CFRangeMake(0, CFStringGetLength(inName)));
1647      __GetPathExtensionRangesFromPathComponentBuffer(&buffer, outPrimaryExtRange, outSecondaryExtRange);
1648  }
1649  
1650  /*  _CFPathExtensionIsValid/_CFExtensionUniCharsIsValidToAppend determines if the characters in extension are valid to be appended as an extension.
1651   */
1652  CF_EXPORT Boolean _CFExtensionUniCharsIsValidToAppend(const UniChar *uchars, CFIndex ucharsLength) {
1653      CFStringInlineBuffer buffer;
1654      UniCharInitInlineBuffer(uchars, ucharsLength, &buffer);
1655      return ( __ExtensionIsValidToAppend(&buffer) );
1656  }
1657  
1658  CF_EXPORT Boolean _CFExtensionIsValidToAppend(CFStringRef extension) {
1659      CFStringInlineBuffer buffer;
1660      CFStringInitInlineBuffer(extension, &buffer, CFRangeMake(0, CFStringGetLength(extension)));
1661      return ( __ExtensionIsValidToAppend(&buffer) );
1662  }
1663  
1664  
1665  #if DEPLOYMENT_RUNTIME_SWIFT && !TARGET_OS_WASI
1666  
1667  CFDictionaryRef __CFGetEnvironment() {
1668      static dispatch_once_t once = 0L;
1669      static CFMutableDictionaryRef envDict = NULL;
1670      dispatch_once(&once, ^{
1671  #if TARGET_OS_MAC
1672          extern char ***_NSGetEnviron(void);
1673          char **envp = *_NSGetEnviron();
1674  #elif TARGET_OS_BSD || TARGET_OS_CYGWIN || TARGET_OS_WASI
1675          extern char **environ;
1676          char **envp = environ;
1677  #elif TARGET_OS_LINUX
1678  #if !defined(environ) && !TARGET_OS_ANDROID
1679  #define environ __environ
1680  #endif
1681          char **envp = environ;
1682  #elif TARGET_OS_WIN32
1683          char **envp = _environ;
1684  #endif
1685          envDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1686          for (; *envp; ++envp) {
1687              char *eqp = *envp;	// '=' pointer
1688              while (*eqp && *eqp != '=') ++eqp;
1689              
1690              char *endp = eqp;
1691              while (*endp) ++endp;
1692              
1693              if (endp == eqp) {	// oops, badly formed value
1694                  continue;
1695              }
1696              CFStringRef key = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (const uint8_t *)*envp, (eqp - *envp), kCFStringEncodingUTF8, false);
1697              if (key == NULL) {
1698                  key = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (const uint8_t *)*envp, (eqp - *envp), CFStringGetSystemEncoding(), false);
1699              }
1700              CFStringRef value = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (const uint8_t *)(eqp + 1), (endp - (eqp + 1)), kCFStringEncodingUTF8, false);
1701              if (key == NULL) {
1702                  key = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (const uint8_t *)(eqp + 1), (endp - (eqp + 1)), CFStringGetSystemEncoding(), false);
1703              }
1704              if (NULL == key || NULL == value) {
1705                  if (key != NULL) CFRelease(key);
1706                  if (value != NULL) CFRelease(value);
1707                  continue;
1708              }
1709              CFStringRef existingValue = CFDictionaryGetValue(envDict, key);
1710              if (existingValue == NULL) {
1711                  CFDictionarySetValue(envDict, key, value);
1712              } else if (CFEqual(existingValue, value)){
1713                  CFLog(kCFLogLevelWarning, CFSTR("Warning: duplicate definition for key '%@' found in environment -- subsequent definitions are ignored.  The first definition was '%@', the ignored definition is '%@'."), key, existingValue, value);
1714              }
1715              CFRelease(key);
1716              CFRelease(value);
1717          }
1718      });
1719      return envDict;
1720  }
1721  
1722  int32_t __CFGetPid() {
1723      return getpid();
1724  }
1725  
1726  #endif