recastnavigation / recastnavigation

Industry-standard navigation-mesh toolset for games

Home Page:http://recastnav.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

dividePoly crashes on the attempt to add 8th point

elsid opened this issue · comments

This happens here because poly2Vert has value 7. There is a stack allocated buffer used here that does not provide enough capacity for this. Looking at adcd4f4 it seems it should not. So there is a problem in the logic leading to extra data being generated. I had to modify the code adding bounds check to get a snapshot right before the crash.

Stack trace:

Thread 20 (Thread 0x7fffaf7fe6c0 (LWP 104677) "openmw"):
#0  0x00007ffff0aac83c in  () at /usr/lib/libc.so.6
#1  0x00007ffff0a5c668 in raise () at /usr/lib/libc.so.6
#2  0x00007ffff0a444b8 in abort () at /usr/lib/libc.so.6
#3  0x000055555957c2b6 in (anonymous namespace)::Span<float>::operator[](int) const (this=0x7fffaf7fcf10, index=21) at /home/elsid/dev/recastnavigation/Recast/Source/RecastRasterization.cpp:247
#4  0x000055555957ae6f in dividePoly(float const*, int, float*, int*, float*, int*, float, rcAxis, float const*) (inVertsPtr=0x7fffaf7fd0c4, inVertsCount=7, outVerts1Ptr=0x7fffaf7fd118, outVerts1Count=0x7fffaf7fcfe0, outVerts2Ptr=0x7fffaf7fd16c, outVerts2Count=0x7fffaf7fcfe4, axisOffset=7228336.5, axis=RC_AXIS_X, outEnd=0x7fffaf7fd1c0) at /home/elsid/dev/recastnavigation/Recast/Source/RecastRasterization.cpp:326
        sameSide = true
        inVertA = 6
        inVertB = 5
        __PRETTY_FUNCTION__ = "void dividePoly(const float*, int, float*, int*, float*, int*, float, rcAxis, const float*)"
        inVerts = {values = 0x7fffaf7fd0c4, count = 21}
        outVerts1 = {values = 0x7fffaf7fd118, count = 42}
        outVerts2 = {values = 0x7fffaf7fd16c, count = 21}
        inVertAxisDelta = {0, -1, -0.5, 0, 0, 0, 0, 4.59163468e-41, -2.32663888e-10, 4.59163468e-41, 7228368, 1.57225688e-42}
        poly1Vert = 6
        poly2Vert = 7
#5  0x000055555957b4c4 in rasterizeTri(float const*, float const*, float const*, unsigned char, rcHeightfield&, float const*, float const*, float, float, float, int) (v0=0x7fffaf7fd310, v1=0x7fffaf7fd31c, v2=0x7fffaf7fd328, areaID=1 '\001', heightfield=..., heightfieldBBMin=0x7fffaf7fd578, heightfieldBBMax=0x7fffaf7fd584, cellSize=0.200000003, inverseCellSize=5, inverseCellHeight=5, flagMergeThreshold=5) at /home/elsid/dev/recastnavigation/Recast/Source/RecastRasterization.cpp:447
        spanMinCellIndex = 282
        spanMaxCellIndex = 283
        cx = 7228336.5
        spanMin = 56.4897079
        spanMax = 56.4897079
        x = 3
        minX = 7228336.5
        maxX = 7228337.5
        x0 = 2
        nv = 5
        cellZ = 7228337.5
        x1 = 7
        nv2 = 7
        z = 7
        triBBMin = {7228336.5, -3.7455883, 7228336.5}
        triBBMax = {7228368, -3.7455883, 7228368}
        w = 160
        h = 160
        by = 60.2352943
        z0 = 2
        z1 = 159
        bufSize = 84
        buf = {7228337.5, -3.7455883, 7228337.5, 7228336.5, -3.7455883, 7228337.5, 7228336.5, -3.7455883, 7228368, 7228368, -3.7455883, 7228368, 7228336.5, -3.7455883, 7228337, 7228336.5, -3.7455883, 7228337, 7228336.5, -3.7455883, 7228337, 7228336.5, -3.7455883, 7228337.5, 7228337.5, -3.7455883, 7228337.5, 7228337, -3.7455883, 7228337, 7228336.5, -3.7455883, 7228337, 7228336.5, -3.7455883, 7228337, 7228336.5, -3.7455883, 7228337, 7228336.5, -3.7455883, 7228337.5, 7228336.5, -3.7455883, 7228337.5, 7228336.5, -3.7455883, 7228337.5, 7228336.5, -3.7455883, 7228337, 7228336.5, -3.7455883, 7228337, 7228336.5, -3.7455883, 7228337, 7228336.5, -3.7455883, 7228337.5, -2.32665665e-10, 4.59163468e-41, 0, 7228336.5, -3.7455883, 7228337.5, 7228336.5, -3.7455883, 7228337.5, 7228337.5, -3.7455883, 7228337.5, 7228337, -3.7455883, 7228337, 7228336.5, -3.7455883, 7228337, 7228336.5, -3.7455883, 7228337, 7228336.5, -3.7455883, 7228337}
        in = 0x7fffaf7fd070
        inRow = 0x7fffaf7fd0c4
        bufEnd = 0x7fffaf7fd1c0
        p1 = 0x7fffaf7fd118
        p2 = 0x7fffaf7fd16c
        nvRow = 6
        nvIn = 4
