[Python] Crash during zones fill after unfilling them

I need to hide the zones and then restore them again, so my code looks like this:

import pcbnew

def HideAndShowZones(id):
   # Look for all zones using this layer and unfill them
   zones = pcbnew.ZONES()
   print("Unfilling zones containing "+str(id))
   for e in list(board.Zones()):
       layers = e.GetLayerSet()
       if layers.Contains(id):
           zones.append(e)
           e.UnFill()
   # Refill the affected zones
   if len(zones):
       print("Filling unfilled zones")
       pcbnew.ZONE_FILLER(board).Fill(zones)
       print("Finished filling zones")
   print("\n\n")


board = pcbnew.LoadBoard('test.kicad_pcb')
# The order is important
HideAndShowZones(pcbnew.F_Cu)
# If we do it for the same layer no SIGSEGV is observed
HideAndShowZones(pcbnew.B_Cu)

This usually works, but a user found a case where you get a Segment Violation.

The board is quite complex
test.zip (1.3 MB)

And crashes using KiCad 6.0.11 or 7.0.0.

Using KiCad 7 I was able to reduce the board to just this:
test.zip (2.2 KB)

But I suspect this small version won’t crash all systems.

I’m not sure if this is a bug or I’m doing something that isn’t supposed to be done.

Note that it works for tons of PCBs, but not for this one.

Sounds like a bug to me, but probably one that can only be hit through using Python scripting. It’s still worth reporting, though.

1 Like

I’ve seen weird bugs with method chaining like this. Python GC is confused about swig objects lifetime sometimes. See if assigning filler to a variable helps.

1 Like

I saw strange things too, the GS.board.GetBoundingBox().GetSize() doesn’t work. Thanks.

I tried:

        zf = pcbnew.ZONE_FILLER(board)
        zf.Fill(zones)

And it also crashed.

Can you run it under gdb and post the backtrace after the crash?

Running it under gdb I’m getting:

Thread 7 "python3" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffe8bde700 (LWP 693084)]
CN_VISITOR::checkZoneZoneConnection (this=this@entry=0x7fffe8bddd38, aZoneLayerA=<optimized out>, aZoneLayerB=aZoneLayerB@entry=0x1afa870)
    at /..../pcbnew/connectivity/connectivity_algo.cpp:823
823	    for( int i = 0; i < outline2.PointCount(); i++ )

The backtrace is:

#0  CN_VISITOR::checkZoneZoneConnection(CN_ZONE_LAYER*, CN_ZONE_LAYER*) (this=this@entry=0x7fffe8bddd38, aZoneLayerA=<optimized out>, aZoneLayerB=aZoneLayerB@entry=0x1afa870)
    at /..../pcbnew/connectivity/connectivity_algo.cpp:823
#1  0x00007ffff58d2a32 in CN_VISITOR::operator()(CN_ITEM*) (this=this@entry=0x7fffe8bddd38, aCandidate=0x1afa870)
    at /..../pcbnew/connectivity/connectivity_algo.cpp:862
#2  0x00007ffff58d325d in RTree<CN_ITEM*, int, 3, double, 8, 4>::Search<CN_VISITOR>(RTree<CN_ITEM*, int, 3, double, 8, 4>::Node const*, RTree<CN_ITEM*, int, 3, double, 8, 4>::Rect const*, CN_VISITOR&, int&) const (this=<optimized out>, a_foundCount=<optimized out>, a_visitor=<optimized out>, a_rect=<optimized out>, a_node=<optimized out>)
    at /..../thirdparty/rtree/geometry/rtree.h:595
#3  RTree<CN_ITEM*, int, 3, double, 8, 4>::Search<CN_VISITOR>(RTree<CN_ITEM*, int, 3, double, 8, 4>::Node const*, RTree<CN_ITEM*, int, 3, double, 8, 4>::Rect const*, CN_VISITOR&, int&) const (a_node=0x1adc820, a_rect=a_rect@entry=0x7fffe8bddd40, a_visitor=..., a_foundCount=@0x7fffe8bddd34: 1, this=<optimized out>)
    at /..../thirdparty/rtree/geometry/rtree.h:568
#4  0x00007ffff58d337f in RTree<CN_ITEM*, int, 3, double, 8, 4>::Search<CN_VISITOR>(RTree<CN_ITEM*, int, 3, double, 8, 4>::Node const*, RTree<CN_ITEM*, int, 3, double, 8, 4>::Rect const*, CN_VISITOR&, int&) const (this=<optimized out>, a_foundCount=@0x7fffe8bddd34: 1, a_visitor=..., a_rect=0x7fffe8bddd40, a_node=0x1b0b070)
    at /..../thirdparty/rtree/geometry/rtree.h:580
