Skip to content

lib/raster3d: allocate no-cache block tile in the map's internal type - #7952

Merged
echoix merged 1 commit into
OSGeo:mainfrom
YannChemin:raster3d-getblock-nocache-tiletype
Sep 30, 2026
Merged

echoix merged 1 commit into
OSGeo:mainfrom
YannChemin:raster3d-getblock-nocache-tiletype

Conversation

@YannChemin

Copy link
Copy Markdown
Contributor

Problem

Rast3d_get_block_nocache() (used by Rast3d_get_block() whenever a map is opened with RASTER3D_NO_CACHE) allocates its scratch tile in the requested cell type:

tile = Rast3d_alloc_tiles_type(map, 1, type);

but fills it with Rast3d_read_tile(map, tileIndex, tile, map->typeIntern), i.e. in the map's internal type, and Rast3d_copy_values() then reads it as map->typeIntern too. Reading a DCELL 3D raster as FCELL through the fast no-cache path therefore writes a double-sized tile into a float-sized buffer: a heap overflow. glibc aborts with double free or corruption (!prev) or malloc(): corrupted top size.

This was found while streaming hyperspectral cubes band-block by band-block with Rast3d_get_block(..., FCELL_TYPE) on a map produced by r.to.rast3 from DCELL rasters.

Fix

Allocate the scratch tile in map->typeIntern. The conversion to the requested type already happens in Rast3d_copy_values(), so nothing else changes.

Tests

Two cases added to the existing put/get unit (test.raster3d.lib unit=putget), which lib/raster3d/testsuite/raster3d_lib_test.py::test_putget already runs:

  • a DCELL map read as FCELL through Rast3d_get_block() without cache;
  • an FCELL map read as DCELL through the same path.

Each checks every cell value.

Result of lib/raster3d/testsuite/raster3d_lib_test.py:

libgrass_g3d Result
current main FAIL: test_putget, process aborts with double free or corruption (!prev)
this PR Ran 3 tests ... OK

clang-format 22.1.5 (the pre-commit pin) reports no changes.

AI disclosure

The bug was diagnosed and this patch and its tests were written with the help of an AI coding assistant (Claude Code); they were reviewed, run and verified as described above.

🤖 Generated with Claude Code

Rast3d_get_block_nocache() allocated its scratch tile in the requested
cell type but filled it with Rast3d_read_tile() in the map's internal
type. Reading a DCELL map as FCELL without a tile cache therefore
overflowed the heap buffer (glibc aborts with "double free or
corruption" or "malloc(): corrupted top size").

Allocate the tile in map->typeIntern; the conversion to the requested
type already happens in Rast3d_copy_values(). Add unit tests reading a
DCELL map as FCELL and an FCELL map as DCELL through the no-cache path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@echoix
echoix merged commit 0d3ba70 into OSGeo:main Sep 30, 2026
26 of 27 checks passed
@github-actions github-actions Bot added this to the 8.6.0 milestone Sep 30, 2026
@YannChemin
YannChemin deleted the raster3d-getblock-nocache-tiletype branch October 19, 2026 10:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C Related code is in C libraries raster3d tests Related to Test Suite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants