Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dividePoly crashes on the attempt to add 8th point #687

Open
elsid opened this issue Jan 28, 2024 · 2 comments
Open

dividePoly crashes on the attempt to add 8th point #687

elsid opened this issue Jan 28, 2024 · 2 comments

Comments

@elsid
Copy link
Contributor

elsid commented Jan 28, 2024

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
@elsid
Copy link
Contributor Author

elsid commented Jan 30, 2024

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

@elsid
Copy link
Contributor Author

elsid commented Jan 30, 2024

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));
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants