首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用简单资源分配程序结构的生存期错误

使用简单资源分配程序结构的生存期错误
EN

Stack Overflow用户
提问于 2016-03-26 09:34:29
回答 2查看 73关注 0票数 1

我正在尝试做一个简单的分配器,它从一个固定的缓冲区池中分配和释放缓冲区。

代码语言:javascript
复制
struct AllocatedMemory<'a> {
    mem: &'a mut [u8],
    next: Option<&'a mut AllocatedMemory<'a>>,
}

struct Alloc<'a> {
    glob: Option<&'a mut AllocatedMemory<'a>>,
}

impl<'a> Alloc<'a> {
    fn alloc_cell(mut self: &mut Alloc<'a>) -> &mut AllocatedMemory<'a> {
        let rest: Option<&'a mut AllocatedMemory<'a>>;
        match self.glob {
            Some(ref mut root_cell) => {
                rest = std::mem::replace(&mut root_cell.next, None);
            }
            None => rest = None,
        }
        match std::mem::replace(&mut self.glob, rest) {
            Some(mut root_cell) => {
                return root_cell;
            }
            None => panic!("OOM"),
        }
    }

    fn free_cell(mut self: &mut Alloc<'a>, mut val: &'a mut AllocatedMemory<'a>) {
        match std::mem::replace(&mut self.glob, None) {
            Some(mut x) => {
                let discard = std::mem::replace(&mut val.next, Some(x));
                let rest: Option<&'a mut AllocatedMemory<'a>>;
            }
            None => {}
        }
        self.glob = Some(val);
    }
}

fn main() {
    let mut buffer0: [u8; 1024] = [0; 1024];
    let mut buffer1: [u8; 1024] = [0; 1024];
    {
        let mut cell1: AllocatedMemory = AllocatedMemory {
            mem: &mut buffer1[0..1024],
            next: None,
        };
        let mut cell0: AllocatedMemory = AllocatedMemory {
            mem: &mut buffer0[0..1024],
            next: None,
        };
        let mut allocator = Alloc { glob: None };
        allocator.free_cell(&mut cell1); //populate allocator with a cell
        allocator.free_cell(&mut cell0); //populate allocator with another cell (why does this fail?)

        let mut x = allocator.alloc_cell();
        allocator.free_cell(x);
        let mut y = allocator.alloc_cell();
        let mut z = allocator.alloc_cell();
        allocator.free_cell(y);
        allocator.free_cell(z);
    }
}

错误是

代码语言:javascript
复制
error: `cell0` does not live long enough
     allocator.free_cell(&mut cell0); //populate allocator with another cell (why does this fail?)

当我简单地删除cell0并使cell1只对我的单元格池可用时,就会发生以下错误:

代码语言:javascript
复制
error: allocator does not live long enough
         let mut x = allocator.alloc_cell();
                     ^~~~~~~~~
note: reference must be valid for the block suffix following statement 0 at 46:69...
                                                          next: None};
         let mut cell0 : AllocatedMemory = AllocatedMemory{mem: &mut buffer0[0..1024],
                                                          next: None};
         let mut allocator = Alloc {glob : None};
         allocator.free_cell(&mut cell1); //populate allocator with a cell
         //allocator.free_cell(&mut cell0); //populate allocator with another cell (why does this fail?)

note: ...but borrowed value is only valid for the block suffix following statement 2 at 49:48
         let mut allocator = Alloc {glob : None};
         allocator.free_cell(&mut cell1); //populate allocator with a cell
         //allocator.free_cell(&mut cell0); //populate allocator with another cell (why does this fail?)

         let mut x = allocator.alloc_cell();
         allocator.free_cell(x);
               ...
error: aborting due to previous error

是否有人对如何修复此代码有建议,以便它可以在空闲列表中编译并可能包含2+项?

我希望填充数组的引用列表,然后能够弹出它们--使用它们一段时间,并将已使用/完成的值返回给自由职业者。

这里的目的是构建一个使用#![nostd]指令的库,因此它需要一个分配器接口才能正常运行。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-03-27 06:26:28