#5  RTree<CN_ITEM*, int, 3, double, 8, 4>::Search<CN_VISITOR>(int const*, int const*, CN_VISITOR&) const
    (a_visitor=..., a_max=<synthetic pointer>, a_min=<synthetic pointer>, this=<optimized out>) at /..../thirdparty/rtree/geometry/rtree.h:203
#6  CN_RTREE<CN_ITEM*>::Query<CN_VISITOR>(BOX2<VECTOR2<int> > const&, LAYER_RANGE const&, CN_VISITOR&) const
    (this=<optimized out>, aBounds=<optimized out>, aRange=<optimized out>, this=0x7fffe8bddd6c, aBounds=<optimized out>, aRange=<optimized out>, aVisitor=...)
    at /..../pcbnew/connectivity/../connectivity/connectivity_rtree.h:115
#7  CN_LIST::FindNearby<CN_VISITOR>(CN_ITEM*, CN_VISITOR) (aFunc=..., aItem=<optimized out>, this=0x7fffe8bddd4c)
    at /..../pcbnew/connectivity/../connectivity/connectivity_items.h:438
#8  operator() (aReporter=0x0, aItemList=0x7fffe8bddd4c, aItem=<optimized out>, __closure=<optimized out>) at /..../pcbnew/connectivity/connectivity_algo.cpp:254
#9  std::__invoke_impl<long unsigned int, CN_CONNECTIVITY_ALGO::searchConnections()::<lambda(size_t, CN_LIST*, PROGRESS_REPORTER*)>&, long unsigned int&, CN_LIST*&, PROGRESS_REPORTER*&>
    (__f=<optimized out>) at /usr/include/c++/10/bits/invoke.h:60
#10 std::__invoke<CN_CONNECTIVITY_ALGO::searchConnections()::<lambda(size_t, CN_LIST*, PROGRESS_REPORTER*)>&, long unsigned int&, CN_LIST*&, PROGRESS_REPORTER*&> (__fn=<optimized out>)
    at /usr/include/c++/10/bits/invoke.h:95
#11 std::_Bind<CN_CONNECTIVITY_ALGO::searchConnections()::<lambda(size_t, CN_LIST*, PROGRESS_REPORTER*)>(long unsigned int, CN_LIST*, PROGRESS_REPORTER*)>::__call<unsigned long, 0, 1, 2>
    (__args=<optimized out>, this=<optimized out>) at /usr/include/c++/10/functional:416
#12 std::_Bind<CN_CONNECTIVITY_ALGO::searchConnections()::<lambda(size_t, CN_LIST*, PROGRESS_REPORTER*)>(long unsigned int, CN_LIST*, PROGRESS_REPORTER*)>::operator()<>
    (this=<optimized out>) at /usr/include/c++/10/functional:499
