]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-os.mm
objc4-706.tar.gz
[apple/objc4.git] / runtime / objc-os.mm
1 /*
2 * Copyright (c) 2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /***********************************************************************
25 * objc-os.m
26 * OS portability layer.
27 **********************************************************************/
28
29 #include "objc-private.h"
30 #include "objc-loadmethod.h"
31
32 #if TARGET_OS_WIN32
33
34 #include "objc-runtime-old.h"
35 #include "objcrt.h"
36
37 int monitor_init(monitor_t *c)
38 {
39 // fixme error checking
40 HANDLE mutex = CreateMutex(NULL, TRUE, NULL);
41 while (!c->mutex) {
42 // fixme memory barrier here?
43 if (0 == InterlockedCompareExchangePointer(&c->mutex, mutex, 0)) {
44 // we win - finish construction
45 c->waiters = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
46 c->waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL);
47 InitializeCriticalSection(&c->waitCountLock);
48 c->waitCount = 0;
49 c->didBroadcast = 0;
50 ReleaseMutex(c->mutex);
51 return 0;
52 }
53 }
54
55 // someone else allocated the mutex and constructed the monitor
56 ReleaseMutex(mutex);
57 CloseHandle(mutex);
58 return 0;
59 }
60
61 void mutex_init(mutex_t *m)
62 {
63 while (!m->lock) {
64 CRITICAL_SECTION *newlock = malloc(sizeof(CRITICAL_SECTION));
65 InitializeCriticalSection(newlock);
66 // fixme memory barrier here?
67 if (0 == InterlockedCompareExchangePointer(&m->lock, newlock, 0)) {
68 return;
69 }
70 // someone else installed their lock first
71 DeleteCriticalSection(newlock);
72 free(newlock);
73 }
74 }
75
76
77 void recursive_mutex_init(recursive_mutex_t *m)
78 {
79 // fixme error checking
80 HANDLE newmutex = CreateMutex(NULL, FALSE, NULL);
81 while (!m->mutex) {
82 // fixme memory barrier here?
83 if (0 == InterlockedCompareExchangePointer(&m->mutex, newmutex, 0)) {
84 // we win
85 return;
86 }
87 }
88
89 // someone else installed their lock first
90 CloseHandle(newmutex);
91 }
92
93
94 WINBOOL APIENTRY DllMain( HMODULE hModule,
95 DWORD ul_reason_for_call,
96 LPVOID lpReserved
97 )
98 {
99 switch (ul_reason_for_call) {
100 case DLL_PROCESS_ATTACH:
101 environ_init();
102 tls_init();
103 lock_init();
104 sel_init(3500); // old selector heuristic
105 exception_init();
106 break;
107
108 case DLL_THREAD_ATTACH:
109 break;
110
111 case DLL_THREAD_DETACH:
112 case DLL_PROCESS_DETACH:
113 break;
114 }
115 return TRUE;
116 }
117
118 OBJC_EXPORT void *_objc_init_image(HMODULE image, const objc_sections *sects)
119 {
120 header_info *hi = malloc(sizeof(header_info));
121 size_t count, i;
122
123 hi->mhdr = (const headerType *)image;
124 hi->info = sects->iiStart;
125 hi->allClassesRealized = NO;
126 hi->modules = sects->modStart ? (Module *)((void **)sects->modStart+1) : 0;
127 hi->moduleCount = (Module *)sects->modEnd - hi->modules;
128 hi->protocols = sects->protoStart ? (struct old_protocol **)((void **)sects->protoStart+1) : 0;
129 hi->protocolCount = (struct old_protocol **)sects->protoEnd - hi->protocols;
130 hi->imageinfo = NULL;
131 hi->imageinfoBytes = 0;
132 // hi->imageinfo = sects->iiStart ? (uint8_t *)((void **)sects->iiStart+1) : 0;;
133 // hi->imageinfoBytes = (uint8_t *)sects->iiEnd - hi->imageinfo;
134 hi->selrefs = sects->selrefsStart ? (SEL *)((void **)sects->selrefsStart+1) : 0;
135 hi->selrefCount = (SEL *)sects->selrefsEnd - hi->selrefs;
136 hi->clsrefs = sects->clsrefsStart ? (Class *)((void **)sects->clsrefsStart+1) : 0;
137 hi->clsrefCount = (Class *)sects->clsrefsEnd - hi->clsrefs;
138
139 count = 0;
140 for (i = 0; i < hi->moduleCount; i++) {
141 if (hi->modules[i]) count++;
142 }
143 hi->mod_count = 0;
144 hi->mod_ptr = 0;
145 if (count > 0) {
146 hi->mod_ptr = malloc(count * sizeof(struct objc_module));
147 for (i = 0; i < hi->moduleCount; i++) {
148 if (hi->modules[i]) memcpy(&hi->mod_ptr[hi->mod_count++], hi->modules[i], sizeof(struct objc_module));
149 }
150 }
151
152 hi->moduleName = malloc(MAX_PATH * sizeof(TCHAR));
153 GetModuleFileName((HMODULE)(hi->mhdr), hi->moduleName, MAX_PATH * sizeof(TCHAR));
154
155 appendHeader(hi);
156
157 if (PrintImages) {
158 _objc_inform("IMAGES: loading image for %s%s%s%s\n",
159 hi->fname,
160 headerIsBundle(hi) ? " (bundle)" : "",
161 hi->info->isReplacement() ? " (replacement)":"",
162 hi->info->hasCategoryClassProperties() ? " (has class properties)":"");
163 }
164
165 // Count classes. Size various table based on the total.
166 int total = 0;
167 int unoptimizedTotal = 0;
168 {
169 if (_getObjc2ClassList(hi, &count)) {
170 total += (int)count;
171 if (!hi->getInSharedCache()) unoptimizedTotal += count;
172 }
173 }
174
175 _read_images(&hi, 1, total, unoptimizedTotal);
176
177 return hi;
178 }
179
180 OBJC_EXPORT void _objc_load_image(HMODULE image, header_info *hinfo)
181 {
182 prepare_load_methods(hinfo);
183 call_load_methods();
184 }
185
186 OBJC_EXPORT void _objc_unload_image(HMODULE image, header_info *hinfo)
187 {
188 _objc_fatal("image unload not supported");
189 }
190
191
192 // TARGET_OS_WIN32
193 #elif TARGET_OS_MAC
194
195 #include "objc-file-old.h"
196 #include "objc-file.h"
197
198
199 /***********************************************************************
200 * libobjc must never run static destructors.
201 * Cover libc's __cxa_atexit with our own definition that runs nothing.
202 * rdar://21734598 ER: Compiler option to suppress C++ static destructors
203 **********************************************************************/
204 extern "C" int __cxa_atexit();
205 extern "C" int __cxa_atexit() { return 0; }
206
207
208 /***********************************************************************
209 * bad_magic.
210 * Return YES if the header has invalid Mach-o magic.
211 **********************************************************************/
212 bool bad_magic(const headerType *mhdr)
213 {
214 return (mhdr->magic != MH_MAGIC && mhdr->magic != MH_MAGIC_64 &&
215 mhdr->magic != MH_CIGAM && mhdr->magic != MH_CIGAM_64);
216 }
217
218
219 static header_info * addHeader(const headerType *mhdr, const char *path, int &totalClasses, int &unoptimizedTotalClasses)
220 {
221 header_info *hi;
222
223 if (bad_magic(mhdr)) return NULL;
224
225 bool inSharedCache = false;
226
227 // Look for hinfo from the dyld shared cache.
228 hi = preoptimizedHinfoForHeader(mhdr);
229 if (hi) {
230 // Found an hinfo in the dyld shared cache.
231
232 // Weed out duplicates.
233 if (hi->isLoaded()) {
234 return NULL;
235 }
236
237 inSharedCache = true;
238
239 // Initialize fields not set by the shared cache
240 // hi->next is set by appendHeader
241 hi->setLoaded(true);
242
243 if (PrintPreopt) {
244 _objc_inform("PREOPTIMIZATION: honoring preoptimized header info at %p for %s", hi, hi->fname());
245 }
246
247 #if !__OBJC2__
248 _objc_fatal("shouldn't be here");
249 #endif
250 #if DEBUG
251 // Verify image_info
252 size_t info_size = 0;
253 const objc_image_info *image_info = _getObjcImageInfo(mhdr,&info_size);
254 assert(image_info == hi->info());
255 #endif
256 }
257 else
258 {
259 // Didn't find an hinfo in the dyld shared cache.
260
261 // Weed out duplicates
262 for (hi = FirstHeader; hi; hi = hi->getNext()) {
263 if (mhdr == hi->mhdr()) return NULL;
264 }
265
266 // Locate the __OBJC segment
267 size_t info_size = 0;
268 unsigned long seg_size;
269 const objc_image_info *image_info = _getObjcImageInfo(mhdr,&info_size);
270 const uint8_t *objc_segment = getsegmentdata(mhdr,SEG_OBJC,&seg_size);
271 if (!objc_segment && !image_info) return NULL;
272
273 // Allocate a header_info entry.
274 // Note we also allocate space for a single header_info_rw in the
275 // rw_data[] inside header_info.
276 hi = (header_info *)calloc(sizeof(header_info) + sizeof(header_info_rw), 1);
277
278 // Set up the new header_info entry.
279 hi->setmhdr(mhdr);
280 #if !__OBJC2__
281 // mhdr must already be set
282 hi->mod_count = 0;
283 hi->mod_ptr = _getObjcModules(hi, &hi->mod_count);
284 #endif
285 // Install a placeholder image_info if absent to simplify code elsewhere
286 static const objc_image_info emptyInfo = {0, 0};
287 hi->setinfo(image_info ?: &emptyInfo);
288
289 hi->setLoaded(true);
290 hi->setAllClassesRealized(NO);
291 }
292
293 #if __OBJC2__
294 {
295 size_t count = 0;
296 if (_getObjc2ClassList(hi, &count)) {
297 totalClasses += (int)count;
298 if (!inSharedCache) unoptimizedTotalClasses += count;
299 }
300 }
301 #endif
302
303 appendHeader(hi);
304
305 return hi;
306 }
307
308
309 /***********************************************************************
310 * linksToLibrary
311 * Returns true if the image links directly to a dylib whose install name
312 * is exactly the given name.
313 **********************************************************************/
314 bool
315 linksToLibrary(const header_info *hi, const char *name)
316 {
317 const struct dylib_command *cmd;
318 unsigned long i;
319
320 cmd = (const struct dylib_command *) (hi->mhdr() + 1);
321 for (i = 0; i < hi->mhdr()->ncmds; i++) {
322 if (cmd->cmd == LC_LOAD_DYLIB || cmd->cmd == LC_LOAD_UPWARD_DYLIB ||
323 cmd->cmd == LC_LOAD_WEAK_DYLIB || cmd->cmd == LC_REEXPORT_DYLIB)
324 {
325 const char *dylib = cmd->dylib.name.offset + (const char *)cmd;
326 if (0 == strcmp(dylib, name)) return true;
327 }
328 cmd = (const struct dylib_command *)((char *)cmd + cmd->cmdsize);
329 }
330
331 return false;
332 }
333
334
335 #if SUPPORT_GC_COMPAT
336
337 /***********************************************************************
338 * shouldRejectGCApp
339 * Return YES if the executable requires GC.
340 **********************************************************************/
341 static bool shouldRejectGCApp(const header_info *hi)
342 {
343 assert(hi->mhdr()->filetype == MH_EXECUTE);
344
345 if (!hi->info()->supportsGC()) {
346 // App does not use GC. Don't reject it.
347 return NO;
348 }
349
350 // Exception: Trivial AppleScriptObjC apps can run without GC.
351 // 1. executable defines no classes
352 // 2. executable references NSBundle only
353 // 3. executable links to AppleScriptObjC.framework
354 // Note that objc_appRequiresGC() also knows about this.
355 size_t classcount = 0;
356 size_t refcount = 0;
357 #if __OBJC2__
358 _getObjc2ClassList(hi, &classcount);
359 _getObjc2ClassRefs(hi, &refcount);
360 #else
361 if (hi->mod_count == 0 || (hi->mod_count == 1 && !hi->mod_ptr[0].symtab)) classcount = 0;
362 else classcount = 1;
363 _getObjcClassRefs(hi, &refcount);
364 #endif
365 if (classcount == 0 && refcount == 1 &&
366 linksToLibrary(hi, "/System/Library/Frameworks"
367 "/AppleScriptObjC.framework/Versions/A"
368 "/AppleScriptObjC"))
369 {
370 // It's AppleScriptObjC. Don't reject it.
371 return NO;
372 }
373 else {
374 // GC and not trivial AppleScriptObjC. Reject it.
375 return YES;
376 }
377 }
378
379
380 /***********************************************************************
381 * rejectGCImage
382 * Halt if an image requires GC.
383 * Testing of the main executable should use rejectGCApp() instead.
384 **********************************************************************/
385 static bool shouldRejectGCImage(const headerType *mhdr)
386 {
387 assert(mhdr->filetype != MH_EXECUTE);
388
389 objc_image_info *image_info;
390 size_t size;
391
392 #if !__OBJC2__
393 unsigned long seg_size;
394 // 32-bit: __OBJC seg but no image_info means no GC support
395 if (!getsegmentdata(mhdr, "__OBJC", &seg_size)) {
396 // Not objc, therefore not GC. Don't reject it.
397 return NO;
398 }
399 image_info = _getObjcImageInfo(mhdr, &size);
400 if (!image_info) {
401 // No image_info, therefore not GC. Don't reject it.
402 return NO;
403 }
404 #else
405 // 64-bit: no image_info means no objc at all
406 image_info = _getObjcImageInfo(mhdr, &size);
407 if (!image_info) {
408 // Not objc, therefore not GC. Don't reject it.
409 return NO;
410 }
411 #endif
412
413 return image_info->requiresGC();
414 }
415
416 // SUPPORT_GC_COMPAT
417 #endif
418
419
420 /***********************************************************************
421 * map_images_nolock
422 * Process the given images which are being mapped in by dyld.
423 * All class registration and fixups are performed (or deferred pending
424 * discovery of missing superclasses etc), and +load methods are called.
425 *
426 * info[] is in bottom-up order i.e. libobjc will be earlier in the
427 * array than any library that links to libobjc.
428 *
429 * Locking: loadMethodLock(old) or runtimeLock(new) acquired by map_images.
430 **********************************************************************/
431 #if __OBJC2__
432 #include "objc-file.h"
433 #else
434 #include "objc-file-old.h"
435 #endif
436
437 void
438 map_images_nolock(unsigned mhCount, const char * const mhPaths[],
439 const struct mach_header * const mhdrs[])
440 {
441 static bool firstTime = YES;
442 header_info *hList[mhCount];
443 uint32_t hCount;
444 size_t selrefCount = 0;
445
446 // Perform first-time initialization if necessary.
447 // This function is called before ordinary library initializers.
448 // fixme defer initialization until an objc-using image is found?
449 if (firstTime) {
450 preopt_init();
451 }
452
453 if (PrintImages) {
454 _objc_inform("IMAGES: processing %u newly-mapped images...\n", mhCount);
455 }
456
457
458 // Find all images with Objective-C metadata.
459 hCount = 0;
460
461 // Count classes. Size various table based on the total.
462 int totalClasses = 0;
463 int unoptimizedTotalClasses = 0;
464 {
465 uint32_t i = mhCount;
466 while (i--) {
467 const headerType *mhdr = (const headerType *)mhdrs[i];
468
469 auto hi = addHeader(mhdr, mhPaths[i], totalClasses, unoptimizedTotalClasses);
470 if (!hi) {
471 // no objc data in this entry
472 continue;
473 }
474
475 if (mhdr->filetype == MH_EXECUTE) {
476 // Size some data structures based on main executable's size
477 #if __OBJC2__
478 size_t count;
479 _getObjc2SelectorRefs(hi, &count);
480 selrefCount += count;
481 _getObjc2MessageRefs(hi, &count);
482 selrefCount += count;
483 #else
484 _getObjcSelectorRefs(hi, &selrefCount);
485 #endif
486
487 #if SUPPORT_GC_COMPAT
488 // Halt if this is a GC app.
489 if (shouldRejectGCApp(hi)) {
490 _objc_fatal_with_reason
491 (OBJC_EXIT_REASON_GC_NOT_SUPPORTED,
492 OS_REASON_FLAG_CONSISTENT_FAILURE,
493 "Objective-C garbage collection "
494 "is no longer supported.");
495 }
496 #endif
497 }
498
499 hList[hCount++] = hi;
500
501 if (PrintImages) {
502 _objc_inform("IMAGES: loading image for %s%s%s%s%s\n",
503 hi->fname(),
504 mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
505 hi->info()->isReplacement() ? " (replacement)" : "",
506 hi->info()->hasCategoryClassProperties() ? " (has class properties)" : "",
507 hi->info()->optimizedByDyld()?" (preoptimized)":"");
508 }
509 }
510 }
511
512 // Perform one-time runtime initialization that must be deferred until
513 // the executable itself is found. This needs to be done before
514 // further initialization.
515 // (The executable may not be present in this infoList if the
516 // executable does not contain Objective-C code but Objective-C
517 // is dynamically loaded later.
518 if (firstTime) {
519 sel_init(selrefCount);
520 arr_init();
521
522 #if SUPPORT_GC_COMPAT
523 // Reject any GC images linked to the main executable.
524 // We already rejected the app itself above.
525 // Images loaded after launch will be rejected by dyld.
526
527 for (uint32_t i = 0; i < hCount; i++) {
528 auto hi = hList[i];
529 auto mh = hi->mhdr();
530 if (mh->filetype != MH_EXECUTE && shouldRejectGCImage(mh)) {
531 _objc_fatal_with_reason
532 (OBJC_EXIT_REASON_GC_NOT_SUPPORTED,
533 OS_REASON_FLAG_CONSISTENT_FAILURE,
534 "%s requires Objective-C garbage collection "
535 "which is no longer supported.", hi->fname());
536 }
537 }
538 #endif
539 }
540
541 if (hCount > 0) {
542 _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
543 }
544
545 firstTime = NO;
546 }
547
548
549 /***********************************************************************
550 * unmap_image_nolock
551 * Process the given image which is about to be unmapped by dyld.
552 * mh is mach_header instead of headerType because that's what
553 * dyld_priv.h says even for 64-bit.
554 *
555 * Locking: loadMethodLock(both) and runtimeLock(new) acquired by unmap_image.
556 **********************************************************************/
557 void
558 unmap_image_nolock(const struct mach_header *mh)
559 {
560 if (PrintImages) {
561 _objc_inform("IMAGES: processing 1 newly-unmapped image...\n");
562 }
563
564 header_info *hi;
565
566 // Find the runtime's header_info struct for the image
567 for (hi = FirstHeader; hi != NULL; hi = hi->getNext()) {
568 if (hi->mhdr() == (const headerType *)mh) {
569 break;
570 }
571 }
572
573 if (!hi) return;
574
575 if (PrintImages) {
576 _objc_inform("IMAGES: unloading image for %s%s%s\n",
577 hi->fname(),
578 hi->mhdr()->filetype == MH_BUNDLE ? " (bundle)" : "",
579 hi->info()->isReplacement() ? " (replacement)" : "");
580 }
581
582 _unload_image(hi);
583
584 // Remove header_info from header list
585 removeHeader(hi);
586 free(hi);
587 }
588
589
590 /***********************************************************************
591 * static_init
592 * Run C++ static constructor functions.
593 * libc calls _objc_init() before dyld would call our static constructors,
594 * so we have to do it ourselves.
595 **********************************************************************/
596 static void static_init()
597 {
598 size_t count;
599 Initializer *inits = getLibobjcInitializers(&_mh_dylib_header, &count);
600 for (size_t i = 0; i < count; i++) {
601 inits[i]();
602 }
603 }
604
605
606 /***********************************************************************
607 * _objc_init
608 * Bootstrap initialization. Registers our image notifier with dyld.
609 * Called by libSystem BEFORE library initialization time
610 **********************************************************************/
611
612 void _objc_init(void)
613 {
614 static bool initialized = false;
615 if (initialized) return;
616 initialized = true;
617
618 // fixme defer initialization until an objc-using image is found?
619 environ_init();
620 tls_init();
621 static_init();
622 lock_init();
623 exception_init();
624
625 _dyld_objc_notify_register(&map_2_images, load_images, unmap_image);
626 }
627
628
629 /***********************************************************************
630 * _headerForAddress.
631 * addr can be a class or a category
632 **********************************************************************/
633 static const header_info *_headerForAddress(void *addr)
634 {
635 #if __OBJC2__
636 const char *segnames[] = { "__DATA", "__DATA_CONST", "__DATA_DIRTY" };
637 #else
638 const char *segnames[] = { "__OBJC" };
639 #endif
640 header_info *hi;
641
642 for (hi = FirstHeader; hi != NULL; hi = hi->getNext()) {
643 for (size_t i = 0; i < sizeof(segnames)/sizeof(segnames[0]); i++) {
644 unsigned long seg_size;
645 uint8_t *seg = getsegmentdata(hi->mhdr(), segnames[i], &seg_size);
646 if (!seg) continue;
647
648 // Is the class in this header?
649 if ((uint8_t *)addr >= seg && (uint8_t *)addr < seg + seg_size) {
650 return hi;
651 }
652 }
653 }
654
655 // Not found
656 return 0;
657 }
658
659
660 /***********************************************************************
661 * _headerForClass
662 * Return the image header containing this class, or NULL.
663 * Returns NULL on runtime-constructed classes, and the NSCF classes.
664 **********************************************************************/
665 const header_info *_headerForClass(Class cls)
666 {
667 return _headerForAddress(cls);
668 }
669
670
671 /**********************************************************************
672 * secure_open
673 * Securely open a file from a world-writable directory (like /tmp)
674 * If the file does not exist, it will be atomically created with mode 0600
675 * If the file exists, it must be, and remain after opening:
676 * 1. a regular file (in particular, not a symlink)
677 * 2. owned by euid
678 * 3. permissions 0600
679 * 4. link count == 1
680 * Returns a file descriptor or -1. Errno may or may not be set on error.
681 **********************************************************************/
682 int secure_open(const char *filename, int flags, uid_t euid)
683 {
684 struct stat fs, ls;
685 int fd = -1;
686 bool truncate = NO;
687 bool create = NO;
688
689 if (flags & O_TRUNC) {
690 // Don't truncate the file until after it is open and verified.
691 truncate = YES;
692 flags &= ~O_TRUNC;
693 }
694 if (flags & O_CREAT) {
695 // Don't create except when we're ready for it
696 create = YES;
697 flags &= ~O_CREAT;
698 flags &= ~O_EXCL;
699 }
700
701 if (lstat(filename, &ls) < 0) {
702 if (errno == ENOENT && create) {
703 // No such file - create it
704 fd = open(filename, flags | O_CREAT | O_EXCL, 0600);
705 if (fd >= 0) {
706 // File was created successfully.
707 // New file does not need to be truncated.
708 return fd;
709 } else {
710 // File creation failed.
711 return -1;
712 }
713 } else {
714 // lstat failed, or user doesn't want to create the file
715 return -1;
716 }
717 } else {
718 // lstat succeeded - verify attributes and open
719 if (S_ISREG(ls.st_mode) && // regular file?
720 ls.st_nlink == 1 && // link count == 1?
721 ls.st_uid == euid && // owned by euid?
722 (ls.st_mode & ALLPERMS) == (S_IRUSR | S_IWUSR)) // mode 0600?
723 {
724 // Attributes look ok - open it and check attributes again
725 fd = open(filename, flags, 0000);
726 if (fd >= 0) {
727 // File is open - double-check attributes
728 if (0 == fstat(fd, &fs) &&
729 fs.st_nlink == ls.st_nlink && // link count == 1?
730 fs.st_uid == ls.st_uid && // owned by euid?
731 fs.st_mode == ls.st_mode && // regular file, 0600?
732 fs.st_ino == ls.st_ino && // same inode as before?
733 fs.st_dev == ls.st_dev) // same device as before?
734 {
735 // File is open and OK
736 if (truncate) ftruncate(fd, 0);
737 return fd;
738 } else {
739 // Opened file looks funny - close it
740 close(fd);
741 return -1;
742 }
743 } else {
744 // File didn't open
745 return -1;
746 }
747 } else {
748 // Unopened file looks funny - don't open it
749 return -1;
750 }
751 }
752 }
753
754
755 #if TARGET_OS_IPHONE
756
757 const char *__crashreporter_info__ = NULL;
758
759 const char *CRSetCrashLogMessage(const char *msg)
760 {
761 __crashreporter_info__ = msg;
762 return msg;
763 }
764 const char *CRGetCrashLogMessage(void)
765 {
766 return __crashreporter_info__;
767 }
768
769 #endif
770
771 // TARGET_OS_MAC
772 #else
773
774
775 #error unknown OS
776
777
778 #endif