You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实现路由表管理器注册时遇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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 21:35:02