#13 std::__invoke_impl<long unsigned int, std::_Bind<CN_CONNECTIVITY_ALGO::searchConnections()::<lambda(size_t, CN_LIST*, PROGRESS_REPORTER*)>(long unsigned int, CN_LIST*, PROGRESS_REPORTER*)>&> (__f=<optimized out>) at /usr/include/c++/10/bits/invoke.h:60
#14 std::__invoke_r<long unsigned int, std::_Bind<CN_CONNECTIVITY_ALGO::searchConnections()::<lambda(size_t, CN_LIST*, PROGRESS_REPORTER*)>(long unsigned int, CN_LIST*, PROGRESS_REPORTER*)>&> (__fn=<optimized out>) at /usr/include/c++/10/bits/invoke.h:113
#15 std::_Function_handler<long unsigned int(), std::_Bind<CN_CONNECTIVITY_ALGO::searchConnections()::<lambda(size_t, CN_LIST*, PROGRESS_REPORTER*)>(long unsigned int, CN_LIST*, PROGRESS_REPORTER*)> >::_M_invoke(const std::_Any_data &) (__functor=<optimized out>) at /usr/include/c++/10/bits/std_function.h:291
#16 0x00007ffff58d34a5 in std::function<unsigned long ()>::operator()() const (this=0x1b096f0) at /usr/include/c++/10/bits/std_function.h:622
#17 std::__invoke_impl<unsigned long, std::function<unsigned long ()> const&>(std::__invoke_other, std::function<unsigned long ()> const&) (__f=...) at /usr/include/c++/10/bits/invoke.h:60
#18 std::__invoke<std::function<unsigned long ()> const&>(std::function<unsigned long ()> const&) (__fn=...) at /usr/include/c++/10/bits/invoke.h:95
#19 std::invoke<std::function<unsigned long ()> const&>(std::function<unsigned long ()> const&) (__fn=...) at /usr/include/c++/10/functional:88
#20 operator() (this=0x1b096f0) at /..../thirdparty/thread-pool/bs_thread_pool.hpp:481
#21 std::__invoke_impl<void, BS::thread_pool::submit<CN_CONNECTIVITY_ALGO::searchConnections()::<lambda(size_t, CN_LIST*, PROGRESS_REPORTER*)>&, {long unsigned int&, CN_LIST*, PROGRESS_REPORTER*&}, long unsigned int>::<lambda()>&> (__f=...) at /usr/include/c++/10/bits/invoke.h:60
#22 std::__invoke<BS::thread_pool::submit<CN_CONNECTIVITY_ALGO::searchConnections()::<lambda(size_t, CN_LIST*, PROGRESS_REPORTER*)>&, {long unsigned int&, CN_LIST*, PROGRESS_REPORTER*&}, long unsigned int>::<lambda()>&> (__fn=...) at /usr/include/c++/10/bits/invoke.h:95
#23 std::_Bind<BS::thread_pool::submit<CN_CONNECTIVITY_ALGO::searchConnections()::<lambda(size_t, CN_LIST*, PROGRESS_REPORTER*)>&, {long unsigned int&, CN_LIST*, PROGRESS_REPORTER*&}, long unsigned int>::<lambda()>()>::__call<void> (__args=<optimized out>, this=0x1b096f0) at /usr/include/c++/10/functional:416
#24 std::_Bind<BS::thread_pool::submit<CN_CONNECTIVITY_ALGO::searchConnections()::<lambda(size_t, CN_LIST*, PROGRESS_REPORTER*)>&, {long unsigned int&, CN_LIST*, PROGRESS_REPORTER*&}, long unsigned int>::<lambda()>()>::operator()<> (this=0x1b096f0) at /usr/include/c++/10/functional:499
#25 std::__invoke_impl<void, std::_Bind<BS::thread_pool::submit<CN_CONNECTIVITY_ALGO::searchConnections()::<lambda(size_t, CN_LIST*, PROGRESS_REPORTER*)>&, {long unsigned int&, CN_LIST*, PROGRESS_REPORTER*&}, long unsigned int>::<lambda()>()>&> (__f=...) at /usr/include/c++/10/bits/invoke.h:60
#26 std::__invoke_r<void, std::_Bind<BS::thread_pool::submit<CN_CONNECTIVITY_ALGO::searchConnections()::<lambda(size_t, CN_LIST*, PROGRESS_REPORTER*)>&, {long unsigned int&, CN_LIST*, PROGRE--Type <RET> for more, q to quit, c to continue without paging--
SS_REPORTER*&}, long unsigned int>::<lambda()>()>&> (__fn=...) at /usr/include/c++/10/bits/invoke.h:110
#27 std::_Function_handler<void(), std::_Bind<BS::thread_pool::submit<CN_CONNECTIVITY_ALGO::searchConnections()::<lambda(size_t, CN_LIST*, PROGRESS_REPORTER*)>&, {long unsigned int&, CN_LIST*, PROGRESS_REPORTER*&}, long unsigned int>::<lambda()>()> >::_M_invoke(const std::_Any_data &) (__functor=<optimized out>) at /usr/include/c++/10/bits/std_function.h:291
#28 0x00007ffff625d38b in std::function<void ()>::operator()() const (this=0x7fffe8bdde60) at /usr/include/c++/10/bits/std_function.h:622
#29 BS::thread_pool::worker() (this=0x1af3ca0) at /..../thirdparty/thread-pool/bs_thread_pool.hpp:581
#30 0x00007ffff0252ed0 in  () at /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#31 0x00007ffff7f6fea7 in start_thread (arg=<optimized out>) at pthread_create.c:477
#32 0x00007ffff7cf2a2f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

Looking at the values the problem seems to be that zoneB->GetFilledPolysList( layer )->m_polys[1] is empty.

So outline2 is a null pointer (zoneB->GetFilledPolysList( layer )->COutline( aZoneLayerB->SubpolyIndex() ) is zoneB->GetFilledPolysList( layer )->m_polys[1][0] which is 0)

Ok, I found the problem. Is in a comment of the ZONE_FILLER::Fill.

You must call board.BuildConnectivity() after filling zones.

3 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.