【问题标题】:How to specify that method argument must have longer lifetime than self's lifetime?如何指定方法参数的生命周期必须比自身的生命周期长?
【发布时间】:2015-01-17 14:27:47
【问题描述】:

我想为 C 库编写一个安全的 Rust 包装器。我需要用 Rust 的术语来表达 C 的库原始指针所有权规则。

该库具有其私有结构,例如:struct handle {void *_data},并将 setter 公开为set_data(struct handle*, void *data)

我想制作该方法的 Rust 版本,签名上写着“data 必须至少与handle 一样长”。

我试过了:

set_data(&'a self, &'a data:…)

但借用检查器似乎将其应用于该函数内的生命周期,而不是对象的整体生命周期。

我也尝试为impl 添加生命周期,但这仍然没有好处。完整的测试用例:

#![allow(unused_variables)]
struct Handle<'a>;

impl<'a> Handle<'a> {
    pub fn set_data(&'a mut self, data: &'a DropCanary) {
        // save data raw ptr
    }

    pub fn use_data(&'a self) {
        // use data raw ptr
        println!("alive?");
    }
}

fn main() {
    let mut handle = Handle;
    let long_enough_lifetime = DropCanary{label:"long"};

    {
        let short_lifetime = DropCanary{label:"short"};
        handle.set_data(&short_lifetime); // This shouldn't be allowed!
        handle.set_data(&long_enough_lifetime); // This is OK
    }

    handle.use_data();
}

/// --- just for testing ---

struct DropCanary {
    label: &'static str,
}

impl Drop for DropCanary {
    fn drop(&mut self) {
        println!("dropped: {}", self.label);
    }
}

问题在于以下代码compiles 和输出:

掉线:短
还活着吗?
掉线:长

所以它会导致 use-after-free,因为 Rust 不知道 short_lifetime 必须比 handle 寿命长。

【问题讨论】:

    标签: rust lifetime


    【解决方案1】:

    这应该适合你 (playpen)。

    您的示例编译的原因仅仅是因为您没有使用示例中结构内部的生命周期。由于您不使用它,因此对它没有任何限制,它也可以被省略。如果您没有在结构中存储任何具有生命周期的数据,则可以使用标记类型替换我使用的选项here

    #![allow(unused_variables)]
    struct Handle<'a>(Option<&'a DropCanary>);
    
    impl<'a> Handle<'a> {
        pub fn set_data(&mut self, data: &'a DropCanary) {
            self.0 = Some(data);
            // save data raw ptr
        }
    
        pub fn use_data(&self) {
            // use data raw ptr
            println!("alive?");
        }
    }
    
    fn main() {
        let mut handle = Handle(None);
        let long_enough_lifetime = DropCanary{label:"long"};
    
        {
            let short_lifetime = DropCanary{label:"short"};
            //handle.set_data(&short_lifetime); // This shouldn't be allowed!
            handle.set_data(&long_enough_lifetime); // This is OK
        }
    
        handle.use_data();
    }
    
    /// --- just for testing ---
    
    struct DropCanary {
        label: &'static str,
    }
    
    impl Drop for DropCanary {
        fn drop(&mut self) {
            println!("dropped: {}", self.label);
        }
    }
    

    【讨论】:

    • 谢谢! ContravariantLifetime 标记是我需要的。
    • 现在叫PhantomData :)
    • 如果你没有包含标记,现在也是一个错误。
    猜你喜欢
    • 1970-01-01
    • 2015-08-26
    • 1970-01-01
    • 1970-01-01
    • 2020-11-21
    • 1970-01-01
    • 1970-01-01
    • 2017-10-06
    • 1970-01-01
    相关资源
    最近更新 更多