@@ -69,18 +69,27 @@ impl CefContext {
6969 let control_thread = std:: thread:: Builder :: new ( )
7070 . name ( "cef-host-control" . to_string ( ) )
7171 . spawn ( move || {
72- let result = control ( CefContextHandle ) ;
72+ let result = std :: panic :: catch_unwind ( std :: panic :: AssertUnwindSafe ( || control ( CefContextHandle ) ) ) ;
7373 with_context ( |context| {
74- context. browser . host ( ) . unwrap ( ) . close_browser ( 1 ) ;
74+ if let Some ( host) = context. browser . host ( ) {
75+ host. close_browser ( 1 ) ;
76+ }
7577 } ) ;
7678 run_on_ui_thread ( cef:: quit_message_loop) ;
77- let _ = result_sender. send ( result) ;
79+ match result {
80+ Ok ( result) => {
81+ let _ = result_sender. send ( result) ;
82+ }
83+ Err ( panic) => std:: panic:: resume_unwind ( panic) ,
84+ }
7885 } )
7986 . expect ( "Failed to spawn the CEF control thread" ) ;
8087 cef:: run_message_loop ( ) ;
8188 drop ( CONTEXT . take ( ) ) ;
8289 cef:: shutdown ( ) ;
83- let _ = control_thread. join ( ) ;
90+ if let Err ( panic) = control_thread. join ( ) {
91+ std:: panic:: resume_unwind ( panic) ;
92+ }
8493 result_receiver. recv ( ) . expect ( "The CEF control thread ended without a result" )
8594 }
8695}
@@ -95,11 +104,12 @@ pub(crate) fn execute_helper_process() -> std::process::ExitCode {
95104
96105fn bootstrap ( helper : bool ) -> Args {
97106 #[ cfg( target_os = "macos" ) ]
98- let _loader = {
107+ {
99108 let loader = cef:: library_loader:: LibraryLoader :: new ( & std:: env:: current_exe ( ) . unwrap ( ) , helper) ;
100109 assert ! ( loader. load( ) ) ;
101- loader
102- } ;
110+ // LibraryLoader unloads the framework on drop
111+ std:: mem:: forget ( loader) ;
112+ }
103113 #[ cfg( not( target_os = "macos" ) ) ]
104114 let _ = helper;
105115
@@ -109,13 +119,13 @@ fn bootstrap(helper: bool) -> Args {
109119
110120fn initialize ( args : & Args , instance_dir : & Path , accelerated_paint : bool ) -> Result < ( ) , InitError > {
111121 let mut app = App :: new ( BrowserProcessAppImpl :: new ( accelerated_paint) ) ;
112- if cef:: initialize ( Some ( args. as_main_args ( ) ) , Some ( & platform_settings ( instance_dir) ) , Some ( & mut app) , std:: ptr:: null_mut ( ) ) != 1 {
122+ if cef:: initialize ( Some ( args. as_main_args ( ) ) , Some ( & platform_settings ( instance_dir) ? ) , Some ( & mut app) , std:: ptr:: null_mut ( ) ) != 1 {
113123 return Err ( InitError :: InitializationFailureCode ( cef:: get_exit_code ( ) as u32 ) ) ;
114124 }
115125 Ok ( ( ) )
116126}
117127
118- fn platform_settings ( instance_dir : & Path ) -> Settings {
128+ fn platform_settings ( instance_dir : & Path ) -> Result < Settings , InitError > {
119129 let log_severity = match std:: env:: var ( "GRAPHITE_BROWSER_LOG" ) . unwrap_or_default ( ) . to_lowercase ( ) . as_str ( ) {
120130 "debug" => cef_log_severity_t:: LOGSEVERITY_VERBOSE ,
121131 "info" => cef_log_severity_t:: LOGSEVERITY_INFO ,
@@ -125,9 +135,12 @@ fn platform_settings(instance_dir: &Path) -> Settings {
125135 _ => cef_log_severity_t:: LOGSEVERITY_FATAL ,
126136 } ;
127137
138+ let Some ( root_cache_path) = instance_dir. to_str ( ) . map ( CefString :: from) else {
139+ return Err ( InitError :: PathResolutionFailed ( format ! ( "non-UTF-8 instance directory path: {}" , instance_dir. display( ) ) ) ) ;
140+ } ;
128141 let base = Settings {
129142 windowless_rendering_enabled : 1 ,
130- root_cache_path : instance_dir . to_str ( ) . map ( CefString :: from ) . unwrap ( ) ,
143+ root_cache_path,
131144 cache_path : "" . into ( ) ,
132145 disable_signal_handlers : 1 ,
133146 log_severity : LogSeverity :: from ( log_severity) ,
@@ -136,24 +149,31 @@ fn platform_settings(instance_dir: &Path) -> Settings {
136149
137150 #[ cfg( target_os = "macos" ) ]
138151 {
139- let exe = std:: env:: current_exe ( ) . expect ( "cannot get current exe path" ) ;
140- let app_root = exe. parent ( ) . and_then ( |p| p. parent ( ) ) . expect ( "bad path structure" ) . parent ( ) . expect ( "bad path structure" ) ;
141- Settings {
142- main_bundle_path : app_root. to_str ( ) . map ( CefString :: from) . unwrap ( ) ,
152+ let exe = std:: env:: current_exe ( ) . map_err ( |e| InitError :: PathResolutionFailed ( format ! ( "cannot get current exe path: {e}" ) ) ) ?;
153+ let app_root = exe
154+ . parent ( )
155+ . and_then ( |p| p. parent ( ) )
156+ . and_then ( |p| p. parent ( ) )
157+ . ok_or_else ( || InitError :: PathResolutionFailed ( format ! ( "executable is not inside an app bundle: {}" , exe. display( ) ) ) ) ?;
158+ let Some ( main_bundle_path) = app_root. to_str ( ) . map ( CefString :: from) else {
159+ return Err ( InitError :: PathResolutionFailed ( format ! ( "invalid app bundle path: {}" , app_root. display( ) ) ) ) ;
160+ } ;
161+ Ok ( Settings {
162+ main_bundle_path,
143163 multi_threaded_message_loop : 0 ,
144164 external_message_pump : 0 ,
145165 no_sandbox : 1 , // GPU helper crashes when running with sandbox
146166 ..base
147- }
167+ } )
148168 }
149169
150170 #[ cfg( not( target_os = "macos" ) ) ]
151- Settings {
171+ Ok ( Settings {
152172 multi_threaded_message_loop : 1 ,
153173 #[ cfg( target_os = "linux" ) ]
154174 no_sandbox : 1 ,
155175 ..base
156- }
176+ } )
157177}
158178
159179fn create_browser ( delegate : BrowserDelegate , frames : FrameStreamer , view_info_sender : Sender < ViewInfoUpdate > , instance_dir : TempDir , accelerated_paint : bool ) -> Result < BrowserContext , InitError > {
@@ -187,7 +207,9 @@ fn create_browser(delegate: BrowserDelegate, frames: FrameStreamer, view_info_se
187207
188208 let mut scheme_handler_factory = SchemeHandlerFactory :: new ( SchemeHandlerFactoryImpl :: new ( delegate. clone ( ) ) ) ;
189209 incognito_request_context. clear_scheme_handler_factories ( ) ;
190- incognito_request_context. register_scheme_handler_factory ( Some ( & RESOURCE_SCHEME . into ( ) ) , Some ( & RESOURCE_DOMAIN . into ( ) ) , Some ( & mut scheme_handler_factory) ) ;
210+ if incognito_request_context. register_scheme_handler_factory ( Some ( & RESOURCE_SCHEME . into ( ) ) , Some ( & RESOURCE_DOMAIN . into ( ) ) , Some ( & mut scheme_handler_factory) ) != 1 {
211+ return Err ( InitError :: SchemeHandlerRegistrationFailed ) ;
212+ }
191213
192214 let url = format ! ( "{RESOURCE_SCHEME}://{RESOURCE_DOMAIN}/" ) ;
193215 browser_host_create_browser_sync (
@@ -220,6 +242,10 @@ pub(crate) enum InitError {
220242 BrowserCreationFailed ,
221243 #[ error( "Request context creation failed" ) ]
222244 RequestContextCreationFailed ,
245+ #[ error( "Failed to resolve a required path: {0}" ) ]
246+ PathResolutionFailed ( String ) ,
247+ #[ error( "Scheme handler registration failed" ) ]
248+ SchemeHandlerRegistrationFailed ,
223249}
224250
225251#[ derive( Clone ) ]
@@ -261,7 +287,10 @@ impl BrowserContext {
261287
262288 fn refresh_view_info ( & self ) {
263289 let view_info = self . delegate . view_info ( ) ;
264- let host = self . browser . host ( ) . unwrap ( ) ;
290+ let Some ( host) = self . browser . host ( ) else {
291+ tracing:: error!( "Browser host is not available, cannot refresh view info" ) ;
292+ return ;
293+ } ;
265294 host. set_zoom_level ( view_info. zoom ( ) ) ;
266295 host. was_resized ( ) ;
267296
@@ -278,7 +307,11 @@ impl BrowserContext {
278307impl Drop for BrowserContext {
279308 fn drop ( & mut self ) {
280309 tracing:: debug!( "Shutting down CEF" ) ;
281- self . browser . host ( ) . unwrap ( ) . close_browser ( 1 ) ;
310+ if let Some ( host) = self . browser . host ( ) {
311+ host. close_browser ( 1 ) ;
312+ } else {
313+ tracing:: error!( "Browser host is not available, cannot close browser" ) ;
314+ }
282315 }
283316}
284317
@@ -298,7 +331,9 @@ where
298331{
299332 let closure_task = ClosureTask :: new ( closure) ;
300333 let mut task = Task :: new ( closure_task) ;
301- post_task ( ThreadId :: from ( cef_thread_id_t:: TID_UI ) , Some ( & mut task) ) ;
334+ if post_task ( ThreadId :: from ( cef_thread_id_t:: TID_UI ) , Some ( & mut task) ) != 1 {
335+ tracing:: error!( "Failed to post a task to the CEF UI thread" ) ;
336+ }
302337}
303338
304339fn with_context < F > ( closure : F )
0 commit comments