Rhino3dm js wasm memory access out of bounds error

I am trying to use rhino3dm js to author a rhino file containing blocks from meshes I create. I am running into trouble with a memory access out of bounds error thrown at instanceDefinitions().add(). I am seeing this issue in both the browser context and the node context.

Here is a set of tests:

import rhino3dm, { RhinoModule } from "rhino3dm"
import { ExportMesh } from "./pringleTypes"
import fs from 'fs'

const exportMeshToRhinoMesh = (mesh: ExportMesh, rhino: RhinoModule) => {
    const rhinoMesh = new rhino.Mesh()
    mesh.vertices.forEach((vertex) => {
        rhinoMesh.vertices().add(vertex.x, vertex.y, vertex.z)
    })
    for (let i = 0; i < mesh.faces.length; i++) {
        rhinoMesh.faces().addTriFace(mesh.faces[i][0], mesh.faces[i][1], mesh.faces[i][2])
    }
    return rhinoMesh
}
const exportMeshJson = fs.readFileSync('./test-input/badMesh.json')
const badMeshes: ExportMesh[] = JSON.parse(exportMeshJson.toString())

describe('creating a rhino file', () => {
    // SUCCEEDS
    it('creates a definition from the first mesh', async () => {
        const rhino = await rhino3dm()
        const doc = new rhino.File3dm()
        const mesh1 = exportMeshToRhinoMesh(badMeshes[0], rhino)
        const blockId = doc.instanceDefinitions().add(`block`, '', '', '', [0, 0, 0], [mesh1], [new rhino.ObjectAttributes()])
    })

    // SUCCEEDS
    it('creates a definition from the second mesh', async () => {
        const rhino = await rhino3dm()
        const doc = new rhino.File3dm()
        const mesh2 = exportMeshToRhinoMesh(badMeshes[1], rhino)
        const blockId = doc.instanceDefinitions().add(`block`, '', '', '', [0, 0, 0], [mesh2], [new rhino.ObjectAttributes()])
    })

    // SUCCEEDS
    it('creates a definition from the third mesh', async () => {
        const rhino = await rhino3dm()
        const doc = new rhino.File3dm()
        const mesh3 = exportMeshToRhinoMesh(badMeshes[2], rhino)
        const blockId = doc.instanceDefinitions().add(`block`, '', '', '', [0, 0, 0], [mesh3], [new rhino.ObjectAttributes()])
    })

    // FAILS
    it('creates a definition for each mesh', async () => {
        const rhino = await rhino3dm()
        const doc = new rhino.File3dm()
        badMeshes.forEach((m) => {
            const mesh = exportMeshToRhinoMesh(m, rhino)
            const blockId = doc.instanceDefinitions().add(`block`, '', '', '', [0, 0, 0], [mesh], [new rhino.ObjectAttributes()])
        })
    })

    // FAILS
    it('creates a single definition from all three meshes', async () => {
        const rhino = await rhino3dm()
        const doc = new rhino.File3dm()
        const meshes = badMeshes.map((m) => exportMeshToRhinoMesh(m, rhino))
        const blockId = doc.instanceDefinitions().add(`block`, '', '', '', [0, 0, 0], meshes, meshes.map((_) => new rhino.ObjectAttributes()))
    })
})

(Note that ALL tests fail if those marked “FAILS” are uncommented — but if you comment them out, the first three do succeed.)

Here is the raw json data for the test:
badMesh.json (1.1 MB)

The error for the failing tests is

    RuntimeError: memory access out of bounds
        at wasm://wasm/009f7dd6:wasm-function[4448]:0xe78b3
        at wasm://wasm/009f7dd6:wasm-function[2536]:0x6dbc9
        at wasm://wasm/009f7dd6:wasm-function[3505]:0xad216
        at wasm://wasm/009f7dd6:wasm-function[10560]:0x2114f1
        at wasm://wasm/009f7dd6:wasm-function[10474]:0x21039e

It’s conceivable that my mesh data is somehow at fault, but the fact that it succeeds for each of the three meshes individually would suggest otherwise. I’ve inspected the meshes in grasshopper and they look fine, all face indices are in range.

Any assistance would be greatly appreciated!

I can duplicate this on my end, and with some debug info I can see that something is up with how we are setting up ObjectAttributes:

RuntimeError: memory access out of bounds

      at ON_3dmObjectAttributes::MeshModifiers() const (wasm:/wasm/rhino3dm.wasm-0ae3606a:1:2589361)
      at BND_File3dmDisplacement::BND_File3dmDisplacement(ON_3dmObjectAttributes*) (wasm:/wasm/rhino3dm.wasm-0ae3606a:1:1607973)
      at BND_File3dmMeshModifiers::BND_File3dmMeshModifiers(BND_File3dmMeshModifiers const&) (wasm:/wasm/rhino3dm.wasm-0ae3606a:1:1611700)
      at BND_3dmObjectAttributes::BND_3dmObjectAttributes(BND_3dmObjectAttributes const&) (wasm:/wasm/rhino3dm.wasm-0ae3606a:1:1100776)
      at BND_3dmObjectAttributes emscripten::internal::fromGenericWireType<BND_3dmObjectAttributes>(double) (wasm:/wasm/rhino3dm.wasm-0ae3606a:1:967628)
      at BND_3dmObjectAttributes emscripten::val::as<BND_3dmObjectAttributes>() const (wasm:/wasm/rhino3dm.wasm-0ae3606a:1:966444)
      at BND_File3dmInstanceDefinitionTable::Add(std::__2::basic_string<wchar_t, std::__2::char_traits<wchar_t>, std::__2::allocator<wchar_t>>, std::__2::basic_string<wchar_t, std::__2::char_traits<wchar_t>, std::__2::allocator<wchar_t>>, std::__2::basic_string<wchar_t, std::__2::char_traits<wchar_t>, std::__2::allocator<wchar_t>>, std::__2::basic_string<wchar_t, std::__2::char_traits<wchar_t>, std::__2::allocator<wchar_t>>, ON_3dPoint, emscripten::val, emscripten::val) (wasm:/wasm/rhino3dm.wasm-0ae3606a:1:963726)
...

Interestingly, your last test creates a single definition from all three meshes passes for me.

Thanks for bringing it up. I’ll keep investigating.

1 Like