理解 “argument requires that `variable` is borrowed for `’static`'”

huangapple go评论136阅读模式
英文:

Understanding "argument requires that `variable` is borrowed for `'static`"

问题

以下是您提供的Rust代码的翻译:

use std::fs;

static mut GRAPH_BUILDER: Option<Box<[&[u8]; 2]>> = None;

#[export_name = "wizer.initialize"]
pub extern "C" fn init() {
    let weights = fs::read("./mobilenet.bin").unwrap();
    let xml = fs::read_to_string("./mobilenet.xml").unwrap().into_bytes();
    let input: [&[u8]; 2] = [&weights, &xml];

    unsafe {
        GRAPH_BUILDER = Some(Box::new(input));
    }
}

pub fn main() {
    unsafe {
        if GRAPH_BUILDER.is_none() {
            init();
        }
    }
}

这段代码存在两个主要问题:

  1. 错误E0597:weightsxml的生命周期问题。这是因为input数组中包含对weightsxml的引用,但它们是在init函数中创建的,该函数结束后它们的生命周期结束。为了解决这个问题,您可以使用Vec来动态分配内存,然后将数据复制到堆上,以确保它们在GRAPH_BUILDER中存在于整个程序生命周期中。请注意,这可能会导致更多的内存分配,但这是一种方式来解决生命周期问题。

  2. 数据类型问题:GRAPH_BUILDER被声明为Option<Box<[&[u8]; 2]>>,但您提到需要将其转换为&[&[u8]]。要做到这一点,您需要修改数据结构以适应需要的类型。以下是修改后的代码:

use std::fs;

static mut GRAPH_BUILDER: Option<Vec<Vec<u8>>> = None;

#[export_name = "wizer.initialize"]
pub extern "C" fn init() {
    let weights = fs::read("./mobilenet.bin").unwrap();
    let xml = fs::read_to_string("./mobilenet.xml").unwrap().into_bytes();

    let input: Vec<Vec<u8>> = vec![weights, xml];

    unsafe {
        GRAPH_BUILDER = Some(input);
    }
}

pub fn main() {
    unsafe {
        if GRAPH_BUILDER.is_none() {
            init();
        }
    }
}

这将使用Vec来存储weightsxml,并将它们包装在GRAPH_BUILDER中以满足所需的数据类型。这应该能够解决生命周期问题和数据类型问题。

英文:

I am completely new to rust but have prior experience in C and I have this rust code which does not compile.

use std::fs;

static mut GRAPH_BUILDER: Option&lt;Box&lt;[&amp;[u8]; 2]&gt;&gt; = None;

#[export_name = &quot;wizer.initialize&quot;]
pub extern &quot;C&quot; fn init() {
    let weights = fs::read(&quot;./mobilenet.bin&quot;).unwrap();
    let xml = fs::read_to_string(&quot;./mobilenet.xml&quot;).unwrap().into_bytes();
    let input: [&amp;[u8]; 2] = [&amp;weights, &amp;xml];

    unsafe {
        GRAPH_BUILDER = Some(Box::new(input));
    }
}

pub fn main() {
    unsafe {
        if GRAPH_BUILDER.is_none() {
            init();
        }
    }
}

When compiled with rustc main.rs It produces these errors

error[E0597]: `weights` does not live long enough
  --&gt; main.rs:9:30
   |
9  |     let input: [&amp;[u8]; 2] = [&amp;weights, &amp;xml];
   |                              ^^^^^^^^ borrowed value does not live long enough
...
12 |         GRAPH_BUILDER = Some(Box::new(input));
   |                              --------------- argument requires that `weights` is borrowed for `&#39;static`
13 |     }
14 | }
   | - `weights` dropped here while still borrowed

error[E0597]: `xml` does not live long enough
  --&gt; main.rs:9:40
   |
9  |     let input: [&amp;[u8]; 2] = [&amp;weights, &amp;xml];
   |                                        ^^^^ borrowed value does not live long enough
...
12 |         GRAPH_BUILDER = Some(Box::new(input));
   |                              --------------- argument requires that `xml` is borrowed for `&#39;static`
