summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteinar H. Gunderson <sesse@google.com>2024-04-08 11:37:45 +0200
committerWilfred Hughes <me@wilfred.me.uk>2024-04-28 15:46:23 -0700
commit4fb14788178245671d5b65c75a8019833e55e578 (patch)
treeeb88c08e288f2324524eeafa13ca50739d7b4d73
parent7353a7926f4a8b97ccb60571210e40a5fb257e33 (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.rs4
-rw-r--r--src/diff/graph.rs5
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>(