Fixed writing out of bounds when the whole buffer is copied

master
Marc Gilleron 2021-10-01 19:31:30 +01:00
parent f5ecd42057
commit 228e41b71e
4 changed files with 68 additions and 25 deletions

View File

@ -44,6 +44,8 @@ Ongoing development - `master`
- Fixes
- `VoxelGeneratorGraph`: changes to node properties are now saved properly
- `VoxelBuffer`: `copy_voxel_metadata_in_area` was checking the source box incorrectly
- `VoxelBuffer`: multiple calls to `create()` with different sizes could lead to heap corruption if a channel was not uniform
- `VoxelBuffer`: `copy_channel_from_area` could lead to heap corruption if the source and destination had the same size and were copied entirely
- `VoxelMesherTransvoxel`: no longer crashes when the input buffer is not cubic
- `VoxelLodTerrain`: fixed errors and crashes when editing voxels near loading borders
- `VoxelLodTerrain`: fixed crash occurring after a few edits when LOD count is set to 1

View File

@ -26,7 +26,8 @@ void copy_3d_region_zxy(
if (area_size == src_size && area_size == dst_size) {
// Copy everything
memcpy(dst.data(), src.data(), dst.size() * item_size);
ERR_FAIL_COND(dst.size() != src.size());
memcpy(dst.data(), src.data(), dst.size());
} else {
// Copy area row by row:
@ -40,6 +41,10 @@ void copy_3d_region_zxy(
unsigned int src_ri = Vector3i(src_min + pos).get_zxy_index(src_size) * item_size;
unsigned int dst_ri = Vector3i(dst_min + pos).get_zxy_index(dst_size) * item_size;
for (; pos.x < area_size.x; ++pos.x) {
#ifdef DEBUG_ENABLED
ERR_FAIL_COND(dst_ri >= dst.size());
ERR_FAIL_COND(dst.size() - dst_ri < area_size.y * item_size);
#endif
// TODO Cast src and dst to `restrict` so the optimizer can assume adresses don't overlap,
// which might allow to write as a for loop (which may compile as a `memcpy`)?
memcpy(&dst[dst_ri], &src[src_ri], area_size.y * item_size);

View File

@ -238,24 +238,42 @@ void test_encode_weights_packed_u16() {
}
void test_copy_3d_region_zxy() {
std::vector<uint16_t> src;
std::vector<uint16_t> dst;
const Vector3i src_size(8, 8, 8);
const Vector3i dst_size(3, 4, 5);
src.resize(src_size.volume(), 0);
dst.resize(src_size.volume(), 0);
for (unsigned int i = 0; i < src.size(); ++i) {
src[i] = i;
}
struct L {
static void compare(
Span<const uint16_t> srcs, Vector3i src_size, Vector3i src_min, Vector3i src_max,
Span<const uint16_t> dsts, Vector3i dst_size, Vector3i dst_min) {
Vector3i pos;
for (pos.z = src_min.z; pos.z < src_max.z; ++pos.z) {
for (pos.x = src_min.x; pos.x < src_max.x; ++pos.x) {
for (pos.y = src_min.y; pos.y < src_max.y; ++pos.y) {
const uint16_t srcv = srcs[pos.get_zxy_index(src_size)];
const uint16_t dstv = dsts[(pos - src_min + dst_min).get_zxy_index(dst_size)];
ERR_FAIL_COND(srcv != dstv);
}
}
}
}
};
// Sub-region
{
std::vector<uint16_t> src;
std::vector<uint16_t> dst;
const Vector3i src_size(8, 8, 8);
const Vector3i dst_size(3, 4, 5);
src.resize(src_size.volume(), 0);
dst.resize(src_size.volume(), 0);
for (unsigned int i = 0; i < src.size(); ++i) {
src[i] = i;
}
Span<const uint16_t> srcs = to_span_const(src);
Span<uint16_t> dsts = to_span(dst);
const Vector3i dst_min(0, 0, 0);
const Vector3i src_min(2, 1, 0);
const Vector3i src_max(5, 4, 3);
copy_3d_region_zxy(dsts, dst_size, dst_min, srcs, src_size, src_min, src_max);
Span<const uint16_t> srcs = to_span_const(src);
Span<uint16_t> dsts = to_span(dst);
const Vector3i dst_min(0, 0, 0);
const Vector3i src_min(2, 1, 0);
const Vector3i src_max(5, 4, 3);
copy_3d_region_zxy(dsts, dst_size, dst_min, srcs, src_size, src_min, src_max);
/*for (pos.y = src_min.y; pos.y < src_max.y; ++pos.y) {
/*for (pos.y = src_min.y; pos.y < src_max.y; ++pos.y) {
String s;
for (pos.x = src_min.x; pos.x < src_max.x; ++pos.x) {
const uint16_t v = srcs[pos.get_zxy_index(src_size)];
@ -287,15 +305,28 @@ void test_copy_3d_region_zxy() {
print_line(s);
}*/
Vector3i pos;
for (pos.z = src_min.z; pos.z < src_max.z; ++pos.z) {
for (pos.x = src_min.x; pos.x < src_max.x; ++pos.x) {
for (pos.y = src_min.y; pos.y < src_max.y; ++pos.y) {
const uint16_t srcv = srcs[pos.get_zxy_index(src_size)];
const uint16_t dstv = dsts[(pos - src_min + dst_min).get_zxy_index(dst_size)];
ERR_FAIL_COND(srcv != dstv);
}
L::compare(srcs, src_size, src_min, src_max, to_span_const(dsts), dst_size, dst_min);
}
// Same size, full region
{
std::vector<uint16_t> src;
std::vector<uint16_t> dst;
const Vector3i src_size(3, 4, 5);
const Vector3i dst_size(3, 4, 5);
src.resize(src_size.volume(), 0);
dst.resize(src_size.volume(), 0);
for (unsigned int i = 0; i < src.size(); ++i) {
src[i] = i;
}
Span<const uint16_t> srcs = to_span_const(src);
Span<uint16_t> dsts = to_span(dst);
const Vector3i dst_min(0, 0, 0);
const Vector3i src_min(0, 0, 0);
const Vector3i src_max = src_max;
copy_3d_region_zxy(dsts, dst_size, dst_min, srcs, src_size, src_min, src_max);
L::compare(srcs, src_size, src_min, src_max, to_span_const(dsts), dst_size, dst_min);
}
}

View File

@ -150,4 +150,9 @@ Span<const T> to_span_const(const FixedArray<T, N> &a) {
return Span<const T>(a.data(), 0, a.size());
}
template <typename T>
Span<const T> to_span_const(const Span<T> &a) {
return Span<const T>(a.data(), 0, a.size());
}
#endif // SPAN_H