#6  0x000055555957bb83 in rcRasterizeTriangles(rcContext*, float const*, int, int const*, unsigned char const*, int, rcHeightfield&, int) (context=0x7fffaf7fd540, verts=0x7fffaf7fd310, tris=0x7fffaf7fd2f0, triAreaIDs=0x7fffaf7fd2ee "\001\001", numTris=2, heightfield=..., flagMergeThreshold=5) at /home/elsid/dev/recastnavigation/Recast/Source/RecastRasterization.cpp:541
        v0 = 0x7fffaf7fd310
        v1 = 0x7fffaf7fd31c
        v2 = 0x7fffaf7fd328
        triIndex = 0
        __PRETTY_FUNCTION__ = "bool rcRasterizeTriangles(rcContext*, const float*, int, const int*, const unsigned char*, int, rcHeightfield&, int)"
        timer = {m_ctx = 0x7fffaf7fd540, m_label = RC_TIMER_RASTERIZE_TRIANGLES}
        inverseCellSize = 5
        inverseCellHeight = 5
#7  0x0000555559469589 in DetourNavigator::(anonymous namespace)::rasterizeTriangles(DetourNavigator::RecastContext&, DetourNavigator::(anonymous namespace)::Rectangle const&, DetourNavigator::AreaType, DetourNavigator::(anonymous namespace)::RecastParams const&, rcHeightfield&) (context=..., rectangle=..., areaType=DetourNavigator::AreaType_water, params=..., solid=...) at /home/elsid/dev/openmw/components/detournavigator/makenavmesh.cpp:227
        vertices = {_M_elems = {7228336.5, -3.7455883, 7228336.5, 7228336.5, -3.7455883, 7228368, 7228368, -3.7455883, 7228368, 7228368, -3.7455883, 7228336.5}}
        indices = {_M_elems = {0, 1, 2, 0, 2, 3}}
        areas = {_M_elems = "\001\001"}
#8  0x0000555559469727 in DetourNavigator::(anonymous namespace)::rasterizeTriangles(DetourNavigator::RecastContext&, float, std::vector<DetourNavigator::CellWater, std::allocator<DetourNavigator::CellWater> > const&, DetourNavigator::RecastSettings const&, DetourNavigator::(anonymous namespace)::RecastParams const&, DetourNavigator::TileBounds const&, rcHeightfield&) (context=..., agentHalfExtentsZ=66.5, water=..., settings=..., params=..., realTileBounds=..., solid=...) at /home/elsid/dev/openmw/components/detournavigator/makenavmesh.cpp:244
        rectangle = {mBounds = {mMin = {_v = {7228336.5, 7228336.5}}, mMax = {_v = {7228368, 7228368}}}, mHeight = -3.7455883}
        intersection = {<std::_Optional_base<DetourNavigator::TileBounds, true, true>> = {<std::_Optional_base_impl<DetourNavigator::TileBounds, std::_Optional_base<DetourNavigator::TileBounds, true, true> >> = {<No data fields>}, _M_payload = {<std::_Optional_payload_base<DetourNavigator::TileBounds>> = {_M_payload = {_M_empty = {<No data fields>}, _M_value = {mMin = {_v = {245763440, 245763440}}, mMax = {_v = {245764512, 245764512}}}}, _M_engaged = true}, <No data fields>}}, <std::_Enable_copy_move<true, true, true, true, std::optional<DetourNavigator::TileBounds> >> = {<No data fields>}, <No data fields>}
        cellTileBounds = {mMin = {_v = {245760000, 245760000}}, mMax = {_v = {245768192, 245768192}}}
        cellWater = @0x7fffa0000bb0: {mCellPosition = {_v = {30000, 30000}}, mWater = {mCellSize = 8192, mLevel = -1}}
        __for_range = @0x7fffa0000cd8: {<std::_Vector_base<DetourNavigator::CellWater, std::allocator<DetourNavigator::CellWater> >> = {_M_impl = {<std::allocator<DetourNavigator::CellWater>> = {<std::__new_allocator<DetourNavigator::CellWater>> = {<No data fields>}, <No data fields>}, <std::_Vector_base<DetourNavigator::CellWater, std::allocator<DetourNavigator::CellWater> >::_Vector_impl_data> = {_M_start = 0x7fffa0000bb0, _M_finish = 0x7fffa0000bc0, _M_end_of_storage = 0x7fffa0000bc0}, <No data fields>}}, <No data fields>}
        __for_begin = {_M_current = 0x7fffa0000bb0}
        __for_end = {_M_current = 0x7fffa0000bc0}
