From 10663af6e209ddf02e7f523fa49d85151fb96058 Mon Sep 17 00:00:00 2001 From: Ernesto Mendoza Date: Thu, 5 Nov 2026 20:09:01 -0600 Subject: [PATCH] Build polyline and polygon indices on the heap, not the stack --- CHANGELOG.md | 1 + ViroRenderer/VROPolygon.cpp | 10 ++++++---- ViroRenderer/VROPolyline.cpp | 11 +++++++---- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f46fdc14..06b8930b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -100,6 +100,7 @@ - **iOS downloads from a signed URL are saved (`VROPlatformDownloadURLToFile`, `VROPlatformDownloadURLToFileAsync`).** The temporary file was named after the URL's last path component with its query, and a signed URL's token pushed the name past the 255-byte file name limit, so the write failed and the download still reported success with a file that did not exist. `VROPlatformLastPathComponent` drops the query and fragment, and a failed write now fails the download. - **Android: a camera added before the renderer no longer crashes (`VROPlatformUtil`, #597).** `libviro_renderer.so` now sets the `JavaVM` in `JNI_OnLoad`. It was set only when a renderer or loader started, and under Fabric `ViroARCamera`'s view is built first, so adding its node reached `getJNIEnv` with no VM. - **A GLB whose skins share joints animates every skin (`VROGLTFLoader`, #599).** Resampling runs once per skin and rewrote a shared joint's channels in place; the next skin's pass kept only the translation of the merged channel, so those joints lost their rotation and scale. Every property of a channel is now copied. +- **A long polyline no longer overflows the stack (`VROPolyline`, `VROPolygon`).** `buildElement` built its index list as a variable-length array on the stack. The world mesh's debug drawing (`debugDrawEnabled`) on an accumulated mesh reaches hundreds of thousands of line corners, which overflowed the iOS main thread's stack and crashed the app. The list is on the heap now, as is a polygon's. ### Removed diff --git a/ViroRenderer/VROPolygon.cpp b/ViroRenderer/VROPolygon.cpp index 6f4e88e30..ac8d12430 100644 --- a/ViroRenderer/VROPolygon.cpp +++ b/ViroRenderer/VROPolygon.cpp @@ -24,6 +24,7 @@ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "VROPolygon.h" +#include #include "VROData.h" #include "VROGeometryUtil.h" #include "VROGeometrySource.h" @@ -189,12 +190,13 @@ void VROPolygon::buildGeometry(std::vector> & } std::shared_ptr VROPolygon::buildElement(size_t numCorners) { - int indices[numCorners]; - for (int i = 0; i < numCorners; i++) { - indices[i] = i; + // On the heap: the corner count has no bound, so a stack array could overflow. + std::vector indices(numCorners); + for (size_t i = 0; i < numCorners; i++) { + indices[i] = (int) i; } - std::shared_ptr indexData = std::make_shared((void *) indices, sizeof(int) * numCorners); + std::shared_ptr indexData = std::make_shared((void *) indices.data(), sizeof(int) * numCorners); std::shared_ptr element= std::make_shared(indexData, VROGeometryPrimitiveType::Triangle, VROGeometryUtilGetPrimitiveCount((int) numCorners, diff --git a/ViroRenderer/VROPolyline.cpp b/ViroRenderer/VROPolyline.cpp index 0bfac5411..2b61115ee 100644 --- a/ViroRenderer/VROPolyline.cpp +++ b/ViroRenderer/VROPolyline.cpp @@ -24,6 +24,7 @@ // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +#include #include "VROPolyline.h" #include "VROLog.h" #include "VROByteBuffer.h" @@ -211,12 +212,14 @@ void VROPolyline::buildGeometry(std::vector> &paths, } std::shared_ptr VROPolyline::buildElement(size_t numCorners) { - int indices[numCorners]; - for (int i = 0; i < numCorners; i++) { - indices[i] = i; + // On the heap: a world mesh's debug lines reach hundreds of thousands of corners, + // which overflowed the render thread's stack as a variable-length array. + std::vector indices(numCorners); + for (size_t i = 0; i < numCorners; i++) { + indices[i] = (int) i; } - std::shared_ptr indexData = std::make_shared((void *) indices, sizeof(int) * numCorners); + std::shared_ptr indexData = std::make_shared((void *) indices.data(), sizeof(int) * numCorners); std::shared_ptr element = std::make_shared(indexData, VROGeometryPrimitiveType::TriangleStrip, VROGeometryUtilGetPrimitiveCount((int) numCorners, VROGeometryPrimitiveType::TriangleStrip),