Skip to content

Commit 7a1e663

Browse files
committed
nanovdb python: harden mergeGrids for empty input and use gridData(n)
Addresses review feedback on PR #2219. Empty input: mergeGrids([]) — or a sequence of only-empty handles — produced totalGrids == 0 and called BufferT::create(0). For HostBuffer that yields a buffer whose data() is non-null over a zero-byte region, so the GridHandle(buffer&&) ctor then reads a full GridData header out of it (heap-overflow read; in practice an opaque "invalid host buffer" throw). Return an empty handle up front when there's nothing to merge. Per-grid source pointer: copy from h->gridData(n) — the authoritative start pointer that applies mMetaData[n].offset — instead of walking a raw data() pointer advanced by gridSize(n). The two are equivalent for the current tightly-packed layout (offsets are a running sum of grid sizes), but the accessor form doesn't bake in that assumption and drops the manual pointer arithmetic. Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
1 parent 88a4f90 commit 7a1e663

1 file changed

Lines changed: 11 additions & 3 deletions

File tree

nanovdb/nanovdb/python/PyGridHandle.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,18 +98,26 @@ template<typename BufferT> void defineGridHandleUtilities(nb::module_& m)
9898
}
9999
}
100100

101+
// Nothing to merge (empty sequence, or only empty handles): return an
102+
// empty handle. BufferT::create(0) is ill-defined — for HostBuffer it
103+
// yields a non-null data() over a zero-byte region, and the
104+
// GridHandle(buffer) ctor would then read a full GridData header out of
105+
// it (heap overflow / "invalid host buffer" throw).
106+
if (totalGrids == 0) return HandleT();
107+
101108
auto buffer = BufferT::create(totalSize);
102109
uint8_t* dst = static_cast<uint8_t*>(buffer.data());
103110
uint32_t writeIndex = 0;
104111
for (const HandleT* h : sources) {
105-
const uint8_t* src = static_cast<const uint8_t*>(h->data());
106112
for (uint32_t n = 0; n < h->gridCount(); ++n) {
113+
// gridData(n) is the authoritative per-grid start pointer (it
114+
// applies mMetaData[n].offset), so we don't assume the source
115+
// grids are laid out contiguously in the buffer.
107116
const uint64_t gs = h->gridSize(n);
108-
std::memcpy(dst, src, gs);
117+
std::memcpy(dst, h->gridData(n), gs);
109118
auto* gd = reinterpret_cast<nanovdb::GridData*>(dst);
110119
nanovdb::tools::updateGridCount(gd, writeIndex++, totalGrids);
111120
dst += gs;
112-
src += gs;
113121
}
114122
}
115123
return HandleT(std::move(buffer));

0 commit comments

Comments
 (0)