多亏了starblue的指针,我决定强制分配程序和单元格的生命周期是相同的,方法是将它们放置到一个结构中,并将其放入堆栈中。最后的结果是:

代码语言:javascript
复制
// This code is placed in the public domain
struct AllocatedMemory<'a> {
   mem : &'a mut [u8],
   next : Option<&'a mut AllocatedMemory <'a> >,
}
struct Alloc<'a> {
  glob : Option<&'a mut AllocatedMemory <'a> >,
}

impl<'a> Alloc <'a> {
  fn alloc_cell(self : &mut Alloc<'a>) -> &'a mut AllocatedMemory<'a> {
      match self.glob {
        Some(ref mut glob_next) => {
             let rest : Option<&'a mut AllocatedMemory <'a> >;
             match glob_next.next {
                 Some(ref mut root_cell) => {
                    rest = std::mem::replace(&mut root_cell.next, None);
                 },
                 None => rest = None,
             }
             match std::mem::replace(&mut glob_next.next, rest) {
                Some(mut root_cell) =>
                {
                 return root_cell;
                },
                None => panic!("OOM"),
             }
        },
        None => panic!("Allocator not initialized"),
     }
  }
  fn free_cell(self : &mut Alloc<'a>,
               mut val : & 'a mut AllocatedMemory<'a>) {
      match self.glob {
          Some(ref mut glob_next) => {
              match std::mem::replace(&mut glob_next.next ,None) {
                  Some(mut x) => {
                      let _discard = std::mem::replace(&mut val.next, Some(x));
                  },
                  None => {},
              }
              glob_next.next = Some(val);
           },
           None => panic!("Allocator not initialized"),
      }
  }
}
struct AllocatorGlobalState<'a>{
  cell1 : AllocatedMemory<'a>,
  cell0 : AllocatedMemory<'a>,
  sentinel : AllocatedMemory<'a>,
  allocator :Alloc<'a>,

}
fn main() {
  let mut buffer0 : [u8; 1024] = [0; 1024];
  let mut buffer1 : [u8; 1024] = [0; 1024];
  let mut sentinel_buffer : [u8; 1] = [0];
  let mut ags : AllocatorGlobalState = AllocatorGlobalState {
  cell1 : AllocatedMemory{mem: &mut buffer1[0..1024],
                          next: None},
  cell0 : AllocatedMemory{mem: &mut buffer0[0..1024],
                          next: None},
  sentinel : AllocatedMemory{mem: &mut sentinel_buffer[0..1], next: None},
  allocator : Alloc {glob : None},
  };
  ags.allocator.glob = Some(&mut ags.sentinel);
  ags.allocator.free_cell(&mut ags.cell1);
  ags.allocator.free_cell(&mut ags.cell0);
  {
  let mut x = ags.allocator.alloc_cell();
  x.mem[0] = 4;
  let mut y = ags.allocator.alloc_cell();
  y.mem[0] = 4;
  ags.allocator.free_cell(y);
  let mut z = ags.allocator.alloc_cell();
  z.mem[0] = 8;
  //y.mem[0] = 5; // <-- this is an error (use after free)
  }
}

我需要添加哨兵结构,以避免在执行多个分配时重复借用ags.allocator。

代码语言:javascript
复制
cell.rs:65:19: 65:32 help: run `rustc --explain E0499` to see a detailed explanation
cell.rs:62:19: 62:32 note: previous borrow of `ags.allocator` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `ags.allocator` until the borrow ends

将哨兵存储在Alloc中后,我可以保证在函数返回后永远不会修改glob

票数 0
EN

Stack Overflow用户

发布于 2016-03-26 14:38:59

问题是,您总是使用相同的生存期'a。这迫使cell0cell1具有相同的生存期,这是不可能的,因为必须先定义一个。如果仔细阅读错误消息,可以看到它抱怨第二个单元格的生存期,不包括定义第一个单元格的语句。

我不知道这是一个错误或错误,它严格地实现了生命周期,或者它是否是生命类型系统中固有的(我还没有看到一个正式的定义)。

我也不知道怎么解决它。通过引入额外的生存期变量,我在一些示例代码中修正了类似的问题,但我无法使它对您的代码有效。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36233735

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档