13 |     }
14 | }
   | - `xml` dropped here while still borrowed

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0597`.

I understand that this error is caused because weights is stored on the stack and will be unallocated when the init function terminates, so the static GRAPH_BUILDER would contain a pointer to unallocated memory. So I tried to use a Box instead, which from my understanding should act like malloc in C. But it does not seem to work. How can I get rust to allocate the weights and xml variables on the heap, without knowing their sizes at compile time? I.e. What is the rust-equivalent of malloc?

I have read here that you can call clone to fix this problem. But I don't want to do it because the files I read in are large. And I also don't understand why that would fix the problem. Wouldn't the clone just end up on the stack too?

EDIT: Another important thing I should mention, I need to provide GRAPH_BUILDER as an argument to the wasi_nn::load function, and it essentially expects it to be of the datatype slice &amp;[&amp;[u8]]. But I have absolutely no idea how to convert it to this datatype. Here is the continuation of the main function.

use wasi_nn;

pub extern &quot;C&quot; fn main() {
    bench::start();
    let context: wasi_nn::GraphExecutionContext;
    unsafe {
        if GRAPH_BUILDER.is_none() {
            init();
        }
    }

    let graph = unsafe {
        wasi_nn::load(
            &amp;GRAPH_BUILDER.expect(&quot;Graph builder was not initialized&quot;),
            wasi_nn::GRAPH_ENCODING_OPENVINO,
            wasi_nn::EXECUTION_TARGET_CPU,
        )
        .unwrap()
    };

I am trying to modify this code such that it creates &amp;[&amp;xml.into_bytes(), &amp;weights] in an initialization function instead of passing it directly.

答案1

得分: 2

Rust等效的malloc是什么?

这是一个完全不必要的问题,你无需深入研究,你需要实际查看你的代码并考虑发生了什么。

Rust的&T不是C风格的野指针,它是一个词法范围内的借用智能指针。它只能引用在其整个生命周期内词法有效的数据。

所以我尝试使用Box,根据我的理解,它应该像C中的malloc一样工作。但似乎不起作用。

不,因为在Box内部,你仍然放置了对函数局部数据的引用。这就是Rust抱怨的原因。

你没有将数据复制或移动到堆上,你只是添加了对完全相同问题的间接引用:当函数结束时,weightsxml仍然会被丢弃,而你放在Box中的引用仍然会悬挂,这是Rust不允许的。

weightsxmlVec<u8>,因此它们已经是拥有的、堆分配的数据类型。你需要做的就是移动它们到你的东西中:

static mut GRAPH_BUILDER: Option<(Vec<u8>, Vec<u8>)> = None;

[...]

GRAPH_BUILDER = Some((weights, xml));

此外,即使在Rust函数中,你也不希望在extern C函数中使用unwrap。据我所知,最好的情况下,它将会立即中止,最坏的情况下,这将是未定义行为。

英文:

> What is the rust-equivalent of malloc?

That is a completely unnecessary question, you don't need to dig further, you need to actually look at your code and think about what's happening.

Rust's &amp;T is not a C-style wild pointer, it's a lexically-scoped borrowing smart pointer. It can only refer to data that is lexically valid for its entire lifespan.

> So I tried to use a Box instead, which from my understanding should act like malloc in C. But it does not seem to work.

Well no, because inside your box you're still putting references to function-local data. Which is what Rust is complaining about.

You're not copying or moving that data to the heap you're just adding an indirection to the exact same issue: when the function ends, weights and xml are still going to be dropped, and the references you put inside your Box will still be dangling, which Rust does not allow.

But weights and xml are Vec&lt;u8&gt; so they're already owned, heap-allocated data types. All you need to do is move them into your thing:

static mut GRAPH_BUILDER: Option&lt;(Vec&lt;u8&gt;, Vec&lt;u8&gt;)&gt; = None;

[...]

        GRAPH_BUILDER = Some((weights, xml));

Also you want to unwrap in an extern C function even less than in a Rust function. To my knowledge, at best that will summarily abort, at worst it's UB.

huangapple
  • 本文由 发表于 2023年4月4日 15:25:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/75926568.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定