@@ -361,7 +361,12 @@ impl LoadedPlugin {
361361 // Linker plugins handle entries of this vector serially, which means the message callback
362362 // should be registered first. Otherwise, they won't be able to indicate the problem with
363363 // entries preceding the callback and, for example, silently skip invalid arguments.
364- transfer_vector. push ( LdPluginTv :: fn_ptr2 ( Tag :: Message , message) ) ;
364+ // The message callback is variadic (printf-style), so we register the C trampoline
365+ // directly as a raw pointer value rather than going through fn_ptr2.
366+ transfer_vector. push ( LdPluginTv {
367+ tag : Tag :: Message as u32 ,
368+ value : wild_plugin_message_callback as * const ( ) as usize ,
369+ } ) ;
365370
366371 for arg in & args. plugin_args {
367372 transfer_vector. push ( LdPluginTv :: c_str ( Tag :: Option , arg) ) ;
@@ -992,26 +997,28 @@ extern "C" fn add_input_library(lib_name: *const libc::c_char) -> Status {
992997 Status :: Ok
993998}
994999
995- /// This function is called when the plugin wants to emit a message. It's supposed to accept varargs
996- /// similar to printf. Unfortunately that's not exactly easy for us to do, so we just report the
997- /// format string.
998- extern "C" fn message ( level : libc:: c_int , format : * const libc:: c_char ) -> Status {
999- catch_panics ( || {
1000- let Some ( level) = MessageLevel :: from_raw ( level) else {
1001- return Status :: Err ;
1002- } ;
1000+ unsafe extern "C" {
1001+ /// C trampoline that accepts the plugin's printf-style varargs, formats them via vsnprintf,
1002+ /// then calls `wild_handle_plugin_message` with the resulting string. Defined in
1003+ /// `plugin_message_shim.c`.
1004+ fn wild_plugin_message_callback ( level : libc:: c_int , fmt : * const libc:: c_char , ...) ;
1005+ }
1006+
1007+ /// Called by the C shim `wild_plugin_message_callback` with the already-formatted message string.
1008+ /// The `no_mangle` is required so the C shim can link against it by name.
1009+ #[ unsafe( no_mangle) ]
1010+ extern "C" fn wild_handle_plugin_message ( level : libc:: c_int , message : * const libc:: c_char ) {
1011+ let Some ( level) = MessageLevel :: from_raw ( level) else {
1012+ return ;
1013+ } ;
10031014
1004- let format = unsafe { CStr :: from_ptr ( format ) } ;
1015+ let text = unsafe { CStr :: from_ptr ( message ) } . to_string_lossy ( ) ;
10051016
1006- if level == MessageLevel :: Error || level == MessageLevel :: Fatal {
1007- println ! ( "Linker plugin {level}: {}" , format. to_string_lossy( ) ) ;
1008- ERROR_MESSAGE . replace ( Some ( format. to_string_lossy ( ) . to_string ( ) ) ) ;
1009- } else {
1010- println ! ( "Linker plugin {level}: {}" , format. to_string_lossy( ) ) ;
1011- }
1017+ println ! ( "Linker plugin {level}: {text}" ) ;
10121018
1013- Status :: Ok
1014- } )
1019+ if level == MessageLevel :: Error || level == MessageLevel :: Fatal {
1020+ ERROR_MESSAGE . replace ( Some ( text. into_owned ( ) ) ) ;
1021+ }
10151022}
10161023
10171024/// Runs `body`, catching any panics. In the case of a panic, the return status is changed to an
0 commit comments