racket / scribble

Other
194 stars 90 forks source link

Small scribble doc w/`pict` & `/gui` seems to cause ObjC exception #344

Closed jasonhemann closed 1 year ago

jasonhemann commented 1 year ago

Comparatively small file:

#lang scribble/manual

@include-section{test-some-pict.scrbl}
@(require "./test-blank-rack-gui-file.rkt")

Where the scribble file is:

#lang scribble/manual

@(require (only-in pict text))
@(text "hello")

and the racket file is simply:

#lang racket/gui

When trying to build the document, I see the following error:

$ scribble --errortrace --text test.scrbl
2022-09-05 18:56:04.312 racket[16615:1823314] -[__NSCFType initWithTypefaceInfo:key:renderingMode:]: unrecognized selector sent to instance 0x7fe75622eb50
2022-09-05 18:56:04.313 racket[16615:1823314] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFType initWithTypefaceInfo:key:renderingMode:]: unrecognized selector sent to instance 0x7fe75622eb50'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff2dda44d7 __exceptionPreprocess + 250
    1   libobjc.A.dylib                     0x00007fff6682e5bf objc_exception_throw + 48
    2   CoreFoundation                      0x00007fff2de23607 -[NSObject(NSObject) __retain_OA] + 0
    3   CoreFoundation                      0x00007fff2dd08d2b ___forwarding___ + 1427
    4   CoreFoundation                      0x00007fff2dd08708 _CF_forwarding_prep_0 + 120
    5   UIFoundation                        0x00007fff5ec1a044 -[__NSFontTypefaceInfo fontInstanceForKey:renderingMode:] + 100
    6   UIFoundation                        0x00007fff5ec19108 __NSGetMetaFontInstanceWithType + 270
    7   UIFoundation                        0x00007fff5ec1b00a +[NSFont systemFontOfSize:] + 94
    8   ???                                 0x000000011088ffc0 0x0 + 4572381120
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Abort trap: 6

I'm on Racket 8.6, XCode Version 12.4 (12D4e), and MacOS 10.15.7.

mflatt commented 1 year ago

The problem seems to be something about the implementation of Mac libraries. Here's a relatively small program that crashes in the same way on my machine:

#lang racket
(require ffi/unsafe
         ffi/unsafe/objc)

(define (load-appkit)
  (void (ffi-lib (format "/System/Library/Frameworks/AppKit.framework/AppKit"))))

(define CTFontCollectionCreateFromAvailableFonts
  (get-ffi-obj 'CTFontCollectionCreateFromAvailableFonts
               (ffi-lib (format "/System/Library/Frameworks/CoreText.framework/CoreText"))
               (_fun _pointer -> _pointer)))

(CTFontCollectionCreateFromAvailableFonts #f)
(load-appkit)

(import-class NSApplication)
(tell NSApplication sharedApplication) ; crash happens here

But if you swap the order of the calls to CTFontCollectionCreateFromAvailableFonts and load-appkit, there's no crash. It seems that maybe CTFontCollectionCreateFromAvailableFonts is sensitive to whether AppKit hash been loaded (which potentially makes sense, given that it's supposed to get fonts available to the current application), and then loading AppKit later puts things in a bad state for NSApplication. Applications don't normally load AppKit and access NSApplication dynamically, so that's why it wouldn't affect many Mac programs.

The answer is probably to force a load of AppKit on Mac OS before the call to pango_cairo_font_map_new, which is the part of Pango that calls CTFontCollectionCreateFromAvailableFonts. Or just loading AppKit on initialization of the Pango library is simplest and probably fine.