diff options
author | Steinar H. Gunderson <sesse@google.com> | 2024-04-08 11:37:45 +0200 |
---|---|---|
committer | Wilfred Hughes <me@wilfred.me.uk> | 2024-04-28 15:46:23 -0700 |
commit | 4fb14788178245671d5b65c75a8019833e55e578 (patch) | |
tree | eb88c08e288f2324524eeafa13ca50739d7b4d73 | |
parent | 7353a7926f4a8b97ccb60571210e40a5fb257e33 (diff) |
Fix memory leak in neighbours array.
Vertex is allocated on the arena, so it is never dropped;
then it cannot contain a Vec allocated on the regular heap
without leaking memory. Replace the Vec with a slice allocated
on the arena, which seems to fix most of the leaks. (Some may
remain; I haven't checked fully.) It should also be slightly
more memory-efficient.
It's not clear that we actually need the RefCell instead of
just putting Option directly into the structure, but I've
let it stay.
This issue was probably introduced in a71d6118cf52.
-rw-r--r-- | src/diff/dijkstra.rs | 4 | ||||
-rw-r--r-- | src/diff/graph.rs | 5 |
2 files changed, 5 insertions, 4 deletions
diff --git a/src/diff/dijkstra.rs b/src/diff/dijkstra.rs index ecbac9626..d9f1ba7af 100644 --- a/src/diff/dijkstra.rs +++ b/src/diff/dijkstra.rs @@ -42,7 +42,7 @@ fn shortest_vertex_path<'s, 'b>( } set_neighbours(current, vertex_arena, &mut seen); - for neighbour in current.neighbours.borrow().as_ref().unwrap() { + for neighbour in *current.neighbours.borrow().as_ref().unwrap() { let (edge, next) = neighbour; let distance_to_next = distance + edge.cost(); @@ -128,7 +128,7 @@ fn edge_between<'s, 'b>(before: &Vertex<'s, 'b>, after: &Vertex<'s, 'b>) -> Edge let mut shortest_edge: Option<Edge> = None; if let Some(neighbours) = &*before.neighbours.borrow() { - for neighbour in neighbours { + for neighbour in *neighbours { let (edge, next) = *neighbour; // If there are multiple edges that can take us to `next`, // prefer the shortest. diff --git a/src/diff/graph.rs b/src/diff/graph.rs index 250b747fb..db1b4657e 100644 --- a/src/diff/graph.rs +++ b/src/diff/graph.rs @@ -51,7 +51,7 @@ use crate::{ /// ``` #[derive(Debug, Clone)] pub(crate) struct Vertex<'s, 'b> { - pub(crate) neighbours: RefCell<Option<Vec<(Edge, &'b Vertex<'s, 'b>)>>>, + pub(crate) neighbours: RefCell<Option<&'b [(Edge, &'b Vertex<'s, 'b>)]>>, pub(crate) predecessor: Cell<Option<(u32, &'b Vertex<'s, 'b>)>>, // TODO: experiment with storing SyntaxId only, and have a HashMap // from SyntaxId to &Syntax. @@ -773,7 +773,8 @@ pub(crate) fn set_neighbours<'s, 'b>( "Must always find some next steps if node is not the end" ); - v.neighbours.replace(Some(neighbours)); + v.neighbours + .replace(Some(alloc.alloc_slice_copy(neighbours.as_slice()))); } pub(crate) fn populate_change_map<'s, 'b>( |