2016-03-26 12 views
1

バッファの固定プールからバッファを割り当て、割り当てを解除する単純なアロケータを作ろうとしています。単純なリソースで生涯エラーが発生するアロケータstruct

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); 
    } 
} 

私は単純に、次のエラーが発生したcell0を削除し、唯一の私の細胞プールに利用できるcell1を持っているときにエラーが

error: `cell0` does not live long enough 
    allocator.free_cell(&mut cell0); //populate allocator with another cell (why does this fail?) 

です:

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]ディレクティブを使用するライブラリを構築することです。したがって、正しく動作するにはアロケータインターフェイスが必要です。

+0

私は詳細を見ていませんが、これはリンクされたリストのようです。典型的な初心者の間違いは、親ノードがボックスで所有するのではなく、&または&mutを使って子ノードを借用することです。これはどんな助けですか? –

+0

これは役に立ちます。しかし、私はlibstdクレートを必要とせずにこれをしたいと思っています。だからボックスは、私がここで私のために働かないと信じています。 – hellcatv

+0

それは、何かが使われる前に、リストに借りられているすべてのものが生き残って、スタックに存在することができてうれしいです。だから私はここで実際に所有権を侵害しているわけではありません...デザインにはリスト構造の範囲外で同じ生涯を持つ細胞がたくさんあります。そうすれば、リスト構造は単にそれらを互いに参照させることができます。 starblueが指摘している問題は、スタック上の2つのアイテムが「同じ時刻」に生き残ることができないので、それ以降のアイテムは以前のアイテムを参照することができないということです。 – hellcatv

答えて

0

starblueのポインタのおかげで、私はアロケータとセルの寿命を強制的に構造体に置き、その構造体をスタックに置くことにしました。 最終的な結果はここにある:私は、複数の割り当てを行うときags.allocatorの二重の借入を避けるために、センチネル構造体を追加するために必要な

// 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) 
    } 
} 

。 Allocに格納されているセンチネルで

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 

私は関数が戻った後globを変更しないことを保証することができます。

2

問題は、常に同じ生涯'aを使用することです。これにより、cell0cell1の寿命が同じになることがあります。これは、最初に定義する必要があるため不可能です。エラーメッセージを注意深く読むと、最初のセルを定義しているステートメントを含めずに、2番目のセルの存続期間について不平を言うことがわかります。

これは生存期間を厳密に実装するバグや誤った機能であるのか、生涯型システムに固有のものであるのか分かりません(正式な定義はまだ見ていません)。

また、修正方法もわかりません。追加の生涯変数を導入することによって私が持っていたいくつかのサンプルコードで同様の問題を修正しましたが、あなたのコードではうまく動作しませんでした。

関連する問題