实现路由表管理器注册时遇RtmRegisterEntity访问违例及映射疑问
路由表管理器注册时触发访问违例及RTM_ENTITY_ID结构体映射问题
问题描述
访问违例错误
在实现微软官方《向路由表管理器注册》示例时,触发如下访问违例:
Exception has occurred: W32/0xC0000005 Unhandled exception at 0x00007FFCFACEBCE4 (rtm.dll) in clash-rs.exe: 0xC0000005: Access violation writing location 0x0000000000000000.
RTM_ENTITY_ID结构体映射疑惑
对Rust中windows::Win32::NetworkManagement::Rras::RTM_ENTITY_ID结构体的嵌套Anonymous、RTM_ENTITY_ID_0_0成员存在疑惑,是否因为对应C语言中的联合体定义?
C语言中原结构体定义:
typedef struct _RTM_ENTITY_ID { union { struct { ULONG EntityProtocolId; ULONG EntityInstanceId; }; ULONGLONG EntityId; }; } RTM_ENTITY_ID, *PRTM_ENTITY_ID;
这是否就是它映射到Rust的方式?不确定当前访问违例是否与指针错误有关。
Crate清单
[target.'cfg(windows)'.dependencies] windows = { version = "0.58", features = [ "Win32_Networking_WinSock", "Win32_Foundation", "Win32_NetworkManagement_Rras", ]}
Crate代码
let address_family = match dest { IpNet::V4(_) => AF_INET, IpNet::V6(_) => AF_INET6, }; let rtm_reg_handle: HANDLE = null_mut(); let mut rtm_entity_info = RTM_ENTITY_INFO::default(); let mut rtm_regn_profile = RTM_REGN_PROFILE::default(); rtm_entity_info.RtmInstanceId = 0; rtm_entity_info.AddressFamily = address_family.0; rtm_entity_info .EntityId .Anonymous .Anonymous .EntityProtocolId = PROTO_IP_RIP.0.try_into().unwrap(); rtm_entity_info .EntityId .Anonymous .Anonymous .EntityInstanceId = protocol_id( PROTO_TYPE_UCAST, PROTO_VENDOR_ID, PROTO_IP_RIP.0.try_into().unwrap(), ); let rv = unsafe { RtmRegisterEntity( &mut rtm_entity_info, null_mut(), None, false, &mut rtm_regn_profile, rtm_reg_handle as *mut _, ) }; if rv != ERROR_SUCCESS.0 { let err = unsafe { GetLastError().to_hresult().message() }; error!("failed to register entity: {}", err); return Err(new_io_error(err)); }
问题分析与解决
1. 访问违例的根源
访问违例提示写入空地址,核心原因是传递给RtmRegisterEntity的最后一个参数是无效的空指针。根据微软官方文档,该参数RegistrationHandle是输出参数,需要传入一个有效的可变HANDLE指针,用于接收注册后的句柄。
原代码中直接将初始化后的空指针rtm_reg_handle强转传递,函数内部尝试向空地址写入数据,导致访问违例。修正方式如下:
// 定义可变的HANDLE变量,初始为空 let mut rtm_reg_handle: HANDLE = null_mut(); // ... let rv = unsafe { RtmRegisterEntity( &mut rtm_entity_info, null_mut(), None, false, &mut rtm_regn_profile, &mut rtm_reg_handle, // 传递可变指针,让函数写入有效句柄 ) };
2. RTM_ENTITY_ID的Rust映射解释
是的,Rust中RTM_ENTITY_ID的嵌套Anonymous成员正是对C语言匿名联合体/结构体的标准映射:
- C中的匿名联合体被映射为Rust结构体的
Anonymous字段 - 联合体内部的匿名结构体进一步映射为该
Anonymous字段下的嵌套Anonymous(或RTM_ENTITY_ID_0_0)字段
你代码中对EntityProtocolId和EntityInstanceId的访问方式是正确的,这部分逻辑不是导致访问违例的原因。
内容的提问来源于stack exchange,提问作者ibigbug
相关产品推荐
相关产品推荐

