@@ -2,7 +2,7 @@ use crate::error::{Error, Result};
22use crate :: instructions:: Instruction ;
33use crate :: logging:: { CallbackRegistry , LogLevel , LogOperation } ;
44use crate :: module:: Module ;
5- use crate :: types:: ValueType ;
5+ use crate :: types:: { ExternType , ValueType } ;
66use crate :: values:: Value ;
77use crate :: { format, String , ToString , Vec } ;
88
@@ -472,10 +472,43 @@ impl Engine {
472472 self . state = ExecutionState :: Running ;
473473
474474 // Fetch and validate information within a scope to limit borrow
475- let ( func_locals, instance_clone) = {
475+ let ( func_locals, instance_clone, _func_type ) = {
476476 // Scope to limit the borrow of self.instances
477477 let instance = & self . instances [ instance_idx as usize ] ;
478- let func = & instance. module . functions [ func_idx as usize ] ;
478+
479+ // Determine if this is an imported function
480+ let import_count = instance
481+ . module
482+ . imports
483+ . iter ( )
484+ . filter ( |import| matches ! ( import. ty, ExternType :: Function ( _) ) )
485+ . count ( ) ;
486+
487+ // Adjust function index for imports
488+ let actual_func_idx = if func_idx < import_count as u32 {
489+ // This is an imported function
490+ return Err ( Error :: Execution ( format ! (
491+ "Imported function at index {} cannot be called directly: {}.{}" ,
492+ func_idx,
493+ instance. module. imports[ func_idx as usize ] . module,
494+ instance. module. imports[ func_idx as usize ] . name
495+ ) ) ) ;
496+ } else {
497+ // This is a regular function, adjust index to skip imports
498+ func_idx - import_count as u32
499+ } ;
500+
501+ // Verify function index is valid
502+ if actual_func_idx as usize >= instance. module . functions . len ( ) {
503+ return Err ( Error :: Execution ( format ! (
504+ "Function index {} out of bounds (max: {})" ,
505+ actual_func_idx,
506+ instance. module. functions. len( )
507+ ) ) ) ;
508+ }
509+
510+ // Get the function and its type
511+ let func = & instance. module . functions [ actual_func_idx as usize ] ;
479512 let func_type = & instance. module . types [ func. type_idx as usize ] ;
480513
481514 // Check argument count
@@ -487,8 +520,8 @@ impl Engine {
487520 ) ) ) ;
488521 }
489522
490- // Clone the locals and instance for use outside this scope
491- ( func. locals . clone ( ) , instance. clone ( ) )
523+ // Clone the locals, function type, and instance for use outside this scope
524+ ( func. locals . clone ( ) , instance. clone ( ) , func_type . clone ( ) )
492525 } ;
493526
494527 // Create frame
@@ -524,18 +557,43 @@ impl Engine {
524557 0
525558 } ;
526559
527- // Get the function clone
528- let func_clone = {
560+ // Get the function clone and expected results
561+ let ( func_clone, expected_results ) = {
529562 let instance = & self . instances [ instance_idx as usize ] ;
530- instance. module . functions [ func_idx as usize ] . clone ( )
531- } ;
532563
533- // Get expected results count
534- let expected_results = {
535- let instance = & self . instances [ instance_idx as usize ] ;
536- let func = & instance. module . functions [ func_idx as usize ] ;
564+ // Determine if this is an imported function
565+ let import_count = instance
566+ . module
567+ . imports
568+ . iter ( )
569+ . filter ( |import| matches ! ( import. ty, ExternType :: Function ( _) ) )
570+ . count ( ) ;
571+
572+ // Adjust function index for imports
573+ let actual_func_idx = if func_idx < import_count as u32 {
574+ // We should not reach here because we already checked and returned an error above
575+ return Err ( Error :: Execution (
576+ "Trying to execute an imported function" . into ( ) ,
577+ ) ) ;
578+ } else {
579+ // This is a regular function, adjust index to skip imports
580+ func_idx - import_count as u32
581+ } ;
582+
583+ // Verify function index is valid
584+ if actual_func_idx as usize >= instance. module . functions . len ( ) {
585+ return Err ( Error :: Execution ( format ! (
586+ "Function index {} out of bounds (max: {})" ,
587+ actual_func_idx,
588+ instance. module. functions. len( )
589+ ) ) ) ;
590+ }
591+
592+ // Get the function and its result count
593+ let func = & instance. module . functions [ actual_func_idx as usize ] ;
537594 let func_type = & instance. module . types [ func. type_idx as usize ] ;
538- func_type. results . len ( )
595+
596+ ( func. clone ( ) , func_type. results . len ( ) )
539597 } ;
540598
541599 // Execute function body with fuel limitation
@@ -895,6 +953,49 @@ impl Engine {
895953 let local_func_idx = * func_idx;
896954 let module_idx = frame. module . module_idx ;
897955
956+ // Count imported functions that may affect the function index
957+ let import_count = frame
958+ . module
959+ . module
960+ . imports
961+ . iter ( )
962+ . filter ( |import| matches ! ( import. ty, ExternType :: Function ( _) ) )
963+ . count ( ) as u32 ;
964+
965+ // Check if we're calling an imported function
966+ let is_imported = local_func_idx < import_count;
967+
968+ // Check if this is an imported function call
969+ if is_imported {
970+ let import = & frame. module . module . imports [ local_func_idx as usize ] ;
971+
972+ // Special handling for the "env.print" function
973+ if import. module == "env" && import. name == "print" {
974+ // Get the parameter (expected to be an i32)
975+ let param = self . stack . pop ( ) ?;
976+ let value = param. as_i32 ( ) . unwrap_or ( 0 ) ;
977+
978+ // Print the value to the log and to stderr for debug purposes
979+ self . handle_log (
980+ LogLevel :: Info ,
981+ format ! ( "[Host function] env.print called with argument: {}" , value) ,
982+ ) ;
983+
984+ // Also print to stderr directly for debugging
985+ #[ cfg( feature = "std" ) ]
986+ eprintln ! ( "[Host function] env.print called with argument: {}" , value) ;
987+
988+ // Return without error for successful imported function execution
989+ return Ok ( None ) ;
990+ }
991+
992+ // For other imported functions, we will report they are not supported
993+ return Err ( Error :: Execution ( format ! (
994+ "Cannot call unsupported imported function at index {}: {}.{}" ,
995+ local_func_idx, import. module, import. name
996+ ) ) ) ;
997+ }
998+
898999 // Check if this is a component model custom function call (log function)
8991000 // We're looking for call to function index 1 (log) in a module with custom section "component-model-info"
9001001 let is_component_log = local_func_idx == 1
@@ -948,7 +1049,20 @@ impl Engine {
9481049 // No return value for log function
9491050 Ok ( None )
9501051 } else {
951- let func = & frame. module . module . functions [ local_func_idx as usize ] ;
1052+ // Adjust the function index to account for imported functions
1053+ let adjusted_func_idx = local_func_idx - import_count;
1054+
1055+ // Verify the adjusted index is valid
1056+ if adjusted_func_idx as usize >= frame. module . module . functions . len ( ) {
1057+ return Err ( Error :: Execution ( format ! (
1058+ "Function index {} (adjusted to {}) out of bounds (max: {})" ,
1059+ local_func_idx,
1060+ adjusted_func_idx,
1061+ frame. module. module. functions. len( )
1062+ ) ) ) ;
1063+ }
1064+
1065+ let func = & frame. module . module . functions [ adjusted_func_idx as usize ] ;
9521066 let func_type = & frame. module . module . types [ func. type_idx as usize ] ;
9531067 let params_len = func_type. params . len ( ) ;
9541068
0 commit comments