#9  0x0000555559469b42 in DetourNavigator::(anonymous namespace)::rasterizeTriangles(DetourNavigator::RecastContext&, DetourNavigator::TilePosition const&, float, DetourNavigator::RecastMesh const&, DetourNavigator::RecastSettings const&, DetourNavigator::(anonymous namespace)::RecastParams const&, rcHeightfield&) (context=..., tilePosition=..., agentHalfExtentsZ=66.5, recastMesh=..., settings=..., params=..., solid=...) at /home/elsid/dev/openmw/components/detournavigator/makenavmesh.cpp:287
        realTileBounds = {mMin = {_v = {245763440, 245763440}}, mMax = {_v = {245764512, 245764512}}}
#10 0x000055555946aedd in DetourNavigator::prepareNavMeshTileData(DetourNavigator::RecastMesh const&, std::basic_string_view<char, std::char_traits<char> >, osg::Vec2i const&, DetourNavigator::AgentBounds const&, DetourNavigator::RecastSettings const&) (recastMesh=..., worldspace=..., tilePosition=..., agentBounds=..., settings=...) at /home/elsid/dev/openmw/components/detournavigator/makenavmesh.cpp:528
        context = {<rcContext> = {_vptr.rcContext = 0x5555596d9290 <vtable for DetourNavigator::RecastContext+16>, m_logEnabled = true, m_timerEnabled = true}, mPrefix = {_M_dataplus = {<std::allocator<char>> = {<std::__new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fffa0000fa0 "Worldspace: sys::default; tile position: 282357, 282357; agent bounds: AgentBounds {AgentShapeType::Cylinder, {29.28, 28.48, 66.5}}; "}, _M_string_length = 133, {_M_local_buf = "\205\000\000\000\000\000\000\000(\260\204cUU\000", _M_allocated_capacity = 133}}}
        minZ = @0x7fffaf7fd518: -2048
        maxZ = @0x7fffaf7fd51c: 0
        solid = {width = 160, height = 160, bmin = {7228336, -60.2352943, 7228336}, bmax = {7228368, 0, 7228368}, cs = 0.200000003, ch = 0.200000003, spans = 0x7fffa0001038, pools = 0x7fffa0033048, freelist = 0x7fffa0033100}
        params = {mSampleDist = 1.20000005, mSampleMaxError = 0.200000003, mMaxEdgeLen = 60, mWalkableClimb = 5, mWalkableHeight = 20, mWalkableRadius = 5}
        result = {_M_t = {<std::__uniq_ptr_impl<DetourNavigator::PreparedNavMeshData, std::default_delete<DetourNavigator::PreparedNavMeshData> >> = {_M_t = {<std::_Tuple_impl<0, DetourNavigator::PreparedNavMeshData*, std::default_delete<DetourNavigator::PreparedNavMeshData> >> = {<std::_Tuple_impl<1, std::default_delete<DetourNavigator::PreparedNavMeshData> >> = {<std::_Head_base<1, std::default_delete<DetourNavigator::PreparedNavMeshData>, true>> = {_M_head_impl = {<No data fields>}}, <No data fields>}, <std::_Head_base<0, DetourNavigator::PreparedNavMeshData*, false>> = {_M_head_impl = 0x7fffaf7fd520}, <No data fields>}, <No data fields>}}, <No data fields>}}
#11 0x0000555559450883 in DetourNavigator::AsyncNavMeshUpdater::processInitialJob(DetourNavigator::Job&, Misc::ScopeGuarded<DetourNavigator::NavMeshCacheItem>&) (this=0x55555a8dfbc0, job=..., navMeshCacheItem=...) at /home/elsid/dev/openmw/components/detournavigator/asyncnavmeshupdater.cpp:437
        recastMesh = {<std::__shared_ptr<DetourNavigator::RecastMesh, (__gnu_cxx::_Lock_policy)2>> = {<std::__shared_ptr_access<DetourNavigator::RecastMesh, (__gnu_cxx::_Lock_policy)2, false, false>> = {<No data fields>}, _M_ptr = 0x7fffa0000c80, _M_refcount = {_M_pi = 0x7fffa0000c70}}, <No data fields>}
        cachedNavMeshData = {mOwner = 0x0, mIterator = {_M_node = 0x0}}
        preparedNavMeshData = {_M_t = {<std::__uniq_ptr_impl<DetourNavigator::PreparedNavMeshData, std::default_delete<DetourNavigator::PreparedNavMeshData> >> = {_M_t = {<std::_Tuple_impl<0, DetourNavigator::PreparedNavMeshData*, std::default_delete<DetourNavigator::PreparedNavMeshData> >> = {<std::_Tuple_impl<1, std::default_delete<DetourNavigator::PreparedNavMeshData> >> = {<std::_Head_base<1, std::default_delete<DetourNavigator::PreparedNavMeshData>, true>> = {_M_head_impl = {<No data fields>}}, <No data fields>}, <std::_Head_base<0, DetourNavigator::PreparedNavMeshData*, false>> = {_M_head_impl = 0x0}, <No data fields>}, <No data fields>}}, <No data fields>}}
        preparedNavMeshDataPtr = 0x0
        offMeshConnections = {<std::_Vector_base<DetourNavigator::OffMeshConnection, std::allocator<DetourNavigator::OffMeshConnection> >> = {_M_impl = {<std::allocator<DetourNavigator::OffMeshConnection>> = {<std::__new_allocator<DetourNavigator::OffMeshConnection>> = {<No data fields>}, <No data fields>}, <std::_Vector_base<DetourNavigator::OffMeshConnection, std::allocator<DetourNavigator::OffMeshConnection> >::_Vector_impl_data> = {_M_start = 0x7fffaf7fd690, _M_finish = 0x55555944f6dd <DetourNavigator::getDistance(osg::Vec2i const&, osg::Vec2i const&)+66>, _M_end_of_storage = 0x7fffaf7fd730}, <No data fields>}}, <No data fields>}
        __PRETTY_FUNCTION__ = "DetourNavigator::JobStatus DetourNavigator::AsyncNavMeshUpdater::processInitialJob(DetourNavigator::Job&, DetourNavigator::GuardedNavMeshCacheItem&)"
        status = 21845
#12 0x00005555594489c6 in DetourNavigator::AsyncNavMeshUpdater::processJob(DetourNavigator::Job&) (this=0x55555a8dfbc0, job=...) at /home/elsid/dev/openmw/components/detournavigator/asyncnavmeshupdater.cpp:392
        navMeshCacheItem = {<std::__shared_ptr<Misc::ScopeGuarded<DetourNavigator::NavMeshCacheItem>, (__gnu_cxx::_Lock_policy)2>> = {<std::__shared_ptr_access<Misc::ScopeGuarded<DetourNavigator::NavMeshCacheItem>, (__gnu_cxx::_Lock_policy)2, false, false>> = {<No data fields>}, _M_ptr = 0x55556003e650, _M_refcount = {_M_pi = 0x55556003e640}}, <No data fields>}
        playerTile = {_v = {282357, 282357}}
        maxTiles = 512
#13 0x00005555594484a2 in DetourNavigator::AsyncNavMeshUpdater::process() (this=0x55555a8dfbc0) at /home/elsid/dev/openmw/components/detournavigator/asyncnavmeshupdater.cpp:337
        status = (unknown: 0x5a8dfc98)
        job = {_M_node = 0x55556384aff0}
#14 0x0000555559447397 in operator()() const (__closure=0x55555a7846d8) at /home/elsid/dev/openmw/components/detournavigator/asyncnavmeshupdater.cpp:161
        this = 0x55555a8dfbc0
        i = 140736137779152
#15 0x000055555944edc5 in std::__invoke_impl<void, DetourNavigator::AsyncNavMeshUpdater::AsyncNavMeshUpdater(const DetourNavigator::Settings&, DetourNavigator::TileCachedRecastMeshManager&, DetourNavigator::OffMeshConnectionsManager&, std::unique_ptr<DetourNavigator::NavMeshDb>&&)::<lambda()> >(std::__invoke_other, struct {...} &&) (__f=...) at /usr/include/c++/13.2.1/bits/invoke.h:61
#16 0x000055555944ed35 in std::__invoke<DetourNavigator::AsyncNavMeshUpdater::AsyncNavMeshUpdater(const DetourNavigator::Settings&, DetourNavigator::TileCachedRecastMeshManager&, DetourNavigator::OffMeshConnectionsManager&, std::unique_ptr<DetourNavigator::NavMeshDb>&&)::<lambda()> >(struct {...} &&) (__fn=...) at /usr/include/c++/13.2.1/bits/invoke.h:96
#17 0x000055555944ecb6 in std::thread::_Invoker<std::tuple<DetourNavigator::AsyncNavMeshUpdater::AsyncNavMeshUpdater(const DetourNavigator::Settings&, DetourNavigator::TileCachedRecastMeshManager&, DetourNavigator::OffMeshConnectionsManager&, std::unique_ptr<DetourNavigator::NavMeshDb>&&)::<lambda()> > >::_M_invoke<0>(std::_Index_tuple<0>) (this=0x55555a7846d8) at /usr/include/c++/13.2.1/bits/std_thread.h:292
#18 0x000055555944ec6e in std::thread::_Invoker<std::tuple<DetourNavigator::AsyncNavMeshUpdater::AsyncNavMeshUpdater(const DetourNavigator::Settings&, DetourNavigator::TileCachedRecastMeshManager&, DetourNavigator::OffMeshConnectionsManager&, std::unique_ptr<DetourNavigator::NavMeshDb>&&)::<lambda()> > >::operator()(void) (this=0x55555a7846d8) at /usr/include/c++/13.2.1/bits/std_thread.h:299
#19 0x000055555944ec32 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<DetourNavigator::AsyncNavMeshUpdater::AsyncNavMeshUpdater(const DetourNavigator::Settings&, DetourNavigator::TileCachedRecastMeshManager&, DetourNavigator::OffMeshConnectionsManager&, std::unique_ptr<DetourNavigator::NavMeshDb>&&)::<lambda()> > > >::_M_run(void) (this=0x55555a7846d0) at /usr/include/c++/13.2.1/bits/std_thread.h:244
#20 0x00007ffff0ce1943 in std::execute_native_thread_routine(void*) (__p=0x55555a7846d0) at /usr/src/debug/gcc/gcc/libstdc++-v3/src/c++11/thread.cc:104
#21 0x00007ffff0aaa9eb in  () at /usr/lib/libc.so.6
#22 0x00007ffff0b2e7cc in  () at /usr/lib/libc.so.6

Original AddressSanitizer report:

==103277==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7efdeabbc280 at pc 0x55afc201ec3f bp 0x7efded0cb480 sp 0x7efded0cb470
WRITE of size 4 at 0x7efdeabbc280 thread T18
    #0 0x55afc201ec3e in rcVcopy(float*, float const*) /home/elsid/dev/recastnavigation/build/gcc/asan/install/include/recastnavigation/Recast.h:774
    #1 0x55afc2296ce0 in dividePoly /home/elsid/dev/recastnavigation/Recast/Source/RecastRasterization.cpp:281
    #2 0x55afc2297c46 in rasterizeTri /home/elsid/dev/recastnavigation/Recast/Source/RecastRasterization.cpp:400
    #3 0x55afc22989bf in rcRasterizeTriangles(rcContext*, float const*, int, int const*, unsigned char const*, int, rcHeightfield&, int) /home/elsid/dev/recastnavigation/Recast/Source/RecastRasterization.cpp:494
    #4 0x55afc2018e60 in rasterizeTriangles /home/elsid/dev/openmw/components/detournavigator/makenavmesh.cpp:227
    #5 0x55afc2019346 in rasterizeTriangles /home/elsid/dev/openmw/components/detournavigator/makenavmesh.cpp:244
    #6 0x55afc2019f3b in rasterizeTriangles /home/elsid/dev/openmw/components/detournavigator/makenavmesh.cpp:287
    #7 0x55afc201c8f7 in DetourNavigator::prepareNavMeshTileData(DetourNavigator::RecastMesh const&, std::basic_string_view<char, std::char_traits<char> >, osg::Vec2i const&, DetourNavigator::AgentBounds const&, DetourNavigator::RecastSettings const&) /home/elsid/dev/openmw/components/detournavigator/makenavmesh.cpp:528
    #8 0x55afc1fde356 in DetourNavigator::AsyncNavMeshUpdater::processInitialJob(DetourNavigator::Job&, Misc::ScopeGuarded<DetourNavigator::NavMeshCacheItem>&) /home/elsid/dev/openmw/components/detournavigator/asyncnavmeshupdater.cpp:437
    #9 0x55afc1fc81c1 in DetourNavigator::AsyncNavMeshUpdater::processJob(DetourNavigator::Job&) /home/elsid/dev/openmw/components/detournavigator/asyncnavmeshupdater.cpp:392
    #10 0x55afc1fc7463 in DetourNavigator::AsyncNavMeshUpdater::process() /home/elsid/dev/openmw/components/detournavigator/asyncnavmeshupdater.cpp:337
    #11 0x55afc1fc4e2d in operator() /home/elsid/dev/openmw/components/detournavigator/asyncnavmeshupdater.cpp:161
    #12 0x55afc1fda8ae in __invoke_impl<void, DetourNavigator::AsyncNavMeshUpdater::AsyncNavMeshUpdater(const DetourNavigator::Settings&, DetourNavigator::TileCachedRecastMeshManager&, DetourNavigator::OffMeshConnectionsManager&, std::unique_ptr<DetourNavigator::NavMeshDb>&&)::<lambda()> > /usr/include/c++/13.2.1/bits/invoke.h:61
    #13 0x55afc1fda81e in __invoke<DetourNavigator::AsyncNavMeshUpdater::AsyncNavMeshUpdater(const DetourNavigator::Settings&, DetourNavigator::TileCachedRecastMeshManager&, DetourNavigator::OffMeshConnectionsManager&, std::unique_ptr<DetourNavigator::NavMeshDb>&&)::<lambda()> > /usr/include/c++/13.2.1/bits/invoke.h:96
    #14 0x55afc1fda79f in _M_invoke<0> /usr/include/c++/13.2.1/bits/std_thread.h:292
    #15 0x55afc1fda757 in operator() /usr/include/c++/13.2.1/bits/std_thread.h:299
    #16 0x55afc1fda71b in _M_run /usr/include/c++/13.2.1/bits/std_thread.h:244
    #17 0x7efe23ae1942 in execute_native_thread_routine /usr/src/debug/gcc/gcc/libstdc++-v3/src/c++11/thread.cc:104
    #18 0x7efe237bd9ea  (/usr/lib/libc.so.6+0x8c9ea) (BuildId: 8bfe03f6bf9b6a6e2591babd0bbc266837d8f658)
    #19 0x7efe238417cb  (/usr/lib/libc.so.6+0x1107cb) (BuildId: 8bfe03f6bf9b6a6e2591babd0bbc266837d8f658)

Address 0x7efdeabbc280 is located in stack of thread T18 at offset 640 in frame
    #0 0x55afc2296e18 in rasterizeTri /home/elsid/dev/recastnavigation/Recast/Source/RecastRasterization.cpp:311

  This frame has 11 object(s):
    [48, 52) 'nvRow' (line 351)
    [64, 68) 'nvIn' (line 352)
    [80, 84) 'nv' (line 393)
    [96, 100) 'nv2' (line 394)
    [112, 120) 'in' (line 343)
    [144, 152) 'inRow' (line 344)
    [176, 184) 'p1' (line 345)
    [208, 216) 'p2' (line 346)
    [240, 252) 'triBBMin' (line 313)
    [272, 284) 'triBBMax' (line 318)
    [304, 640) 'buf' (line 342) <== Memory access at offset 640 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
Thread T18 created by T0 here:
    #0 0x7efe2b04a497 in __interceptor_pthread_create /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_interceptors.cpp:208
    #1 0x7efe23ae1a29 in __gthread_create /usr/src/debug/gcc/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/gthr-default.h:663
    #2 0x7efe23ae1a29 in std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) /usr/src/debug/gcc/gcc/libstdc++-v3/src/c++11/thread.cc:172
    #3 0x55afc1fd0292 in construct_at<std::thread, DetourNavigator::AsyncNavMeshUpdater::AsyncNavMeshUpdater(const DetourNavigator::Settings&, DetourNavigator::TileCachedRecastMeshManager&, DetourNavigator::OffMeshConnectionsManager&, std::unique_ptr<DetourNavigator::NavMeshDb>&&)::<lambda()> > /usr/include/c++/13.2.1/bits/stl_construct.h:97
    #4 0x55afc1fcefac in construct<std::thread, DetourNavigator::AsyncNavMeshUpdater::AsyncNavMeshUpdater(const DetourNavigator::Settings&, DetourNavigator::TileCachedRecastMeshManager&, DetourNavigator::OffMeshConnectionsManager&, std::unique_ptr<DetourNavigator::NavMeshDb>&&)::<lambda()> > /usr/include/c++/13.2.1/bits/alloc_traits.h:539
    #5 0x55afc1fcefac in _M_realloc_insert<DetourNavigator::AsyncNavMeshUpdater::AsyncNavMeshUpdater(const DetourNavigator::Settings&, DetourNavigator::TileCachedRecastMeshManager&, DetourNavigator::OffMeshConnectionsManager&, std::unique_ptr<DetourNavigator::NavMeshDb>&&)::<lambda()> > /usr/include/c++/13.2.1/bits/vector.tcc:468
    #6 0x55afc1fcd693 in emplace_back<DetourNavigator::AsyncNavMeshUpdater::AsyncNavMeshUpdater(const DetourNavigator::Settings&, DetourNavigator::TileCachedRecastMeshManager&, DetourNavigator::OffMeshConnectionsManager&, std::unique_ptr<DetourNavigator::NavMeshDb>&&)::<lambda()> > /usr/include/c++/13.2.1/bits/vector.tcc:123
    #7 0x55afc1fc51c1 in DetourNavigator::AsyncNavMeshUpdater::AsyncNavMeshUpdater(DetourNavigator::Settings const&, DetourNavigator::TileCachedRecastMeshManager&, DetourNavigator::OffMeshConnectionsManager&, std::unique_ptr<DetourNavigator::NavMeshDb, std::default_delete<DetourNavigator::NavMeshDb> >&&) /home/elsid/dev/openmw/components/detournavigator/asyncnavmeshupdater.cpp:161
    #8 0x55afc20685f5 in DetourNavigator::NavMeshManager::NavMeshManager(DetourNavigator::Settings const&, std::unique_ptr<DetourNavigator::NavMeshDb, std::default_delete<DetourNavigator::NavMeshDb> >&&) /home/elsid/dev/openmw/components/detournavigator/navmeshmanager.cpp:59
    #9 0x55afc203026d in DetourNavigator::NavigatorImpl::NavigatorImpl(DetourNavigator::Settings const&, std::unique_ptr<DetourNavigator::NavMeshDb, std::default_delete<DetourNavigator::NavMeshDb> >&&) /home/elsid/dev/openmw/components/detournavigator/navigatorimpl.cpp:14
    #10 0x55afc2025578 in std::__detail::_MakeUniq<DetourNavigator::NavigatorImpl>::__single_object std::make_unique<DetourNavigator::NavigatorImpl, DetourNavigator::Settings const&, std::unique_ptr<DetourNavigator::NavMeshDb, std::default_delete<DetourNavigator::NavMeshDb> > >(DetourNavigator::Settings const&, std::unique_ptr<DetourNavigator::NavMeshDb, std::default_delete<DetourNavigator::NavMeshDb> >&&) /usr/include/c++/13.2.1/bits/unique_ptr.h:1070
    #11 0x55afc20238d6 in DetourNavigator::makeNavigator(DetourNavigator::Settings const&, std::filesystem::__cxx11::path const&) /home/elsid/dev/openmw/components/detournavigator/navigator.cpp:30
    #12 0x55afbfea574a in MWWorld::World::init(osgViewer::Viewer*, osg::ref_ptr<osg::Group>, SceneUtil::WorkQueue*, SceneUtil::UnrefQueue&) /home/elsid/dev/openmw/apps/openmw/mwworld/worldimp.cpp:302
    #13 0x55afc0b05a25 in OMW::Engine::prepareEngine() /home/elsid/dev/openmw/apps/openmw/engine.cpp:826
    #14 0x55afc0b08147 in OMW::Engine::go() /home/elsid/dev/openmw/apps/openmw/engine.cpp:929
    #15 0x55afc0af071e in runApplication(int, char**) /home/elsid/dev/openmw/apps/openmw/main.cpp:231
    #16 0x55afc1ce6d62 in wrapApplication(int (*)(int, char**), int, char**, std::basic_string_view<char, std::char_traits<char> >) /home/elsid/dev/openmw/components/debug/debugging.cpp:361
    #17 0x55afc0af094d in main /home/elsid/dev/openmw/apps/openmw/main.cpp:243
    #18 0x7efe23758ccf  (/usr/lib/libc.so.6+0x27ccf) (BuildId: 8bfe03f6bf9b6a6e2591babd0bbc266837d8f658)

SUMMARY: AddressSanitizer: stack-buffer-overflow /home/elsid/dev/recastnavigation/build/gcc/asan/install/include/recastnavigation/Recast.h:774 in rcVcopy(float*, float const*)
Shadow bytes around the buggy address:
  0x7efdeabbc000: f1 f1 f1 f1 f1 f1 04 f2 04 f2 04 f2 04 f2 00 f2
  0x7efdeabbc080: f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 04
  0x7efdeabbc100: f2 f2 00 04 f2 f2 00 00 00 00 00 00 00 00 00 00
  0x7efdeabbc180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7efdeabbc200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7efdeabbc280:[f3]f3 f3 f3 f3 f3 f3 f3 00 00 00 00 00 00 00 00
  0x7efdeabbc300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7efdeabbc380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7efdeabbc400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7efdeabbc480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7efdeabbc500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==103277==ABORTING

Here is unit test reproducing the issue: elsid@3e115d7

AddressSanitizer report:

=================================================================
==18517==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x75c481831280 at pc 0x57523532ca07 bp 0x7ffee556b7a0 sp 0x7ffee556b790
WRITE of size 4 at 0x75c481831280 thread T0
    #0 0x57523532ca06 in rcVcopy(float*, float const*) /home/elsid/dev/recastnavigation/Tests/../Recast/Include/Recast.h:774
    #1 0x5752355509ea in dividePoly /home/elsid/dev/recastnavigation/Recast/Source/RecastRasterization.cpp:281
    #2 0x575235551950 in rasterizeTri /home/elsid/dev/recastnavigation/Recast/Source/RecastRasterization.cpp:400
    #3 0x5752355526c9 in rcRasterizeTriangles(rcContext*, float const*, int, int const*, unsigned char const*, int, rcHeightfield&, int) /home/elsid/dev/recastnavigation/Recast/Source/RecastRasterization.cpp:494
    #4 0x575235325137 in CATCH2_INTERNAL_TEST_107 /home/elsid/dev/recastnavigation/Tests/Recast/Tests_Recast.cpp:967
    #5 0x57523539cb50 in invoke /home/elsid/dev/recastnavigation/Tests/Contrib/catch2/catch_amalgamated.cpp:6571
    #6 0x57523540cb60 in Catch::TestCaseHandle::invoke() const /home/elsid/dev/recastnavigation/Tests/Contrib/catch2/catch_all.hpp:7210
    #7 0x575235391215 in Catch::RunContext::invokeActiveTestCase() /home/elsid/dev/recastnavigation/Tests/Contrib/catch2/catch_amalgamated.cpp:5613
    #8 0x575235390a94 in Catch::RunContext::runCurrentTest(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&) /home/elsid/dev/recastnavigation/Tests/Contrib/catch2/catch_amalgamated.cpp:5576
    #9 0x57523538c5d4 in Catch::RunContext::runTest(Catch::TestCaseHandle const&) /home/elsid/dev/recastnavigation/Tests/Contrib/catch2/catch_amalgamated.cpp:5300
    #10 0x575235353fb5 in execute /home/elsid/dev/recastnavigation/Tests/Contrib/catch2/catch_amalgamated.cpp:1102
    #11 0x575235356c7b in Catch::Session::runInternal() /home/elsid/dev/recastnavigation/Tests/Contrib/catch2/catch_amalgamated.cpp:1324
    #12 0x57523535620c in Catch::Session::run() /home/elsid/dev/recastnavigation/Tests/Contrib/catch2/catch_amalgamated.cpp:1255
    #13 0x5752354340fb in int Catch::Session::run<char>(int, char const* const*) /home/elsid/dev/recastnavigation/Tests/Contrib/catch2/catch_all.hpp:5166
    #14 0x575235385106 in main /home/elsid/dev/recastnavigation/Tests/Contrib/catch2/catch_amalgamated.cpp:4450
    #15 0x75c484245ccf  (/usr/lib/libc.so.6+0x27ccf) (BuildId: 8bfe03f6bf9b6a6e2591babd0bbc266837d8f658)
    #16 0x75c484245d89 in __libc_start_main (/usr/lib/libc.so.6+0x27d89) (BuildId: 8bfe03f6bf9b6a6e2591babd0bbc266837d8f658)
    #17 0x5752352a8874 in _start (/home/elsid/dev/recastnavigation/build/gcc/asan/Tests/Tests+0x228874) (BuildId: e00578540157788430dcf2f4edccb9160f408bd1)

Address 0x75c481831280 is located in stack of thread T0 at offset 640 in frame
    #0 0x575235550b22 in rasterizeTri /home/elsid/dev/recastnavigation/Recast/Source/RecastRasterization.cpp:311

  This frame has 11 object(s):
    [48, 52) 'nvRow' (line 351)
    [64, 68) 'nvIn' (line 352)
    [80, 84) 'nv' (line 393)
    [96, 100) 'nv2' (line 394)
    [112, 120) 'in' (line 343)
    [144, 152) 'inRow' (line 344)
    [176, 184) 'p1' (line 345)
    [208, 216) 'p2' (line 346)
    [240, 252) 'triBBMin' (line 313)
    [272, 284) 'triBBMax' (line 318)
    [304, 640) 'buf' (line 342) <== Memory access at offset 640 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /home/elsid/dev/recastnavigation/Tests/../Recast/Include/Recast.h:774 in rcVcopy(float*, float const*)
Shadow bytes around the buggy address:
  0x75c481831000: f1 f1 f1 f1 f1 f1 04 f2 04 f2 04 f2 04 f2 00 f2
  0x75c481831080: f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 04
  0x75c481831100: f2 f2 00 04 f2 f2 00 00 00 00 00 00 00 00 00 00
  0x75c481831180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x75c481831200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x75c481831280:[f3]f3 f3 f3 f3 f3 f3 f3 00 00 00 00 00 00 00 00
  0x75c481831300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x75c481831380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x75c481831400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x75c481831480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x75c481831500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==18517==ABORTING

It seems like this is related to the floating point limitations. 7228336 used for input is >= (1 << 22) in other words 23 significant bits are required for the fraction part and it's a borderline for the 32-bit float. If I add tests to use values starting with 1 << 21 and with 1 << 22, first one passes and second one leads to crash. In 1 << 22 case and the original one this expression gives subsequently the same result for some iterations and all different for 1 << 21:

SECTION("22 significant bits")
{
	const int shift = 21;
	rcContext ctx;
	const float verts[] = {
		static_cast<float>(1 << shift), -3.7455883f, static_cast<float>(1 << shift),
		static_cast<float>(1 << shift), -3.7455883f, static_cast<float>(1 << shift) + 32,
		static_cast<float>(1 << shift) + 32, -3.7455883f, static_cast<float>(1 << shift) + 32,
		static_cast<float>(1 << shift) + 32, -3.7455883f, static_cast<float>(1 << shift)
	};
	const int numVerts = 4;
	const int tris[] = {
		0, 1, 2,
		0, 2, 3
	};
	const unsigned char triAreaIDs[] = {1, 2};
	const int numTris = 2;
	const float bmin[3] = {static_cast<float>(1 << shift), -60.2352943f,static_cast<float>(1 << shift)};
	const float bmax[3] = {static_cast<float>(1 << shift) + 32, 0.0f, static_cast<float>(1 << shift) + 32};
	const float cellSize = 0.200000003f;
	const float cellHeight = 0.200000003f;
	const int width = 160;
	const int height = 160;
	rcHeightfield solid;
	REQUIRE(rcCreateHeightfield(&ctx, solid, width, height, bmin, bmax, cellSize, cellHeight));

	const int flagMergeThreshold = 1;
	REQUIRE(rcRasterizeTriangles(&ctx, verts, numVerts, tris, triAreaIDs, numTris, solid, flagMergeThreshold));
}