From 357c7a525d13376f8032a040570f523d7f82949f Mon Sep 17 00:00:00 2001 From: "Werner, Stefan" Date: Mon, 6 Jul 2026 16:16:15 +0200 Subject: [PATCH 1/6] Clamp Morton branching factor and add regression test Clamp BVHBuilderMorton settings to MAX_BRANCHING_FACTOR when an oversized maxBranchingFactor is provided via RTCBuildArguments.\n\nAdd an integration test that exercises rtcBuildBVH with RTC_BUILD_QUALITY_LOW and maxBranchingFactor=64 to verify the Morton build path returns a valid root. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- kernels/builders/bvh_builder_morton.h | 5 + .../integration/test_embree_release/test.cpp | 100 ++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/kernels/builders/bvh_builder_morton.h b/kernels/builders/bvh_builder_morton.h index 87d4786810..d05031c0a2 100644 --- a/kernels/builders/bvh_builder_morton.h +++ b/kernels/builders/bvh_builder_morton.h @@ -32,12 +32,17 @@ namespace embree if (RTC_BUILD_ARGUMENTS_HAS(settings,minLeafSize )) minLeafSize = settings.minLeafSize; if (RTC_BUILD_ARGUMENTS_HAS(settings,maxLeafSize )) maxLeafSize = settings.maxLeafSize; + if (branchingFactor > MAX_BRANCHING_FACTOR) + branchingFactor = MAX_BRANCHING_FACTOR; + minLeafSize = min(minLeafSize,maxLeafSize); } Settings (size_t branchingFactor, size_t maxDepth, size_t minLeafSize, size_t maxLeafSize, size_t singleThreadThreshold) : branchingFactor(branchingFactor), maxDepth(maxDepth), minLeafSize(minLeafSize), maxLeafSize(maxLeafSize), singleThreadThreshold(singleThreadThreshold) { + if (branchingFactor > MAX_BRANCHING_FACTOR) + branchingFactor = MAX_BRANCHING_FACTOR; minLeafSize = min(minLeafSize,maxLeafSize); } diff --git a/tests/integration/test_embree_release/test.cpp b/tests/integration/test_embree_release/test.cpp index 3585e5c3a2..e729ce663d 100644 --- a/tests/integration/test_embree_release/test.cpp +++ b/tests/integration/test_embree_release/test.cpp @@ -4,10 +4,13 @@ #include #include +#include #include #include +#include #include +#include struct Hit @@ -18,6 +21,56 @@ struct Hit float tfar = std::numeric_limits::infinity(); }; +struct BuildTestNodeHeader +{ + unsigned int childCount; +}; + +static bool buildProgress(void* /*userPtr*/, double /*f*/) +{ + return true; +} + +static void* createNode(RTCThreadLocalAllocator alloc, unsigned int childCount, void* /*userPtr*/) +{ + const size_t bytes = + sizeof(BuildTestNodeHeader) + + sizeof(void*) * childCount + + sizeof(RTCBounds) * childCount; + + char* p = (char*) rtcThreadLocalAlloc(alloc, bytes, 16); + std::memset(p, 0, bytes); + ((BuildTestNodeHeader*)p)->childCount = childCount; + return p; +} + +static void setNodeChildren(void* nodePtr, void** children, unsigned int childCount, void* /*userPtr*/) +{ + BuildTestNodeHeader* h = (BuildTestNodeHeader*) nodePtr; + void** out = (void**) (h + 1); + for (unsigned int i = 0; i < childCount; ++i) out[i] = children[i]; +} + +static void setNodeBounds(void* nodePtr, const RTCBounds** bounds, unsigned int childCount, void* /*userPtr*/) +{ + BuildTestNodeHeader* h = (BuildTestNodeHeader*) nodePtr; + void** childBase = (void**) (h + 1); + RTCBounds* out = (RTCBounds*) (childBase + h->childCount); + for (unsigned int i = 0; i < childCount; ++i) out[i] = *bounds[i]; +} + +static void* createLeaf(RTCThreadLocalAllocator alloc, + const RTCBuildPrimitive* prims, + size_t primCount, + void* /*userPtr*/) +{ + const size_t bytes = sizeof(size_t) + primCount * sizeof(RTCBuildPrimitive); + char* p = (char*) rtcThreadLocalAlloc(alloc, bytes, 16); + *((size_t*)p) = primCount; + std::memcpy(p + sizeof(size_t), prims, primCount * sizeof(RTCBuildPrimitive)); + return p; +} + inline Hit castRay(RTCScene scene, float ox, float oy, float oz, float dx, float dy, float dz) @@ -106,3 +159,50 @@ TEST_CASE("Minimal test", "[minimal]") REQUIRE(true); } +TEST_CASE("Morton builder clamps oversized branching factor", "[bvh-builder]") +{ + RTCDevice device = rtcNewDevice(nullptr); + RTCBVH bvh = rtcNewBVH(device); + + const size_t primitiveCount = 1024; + std::vector prims(primitiveCount); + for (size_t i = 0; i < primitiveCount; ++i) + { + const float x = float(i % 32); + const float y = float((i / 32) % 32); + + RTCBuildPrimitive p{}; + p.lower_x = x * 2.0f; + p.lower_y = y * 2.0f; + p.lower_z = 0.0f; + p.upper_x = p.lower_x + 0.5f; + p.upper_y = p.lower_y + 0.5f; + p.upper_z = 0.5f; + p.geomID = 0; + p.primID = (unsigned int)i; + prims[i] = p; + } + + RTCBuildArguments args = rtcDefaultBuildArguments(); + args.byteSize = sizeof(args); + args.buildQuality = RTC_BUILD_QUALITY_LOW; + args.maxBranchingFactor = 64; + args.maxDepth = 1024; + args.minLeafSize = 1; + args.maxLeafSize = 1; + args.bvh = bvh; + args.primitives = prims.data(); + args.primitiveCount = prims.size(); + args.primitiveArrayCapacity = prims.size(); + args.createNode = createNode; + args.setNodeChildren = setNodeChildren; + args.setNodeBounds = setNodeBounds; + args.createLeaf = createLeaf; + args.buildProgress = buildProgress; + + void* root = rtcBuildBVH(&args); + REQUIRE(root != nullptr); + + rtcReleaseBVH(bvh); + rtcReleaseDevice(device); +} From 55ca27c5fa93ce3c73ba680e8d3256e502c76354 Mon Sep 17 00:00:00 2001 From: "Werner, Stefan" Date: Thu, 9 Jul 2026 12:26:08 +0200 Subject: [PATCH 2/6] Created regression test for morton builder clamp --- tests/CMakeLists.txt | 2 + .../integration/test_embree_release/test.cpp | 101 ------------- tests/regression/CMakeLists.txt | 10 ++ .../morton_builder_clamp_regression.cpp | 134 ++++++++++++++++++ 4 files changed, 146 insertions(+), 101 deletions(-) create mode 100644 tests/regression/CMakeLists.txt create mode 100644 tests/regression/morton_builder_clamp_regression.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e2828acb07..54004a79a7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -39,6 +39,8 @@ FOREACH(xml ${PRIMITIVE_TESTS}) ENDFOREACH() ENDFOREACH() + ADD_SUBDIRECTORY(regression) + IF (EMBREE_TESTING_INSTALL_TESTS) # test resources diff --git a/tests/integration/test_embree_release/test.cpp b/tests/integration/test_embree_release/test.cpp index e729ce663d..ea5520676b 100644 --- a/tests/integration/test_embree_release/test.cpp +++ b/tests/integration/test_embree_release/test.cpp @@ -4,13 +4,10 @@ #include #include -#include #include #include -#include #include -#include struct Hit @@ -21,56 +18,6 @@ struct Hit float tfar = std::numeric_limits::infinity(); }; -struct BuildTestNodeHeader -{ - unsigned int childCount; -}; - -static bool buildProgress(void* /*userPtr*/, double /*f*/) -{ - return true; -} - -static void* createNode(RTCThreadLocalAllocator alloc, unsigned int childCount, void* /*userPtr*/) -{ - const size_t bytes = - sizeof(BuildTestNodeHeader) + - sizeof(void*) * childCount + - sizeof(RTCBounds) * childCount; - - char* p = (char*) rtcThreadLocalAlloc(alloc, bytes, 16); - std::memset(p, 0, bytes); - ((BuildTestNodeHeader*)p)->childCount = childCount; - return p; -} - -static void setNodeChildren(void* nodePtr, void** children, unsigned int childCount, void* /*userPtr*/) -{ - BuildTestNodeHeader* h = (BuildTestNodeHeader*) nodePtr; - void** out = (void**) (h + 1); - for (unsigned int i = 0; i < childCount; ++i) out[i] = children[i]; -} - -static void setNodeBounds(void* nodePtr, const RTCBounds** bounds, unsigned int childCount, void* /*userPtr*/) -{ - BuildTestNodeHeader* h = (BuildTestNodeHeader*) nodePtr; - void** childBase = (void**) (h + 1); - RTCBounds* out = (RTCBounds*) (childBase + h->childCount); - for (unsigned int i = 0; i < childCount; ++i) out[i] = *bounds[i]; -} - -static void* createLeaf(RTCThreadLocalAllocator alloc, - const RTCBuildPrimitive* prims, - size_t primCount, - void* /*userPtr*/) -{ - const size_t bytes = sizeof(size_t) + primCount * sizeof(RTCBuildPrimitive); - char* p = (char*) rtcThreadLocalAlloc(alloc, bytes, 16); - *((size_t*)p) = primCount; - std::memcpy(p + sizeof(size_t), prims, primCount * sizeof(RTCBuildPrimitive)); - return p; -} - inline Hit castRay(RTCScene scene, float ox, float oy, float oz, float dx, float dy, float dz) @@ -158,51 +105,3 @@ TEST_CASE("Minimal test", "[minimal]") REQUIRE(true); } - -TEST_CASE("Morton builder clamps oversized branching factor", "[bvh-builder]") -{ - RTCDevice device = rtcNewDevice(nullptr); - RTCBVH bvh = rtcNewBVH(device); - - const size_t primitiveCount = 1024; - std::vector prims(primitiveCount); - for (size_t i = 0; i < primitiveCount; ++i) - { - const float x = float(i % 32); - const float y = float((i / 32) % 32); - - RTCBuildPrimitive p{}; - p.lower_x = x * 2.0f; - p.lower_y = y * 2.0f; - p.lower_z = 0.0f; - p.upper_x = p.lower_x + 0.5f; - p.upper_y = p.lower_y + 0.5f; - p.upper_z = 0.5f; - p.geomID = 0; - p.primID = (unsigned int)i; - prims[i] = p; - } - - RTCBuildArguments args = rtcDefaultBuildArguments(); - args.byteSize = sizeof(args); - args.buildQuality = RTC_BUILD_QUALITY_LOW; - args.maxBranchingFactor = 64; - args.maxDepth = 1024; - args.minLeafSize = 1; - args.maxLeafSize = 1; - args.bvh = bvh; - args.primitives = prims.data(); - args.primitiveCount = prims.size(); - args.primitiveArrayCapacity = prims.size(); - args.createNode = createNode; - args.setNodeChildren = setNodeChildren; - args.setNodeBounds = setNodeBounds; - args.createLeaf = createLeaf; - args.buildProgress = buildProgress; - - void* root = rtcBuildBVH(&args); - REQUIRE(root != nullptr); - - rtcReleaseBVH(bvh); - rtcReleaseDevice(device); -} diff --git a/tests/regression/CMakeLists.txt b/tests/regression/CMakeLists.txt new file mode 100644 index 0000000000..80b0a23e80 --- /dev/null +++ b/tests/regression/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright 2009-2021 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +add_executable(embree_regression_morton_builder_clamp morton_builder_clamp_regression.cpp) +target_link_libraries(embree_regression_morton_builder_clamp PRIVATE embree) +set_property(TARGET embree_regression_morton_builder_clamp PROPERTY FOLDER tests/regression) + +if (BUILD_TESTING) + add_test(NAME regression_morton_builder_clamp COMMAND embree_regression_morton_builder_clamp) +endif() diff --git a/tests/regression/morton_builder_clamp_regression.cpp b/tests/regression/morton_builder_clamp_regression.cpp new file mode 100644 index 0000000000..2c1ebac40a --- /dev/null +++ b/tests/regression/morton_builder_clamp_regression.cpp @@ -0,0 +1,134 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include +#include + +#include +#include +#include +#include + +struct BuildTestNodeHeader +{ + unsigned int childCount; +}; + +static bool buildProgress(void* /*userPtr*/, double /*f*/) +{ + return true; +} + +static void* createNode(RTCThreadLocalAllocator alloc, unsigned int childCount, void* /*userPtr*/) +{ + const size_t bytes = + sizeof(BuildTestNodeHeader) + + sizeof(void*) * childCount + + sizeof(RTCBounds) * childCount; + + char* p = (char*) rtcThreadLocalAlloc(alloc, bytes, 16); + std::memset(p, 0, bytes); + ((BuildTestNodeHeader*)p)->childCount = childCount; + return p; +} + +static void setNodeChildren(void* nodePtr, void** children, unsigned int childCount, void* /*userPtr*/) +{ + BuildTestNodeHeader* h = (BuildTestNodeHeader*) nodePtr; + void** out = (void**) (h + 1); + for (unsigned int i = 0; i < childCount; ++i) out[i] = children[i]; +} + +static void setNodeBounds(void* nodePtr, const RTCBounds** bounds, unsigned int childCount, void* /*userPtr*/) +{ + BuildTestNodeHeader* h = (BuildTestNodeHeader*) nodePtr; + void** childBase = (void**) (h + 1); + RTCBounds* out = (RTCBounds*) (childBase + h->childCount); + for (unsigned int i = 0; i < childCount; ++i) out[i] = *bounds[i]; +} + +static void* createLeaf(RTCThreadLocalAllocator alloc, + const RTCBuildPrimitive* prims, + size_t primCount, + void* /*userPtr*/) +{ + const size_t bytes = sizeof(size_t) + primCount * sizeof(RTCBuildPrimitive); + char* p = (char*) rtcThreadLocalAlloc(alloc, bytes, 16); + *((size_t*)p) = primCount; + std::memcpy(p + sizeof(size_t), prims, primCount * sizeof(RTCBuildPrimitive)); + return p; +} + +static std::vector makeGridPrimitives(size_t primitiveCount) +{ + std::vector prims(primitiveCount); + for (size_t i = 0; i < primitiveCount; ++i) + { + const float x = float(i % 32); + const float y = float((i / 32) % 32); + + RTCBuildPrimitive p{}; + p.lower_x = x * 2.0f; + p.lower_y = y * 2.0f; + p.lower_z = 0.0f; + p.upper_x = p.lower_x + 0.5f; + p.upper_y = p.lower_y + 0.5f; + p.upper_z = 0.5f; + p.geomID = 0; + p.primID = (unsigned int)i; + prims[i] = p; + } + return prims; +} + +static bool runCase(unsigned int maxBranchingFactor) +{ + RTCDevice device = rtcNewDevice(nullptr); + if (device == nullptr) + return false; + + RTCBVH bvh = rtcNewBVH(device); + if (bvh == nullptr) + { + rtcReleaseDevice(device); + return false; + } + + std::vector prims = makeGridPrimitives(1024); + + RTCBuildArguments args = rtcDefaultBuildArguments(); + args.byteSize = sizeof(args); + args.buildQuality = RTC_BUILD_QUALITY_LOW; + args.maxBranchingFactor = maxBranchingFactor; + args.maxDepth = 1024; + args.minLeafSize = 1; + args.maxLeafSize = 1; + args.bvh = bvh; + args.primitives = prims.data(); + args.primitiveCount = prims.size(); + args.primitiveArrayCapacity = prims.size(); + args.createNode = createNode; + args.setNodeChildren = setNodeChildren; + args.setNodeBounds = setNodeBounds; + args.createLeaf = createLeaf; + args.buildProgress = buildProgress; + + void* root = rtcBuildBVH(&args); + + rtcReleaseBVH(bvh); + rtcReleaseDevice(device); + return root != nullptr; +} + +int main() +{ + bool okOversized = runCase(64); + bool okExtreme = runCase(std::numeric_limits::max()); + + if (!okOversized) + std::cerr << "Morton clamp regression failed for maxBranchingFactor=64\n"; + if (!okExtreme) + std::cerr << "Morton clamp regression failed for maxBranchingFactor=UINT_MAX\n"; + + return (okOversized && okExtreme) ? 0 : 1; +} From 9d504af21e6bcc939b5d9981e52c0d2ebf722855 Mon Sep 17 00:00:00 2001 From: "Werner, Stefan" Date: Wed, 15 Jul 2026 23:26:29 +0200 Subject: [PATCH 3/6] Fixed regression test --- .../morton_builder_clamp_regression.cpp | 79 +++++++++++-------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/tests/regression/morton_builder_clamp_regression.cpp b/tests/regression/morton_builder_clamp_regression.cpp index 2c1ebac40a..f4d4705d49 100644 --- a/tests/regression/morton_builder_clamp_regression.cpp +++ b/tests/regression/morton_builder_clamp_regression.cpp @@ -1,62 +1,74 @@ -// Copyright 2009-2021 Intel Corporation +// Copyright 2026 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #include #include +#include #include #include #include #include -struct BuildTestNodeHeader +constexpr unsigned int max_branching_factor = 8; + +struct Node { - unsigned int childCount; + Node() + { + for (unsigned int i = 0; i < max_branching_factor; ++i) + children[i] = nullptr; + } + virtual ~Node() = default; + Node *children[max_branching_factor]; }; -static bool buildProgress(void* /*userPtr*/, double /*f*/) +static bool buildProgress(void * /*userPtr*/, double /*f*/) +{ + return true; +} + +bool memoryMonitor(void * /*userPtr*/, ssize_t /*bytes*/, bool /*post*/) { return true; } -static void* createNode(RTCThreadLocalAllocator alloc, unsigned int childCount, void* /*userPtr*/) +static void *createNode(RTCThreadLocalAllocator alloc, unsigned int childCount, void * /*userPtr*/) { - const size_t bytes = - sizeof(BuildTestNodeHeader) + - sizeof(void*) * childCount + - sizeof(RTCBounds) * childCount; - - char* p = (char*) rtcThreadLocalAlloc(alloc, bytes, 16); - std::memset(p, 0, bytes); - ((BuildTestNodeHeader*)p)->childCount = childCount; - return p; + assert(childCount <= max_branching_factor); + if (childCount > max_branching_factor) + return nullptr; + + Node *node = (Node *)rtcThreadLocalAlloc(alloc, sizeof(Node), 16); + new (node) Node(); + return node; } -static void setNodeChildren(void* nodePtr, void** children, unsigned int childCount, void* /*userPtr*/) +static void setNodeChildren(void *nodePtr, void **children, unsigned int childCount, void * /*userPtr*/) { - BuildTestNodeHeader* h = (BuildTestNodeHeader*) nodePtr; - void** out = (void**) (h + 1); - for (unsigned int i = 0; i < childCount; ++i) out[i] = children[i]; + assert(childCount <= max_branching_factor); + if (childCount > max_branching_factor) + return; + Node *node = (Node *)nodePtr; + for (unsigned int i = 0; i < childCount; ++i) + node->children[i] = (Node *)children[i]; } -static void setNodeBounds(void* nodePtr, const RTCBounds** bounds, unsigned int childCount, void* /*userPtr*/) +static void setNodeBounds(void *nodePtr, const RTCBounds **bounds, unsigned int childCount, void * /*userPtr*/) { - BuildTestNodeHeader* h = (BuildTestNodeHeader*) nodePtr; - void** childBase = (void**) (h + 1); - RTCBounds* out = (RTCBounds*) (childBase + h->childCount); - for (unsigned int i = 0; i < childCount; ++i) out[i] = *bounds[i]; + assert(childCount <= max_branching_factor); + /* deliberately empty in regression test */ } -static void* createLeaf(RTCThreadLocalAllocator alloc, - const RTCBuildPrimitive* prims, +static void *createLeaf(RTCThreadLocalAllocator alloc, + const RTCBuildPrimitive *prims, size_t primCount, - void* /*userPtr*/) + void * /*userPtr*/) { - const size_t bytes = sizeof(size_t) + primCount * sizeof(RTCBuildPrimitive); - char* p = (char*) rtcThreadLocalAlloc(alloc, bytes, 16); - *((size_t*)p) = primCount; - std::memcpy(p + sizeof(size_t), prims, primCount * sizeof(RTCBuildPrimitive)); - return p; + + Node *node = (Node *)rtcThreadLocalAlloc(alloc, sizeof(Node), 16); + new (node) Node(); + return node; } static std::vector makeGridPrimitives(size_t primitiveCount) @@ -113,7 +125,7 @@ static bool runCase(unsigned int maxBranchingFactor) args.createLeaf = createLeaf; args.buildProgress = buildProgress; - void* root = rtcBuildBVH(&args); + void *root = rtcBuildBVH(&args); rtcReleaseBVH(bvh); rtcReleaseDevice(device); @@ -122,6 +134,8 @@ static bool runCase(unsigned int maxBranchingFactor) int main() { + /* In the failure case, this test should assert or result in a segfault from stack overflow. */ + bool okOversized = runCase(64); bool okExtreme = runCase(std::numeric_limits::max()); @@ -130,5 +144,6 @@ int main() if (!okExtreme) std::cerr << "Morton clamp regression failed for maxBranchingFactor=UINT_MAX\n"; + std::cout << "Morton clamp regression test completed.\n"; return (okOversized && okExtreme) ? 0 : 1; } From f591cf303e5111cb25f679410feb8cefffa91311 Mon Sep 17 00:00:00 2001 From: "Werner, Stefan" Date: Wed, 15 Jul 2026 23:27:21 +0200 Subject: [PATCH 4/6] Renamed paramters so they wouldn't shadow members --- kernels/builders/bvh_builder_morton.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernels/builders/bvh_builder_morton.h b/kernels/builders/bvh_builder_morton.h index d05031c0a2..de0bbebaf7 100644 --- a/kernels/builders/bvh_builder_morton.h +++ b/kernels/builders/bvh_builder_morton.h @@ -38,8 +38,8 @@ namespace embree minLeafSize = min(minLeafSize,maxLeafSize); } - Settings (size_t branchingFactor, size_t maxDepth, size_t minLeafSize, size_t maxLeafSize, size_t singleThreadThreshold) - : branchingFactor(branchingFactor), maxDepth(maxDepth), minLeafSize(minLeafSize), maxLeafSize(maxLeafSize), singleThreadThreshold(singleThreadThreshold) + Settings (size_t branchingFactor_, size_t maxDepth_, size_t minLeafSize_, size_t maxLeafSize_, size_t singleThreadThreshold_) + : branchingFactor(branchingFactor_), maxDepth(maxDepth_), minLeafSize(minLeafSize_), maxLeafSize(maxLeafSize_), singleThreadThreshold(singleThreadThreshold_) { if (branchingFactor > MAX_BRANCHING_FACTOR) branchingFactor = MAX_BRANCHING_FACTOR; From cbe7df2927b7ce109124d817c7e82ce7670bf564 Mon Sep 17 00:00:00 2001 From: "Werner, Stefan" Date: Thu, 16 Jul 2026 00:18:10 +0200 Subject: [PATCH 5/6] Fixed indentation --- tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 54004a79a7..5f99ac211d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -39,7 +39,7 @@ FOREACH(xml ${PRIMITIVE_TESTS}) ENDFOREACH() ENDFOREACH() - ADD_SUBDIRECTORY(regression) +ADD_SUBDIRECTORY(regression) IF (EMBREE_TESTING_INSTALL_TESTS) From 5011f85cff807cb5b188cf62050bb30711f4073c Mon Sep 17 00:00:00 2001 From: "Werner, Stefan" Date: Mon, 3 Aug 2026 14:01:31 +0200 Subject: [PATCH 6/6] Branching factor is limited in multiple places: * User facing API will return an error * Internal API will thrown an exception --- kernels/builders/bvh_builder_hair.h | 7 +++++- kernels/builders/bvh_builder_morton.h | 16 ++++++++---- kernels/builders/bvh_builder_msmblur_hair.h | 7 +++++- kernels/common/rtcore_builder.cpp | 25 +++++++++++++++++++ .../morton_builder_clamp_regression.cpp | 18 +++++++------ 5 files changed, 58 insertions(+), 15 deletions(-) diff --git a/kernels/builders/bvh_builder_hair.h b/kernels/builders/bvh_builder_hair.h index d83e8918a1..e4544dd0a3 100644 --- a/kernels/builders/bvh_builder_hair.h +++ b/kernels/builders/bvh_builder_hair.h @@ -84,7 +84,12 @@ namespace embree createLeaf(createLeaf), progressMonitor(progressMonitor), reportFinishedRange(reportFinishedRange), - alignedHeuristic(prims), unalignedHeuristic(scene,prims), strandHeuristic(scene,prims) {} + alignedHeuristic(prims), unalignedHeuristic(scene,prims), strandHeuristic(scene,prims) + { + if (cfg.branchingFactor > MAX_BRANCHING_FACTOR) { + throw_RTCError(RTC_ERROR_UNKNOWN,"bvh_builder: branching factor too large"); + } + } /*! checks if all primitives are from the same geometry */ __forceinline bool sameGeometry(const PrimInfoRange& range) diff --git a/kernels/builders/bvh_builder_morton.h b/kernels/builders/bvh_builder_morton.h index de0bbebaf7..318001837a 100644 --- a/kernels/builders/bvh_builder_morton.h +++ b/kernels/builders/bvh_builder_morton.h @@ -32,8 +32,9 @@ namespace embree if (RTC_BUILD_ARGUMENTS_HAS(settings,minLeafSize )) minLeafSize = settings.minLeafSize; if (RTC_BUILD_ARGUMENTS_HAS(settings,maxLeafSize )) maxLeafSize = settings.maxLeafSize; - if (branchingFactor > MAX_BRANCHING_FACTOR) - branchingFactor = MAX_BRANCHING_FACTOR; + if (branchingFactor > MAX_BRANCHING_FACTOR) { + throw_RTCError(RTC_ERROR_UNKNOWN,"bvh_builder: branching factor too large"); + } minLeafSize = min(minLeafSize,maxLeafSize); } @@ -41,8 +42,9 @@ namespace embree Settings (size_t branchingFactor_, size_t maxDepth_, size_t minLeafSize_, size_t maxLeafSize_, size_t singleThreadThreshold_) : branchingFactor(branchingFactor_), maxDepth(maxDepth_), minLeafSize(minLeafSize_), maxLeafSize(maxLeafSize_), singleThreadThreshold(singleThreadThreshold_) { - if (branchingFactor > MAX_BRANCHING_FACTOR) - branchingFactor = MAX_BRANCHING_FACTOR; + if (branchingFactor > MAX_BRANCHING_FACTOR) { + throw_RTCError(RTC_ERROR_UNKNOWN,"bvh_builder: branching factor too large"); + } minLeafSize = min(minLeafSize,maxLeafSize); } @@ -208,7 +210,11 @@ namespace embree createLeaf(createLeaf), calculateBounds(calculateBounds), progressMonitor(progressMonitor), - morton(nullptr) {} + morton(nullptr) + { + if (branchingFactor > MAX_BRANCHING_FACTOR) + throw_RTCError(RTC_ERROR_UNKNOWN,"bvh_builder: branching factor too large"); + } ReductionTy createLargeLeaf(size_t depth, const range& current, Allocator alloc) { diff --git a/kernels/builders/bvh_builder_msmblur_hair.h b/kernels/builders/bvh_builder_msmblur_hair.h index 397e8636b1..0d3e487535 100644 --- a/kernels/builders/bvh_builder_msmblur_hair.h +++ b/kernels/builders/bvh_builder_msmblur_hair.h @@ -101,7 +101,12 @@ namespace embree createLeaf(createLeaf), progressMonitor(progressMonitor), unalignedHeuristic(scene), - temporalSplitHeuristic(scene->device,recalculatePrimRef) {} + temporalSplitHeuristic(scene->device,recalculatePrimRef) + { + if (cfg.branchingFactor > MAX_BRANCHING_FACTOR) { + throw_RTCError(RTC_ERROR_UNKNOWN,"bvh_builder: branching factor too large"); + } + } private: diff --git a/kernels/common/rtcore_builder.cpp b/kernels/common/rtcore_builder.cpp index 29e3bdca20..cc064d3b2a 100644 --- a/kernels/common/rtcore_builder.cpp +++ b/kernels/common/rtcore_builder.cpp @@ -367,6 +367,31 @@ RTC_NAMESPACE_BEGIN if (arguments->primitiveArrayCapacity < arguments->primitiveCount) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"primitiveArrayCapacity must be greater or equal to primitiveCount") + if (RTC_BUILD_ARGUMENTS_HAS((*arguments),maxLeafSize) && arguments->maxLeafSize > RTC_BUILD_MAX_PRIMITIVES_PER_LEAF) { + throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"maxLeafSize must be smaller or equal to RTC_BUILD_MAX_PRIMITIVES_PER_LEAF") + } + + if (RTC_BUILD_ARGUMENTS_HAS((*arguments),maxBranchingFactor)) + { + const unsigned int branchingFactor = arguments->maxBranchingFactor; + if (branchingFactor < 2) { + throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"maxBranchingFactor must be greater or equal to 2"); + } + + if (arguments->buildQuality == RTC_BUILD_QUALITY_LOW) + { + if (branchingFactor > BVHBuilderMorton::MAX_BRANCHING_FACTOR) { + throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"maxBranchingFactor too large for RTC_BUILD_QUALITY_LOW (maximum is 8)") + } + } + else if (arguments->buildQuality == RTC_BUILD_QUALITY_MEDIUM || arguments->buildQuality == RTC_BUILD_QUALITY_HIGH) + { + if (branchingFactor > GeneralBVHBuilder::MAX_BRANCHING_FACTOR) { + throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"maxBranchingFactor too large for this build quality (maximum is 16)") + } + } + } + /* initialize the allocator */ bvh->allocator.init_estimate(arguments->primitiveCount*sizeof(BBox3fa)); bvh->allocator.reset(); diff --git a/tests/regression/morton_builder_clamp_regression.cpp b/tests/regression/morton_builder_clamp_regression.cpp index f4d4705d49..d258c514bd 100644 --- a/tests/regression/morton_builder_clamp_regression.cpp +++ b/tests/regression/morton_builder_clamp_regression.cpp @@ -125,25 +125,27 @@ static bool runCase(unsigned int maxBranchingFactor) args.createLeaf = createLeaf; args.buildProgress = buildProgress; + rtcGetDeviceError(device); void *root = rtcBuildBVH(&args); + RTCError error = rtcGetDeviceError(device); rtcReleaseBVH(bvh); rtcReleaseDevice(device); - return root != nullptr; + return root == nullptr && error == RTC_ERROR_INVALID_ARGUMENT; } int main() { - /* In the failure case, this test should assert or result in a segfault from stack overflow. */ - bool okOversized = runCase(64); bool okExtreme = runCase(std::numeric_limits::max()); - if (!okOversized) - std::cerr << "Morton clamp regression failed for maxBranchingFactor=64\n"; - if (!okExtreme) - std::cerr << "Morton clamp regression failed for maxBranchingFactor=UINT_MAX\n"; + if (!okOversized) { + std::cerr << "Morton oversized maxBranchingFactor regression failed for maxBranchingFactor=64\n"; + } + if (!okExtreme) { + std::cerr << "Morton oversized maxBranchingFactor regression failed for maxBranchingFactor=UINT_MAX\n"; + } - std::cout << "Morton clamp regression test completed.\n"; + std::cout << "Morton oversized branching factor regression test completed.\n"; return (okOversized && okExtreme) ? 0 : 1; }