Skip to content

Commit dd001c8

Browse files
committed
Fix dangling pointer with Pathfinder._travel_p
Storing these CFFI pointers was a bad idea, it's better to drop them and then recreate them as they are needed.
1 parent 1864c16 commit dd001c8

File tree

2 files changed

+26
-9
lines changed

2 files changed

+26
-9
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ This project adheres to [Semantic Versioning](https://semver.org/) since version
66

77
## [Unreleased]
88

9+
### Fixed
10+
11+
- Fixed dangling pointer in `Pathfinder.clear` method.
12+
913
## [19.4.0] - 2025-08-06
1014

1115
### Changed

tcod/path.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,8 +1002,8 @@ def _resolve(self, pathfinder: Pathfinder) -> None:
10021002
_check(
10031003
lib.path_compute(
10041004
pathfinder._frontier_p,
1005-
pathfinder._distance_p,
1006-
pathfinder._travel_p,
1005+
_export(pathfinder._distance),
1006+
_export(pathfinder._travel),
10071007
len(rules),
10081008
rules,
10091009
pathfinder._heuristic_p,
@@ -1110,8 +1110,6 @@ def __init__(self, graph: CustomGraph | SimpleGraph) -> None:
11101110
self._frontier_p = ffi.gc(lib.TCOD_frontier_new(self._graph._ndim), lib.TCOD_frontier_delete)
11111111
self._distance = maxarray(self._graph._shape_c)
11121112
self._travel = _world_array(self._graph._shape_c)
1113-
self._distance_p = _export(self._distance)
1114-
self._travel_p = _export(self._travel)
11151113
self._heuristic: tuple[int, int, int, int, tuple[int, ...]] | None = None
11161114
self._heuristic_p: Any = ffi.NULL
11171115

@@ -1180,8 +1178,22 @@ def traversal(self) -> NDArray[Any]:
11801178
def clear(self) -> None:
11811179
"""Reset the pathfinder to its initial state.
11821180
1183-
This sets all values on the :any:`distance` array to their maximum
1184-
value.
1181+
This sets all values on the :any:`distance` array to their maximum value.
1182+
1183+
Example::
1184+
1185+
>>> import tcod.path
1186+
>>> graph = tcod.path.SimpleGraph(
1187+
... cost=np.ones((5, 5), np.int8), cardinal=2, diagonal=3,
1188+
... )
1189+
>>> pf = tcod.path.Pathfinder(graph)
1190+
>>> pf.add_root((0, 0))
1191+
>>> pf.path_to((2, 2)).tolist()
1192+
[[0, 0], [1, 1], [2, 2]]
1193+
>>> pf.clear() # Reset Pathfinder to its initial state
1194+
>>> pf.add_root((0, 2))
1195+
>>> pf.path_to((2, 2)).tolist()
1196+
[[0, 2], [1, 2], [2, 2]]
11851197
"""
11861198
self._distance[...] = np.iinfo(self._distance.dtype).max
11871199
self._travel = _world_array(self._graph._shape_c)
@@ -1237,7 +1249,7 @@ def rebuild_frontier(self) -> None:
12371249
"""
12381250
lib.TCOD_frontier_clear(self._frontier_p)
12391251
self._update_heuristic(None)
1240-
_check(lib.rebuild_frontier_from_distance(self._frontier_p, self._distance_p))
1252+
_check(lib.rebuild_frontier_from_distance(self._frontier_p, _export(self._distance)))
12411253

12421254
def resolve(self, goal: tuple[int, ...] | None = None) -> None:
12431255
"""Manually run the pathfinder algorithm.
@@ -1341,12 +1353,13 @@ def path_from(self, index: tuple[int, ...]) -> NDArray[np.intc]:
13411353
self.resolve(index)
13421354
if self._order == "F": # Convert to ij indexing order.
13431355
index = index[::-1]
1344-
length = _check(lib.get_travel_path(self._graph._ndim, self._travel_p, index, ffi.NULL))
1356+
_travel_p = _export(self._travel)
1357+
length = _check(lib.get_travel_path(self._graph._ndim, _travel_p, index, ffi.NULL))
13451358
path: np.ndarray[Any, np.dtype[np.intc]] = np.ndarray((length, self._graph._ndim), dtype=np.intc)
13461359
_check(
13471360
lib.get_travel_path(
13481361
self._graph._ndim,
1349-
self._travel_p,
1362+
_travel_p,
13501363
index,
13511364
ffi.from_buffer("int*", path),
13521365
)

0 commit comments

Comments
 (0)