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

Trouble with nested connections #24

Open
stevenlovegrove opened this issue Sep 8, 2021 · 0 comments
Open

Trouble with nested connections #24

stevenlovegrove opened this issue Sep 8, 2021 · 0 comments

Comments

@stevenlovegrove
Copy link

Safe Recursion and Modification While Iterating

Based on your README, I think the code snippet below is meant to work, but I'm encountering some kind of stack corruption or memory invalidation or something when running (it's causing allocation of a really large value (probably from uninitialized memory). I'm seeing similar behaviour in my own program which I've tried to recreate in this minimal test case.

#include <iostream>
#include <signals/signals.hpp>

int main( int /*argc*/, char** /*argv*/ )
{
    fteng::signal<void(void)> test;

    test.connect([&test](){
        std::cout << "A" << std::endl;
        test.connect([&test](){std::cout << "B" << std::endl;});
        test.connect([&test](){std::cout << "C" << std::endl;});
    });

    std::cout << "=============" << std::endl;
    test();
    std::cout << "=============" << std::endl;
    test();

    return 0;
}

Outputs:

=============
A
libc++abi: terminating with uncaught exception of type std::bad_alloc: std::bad_alloc

1  __pthread_kill                                                                                                                                                                                      (x86_64) /usr/lib/system/libsystem_kernel.dylib       0x7fff2049392e 
2  pthread_kill                                                                                                                                                                                        (x86_64) /usr/lib/system/libsystem_pthread.dylib      0x7fff204c25bd 
3  abort                                                                                                                                                                                               (x86_64) /usr/lib/system/libsystem_c.dylib            0x7fff20417411 
4  abort_message                                                                                                                                                                                       (x86_64) /usr/lib/libc++abi.dylib                     0x7fff20485ef2 
5  demangling_terminate_handler()                                                                                                                                                                      (x86_64) /usr/lib/libc++abi.dylib                     0x7fff204775e5 
6  _objc_terminate()                                                                                                                                                                                   (x86_64h) /usr/lib/libobjc.A.dylib                    0x7fff20370595 
7  std::__terminate(void ( *)())                                                                                                                                                                       (x86_64) /usr/lib/libc++abi.dylib                     0x7fff20485307 
8  __cxxabiv1::failed_throw(__cxxabiv1::__cxa_exception *)                                                                                                                                             (x86_64) /usr/lib/libc++abi.dylib                     0x7fff20487beb 
9  __cxa_throw                                                                                                                                                                                         (x86_64) /usr/lib/libc++abi.dylib                     0x7fff20487bb2 
10 operator new(unsigned long)                                                                                                                                                                         (x86_64) /usr/lib/libc++abi.dylib                     0x7fff2048786f 
11 std::__libcpp_allocate(unsigned long, unsigned long)                                                                                                                                                new                                              253  0x1000096cd    
12 std::allocator<fteng::details::sig_base::call>::allocate(unsigned long)                                                                                                                             memory                                           1664 0x100009615    
13 std::allocator_traits<std::allocator<fteng::details::sig_base::call>>::allocate(std::allocator<fteng::details::sig_base::call>&, unsigned long)                                                     memory                                           1400 0x1000094ad    
14 std::__split_buffer<fteng::details::sig_base::call, std::allocator<fteng::details::sig_base::call>&>::__split_buffer(unsigned long, unsigned long, std::allocator<fteng::details::sig_base::call>&) __split_buffer                                   318  0x100009402    
15 std::__split_buffer<fteng::details::sig_base::call, std::allocator<fteng::details::sig_base::call>&>::__split_buffer(unsigned long, unsigned long, std::allocator<fteng::details::sig_base::call>&) __split_buffer                                   317  0x10000900d    
16 void std::vector<fteng::details::sig_base::call>::__emplace_back_slow_path<>()                                                                                                                      vector                                           1668 0x100008d39    
17 fteng::details::sig_base::call& std::vector<fteng::details::sig_base::call>::emplace_back<>()                                                                                                       vector                                           1690 0x100008b2b    
18 fteng::connection_raw fteng::signal<void ()>::connect<main::$_0::operator()() const::'lambda0'()>(main::$_0::operator()() const::'lambda0'()&&) const                                               signals.hpp                                      307  0x100009d57    
19 main::$_0::operator()() const                                                                                                                                                                       main.cpp                                         11   0x100009c0f    
20 fteng::connection_raw fteng::signal<void ()>::connect<main::$_0>(main::$_0&&) const::'lambda'(void *)::operator()(void *) const                                                                     signals.hpp                                      308  0x100009b8c    
21 fteng::connection_raw fteng::signal<void ()>::connect<main::$_0>(main::$_0&&) const::'lambda'(void *)::__invoke(void *)                                                                             signals.hpp                                      308  0x100009b65    
22 void fteng::signal<void ()>::operator()<>() const                                                                                                                                                   signals.hpp                                      229  0x100006c6a    
23 main                                                                                                                                                                                                main.cpp                                         15   0x100006948    
24 start                                                                                                                                                                                               (x86_64) /usr/lib/system/libdyld.dylib                0x7fff204ddf5d 

Originally I thought there was some issue with the scope of the lambda related to #20 but I see the same on the PR that was raised against that issue (https://github.com/mikezackles/signals/tree/issue-20) or when using a simple functor:

void method_B() { std::cout << "B" << std::endl; }
void method_C() { std::cout << "C" << std::endl; }

int main( int /*argc*/, char** /*argv*/ )
{
    fteng::signal<void(void)> test;

    test.connect([&test](){
        std::cout << "A" << std::endl;
        test.connect(method_B);
        test.connect(method_C);
    });

    std::cout << "=============" << std::endl;
    test();
    std::cout << "=============" << std::endl;
    test();

    return 0;
}

If I comment out the last connection (of the C printout) then I see what might be considered expected output:

=============
A
=============
A
B

Though depending on how the iteration is implemented I might have expected the first invocation to print A\nB and the second to print A\nB\nB (especially since the loop looks like for (size_t i = 0, n = calls.size(); i < n; ++i) in operator().

I've not been able to figure out what is going wrong - I can't see any iterators getting invalidated or something with the recursive modification...

Any thoughts appreciated!

stevenlovegrove added a commit to stevenlovegrove/Pangolin that referenced this issue Sep 9, 2021
Support Var removal

replace signal/slot library due to problems with original (TheWisp/signals#24)

Use signal/slots for Var add/removes

Extensive extra testing
stevenlovegrove added a commit to stevenlovegrove/Pangolin that referenced this issue Sep 9, 2021
Support Var removal

replace signal/slot library due to problems with original (TheWisp/signals#24)

Use signal/slots for Var add/removes

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

No branches or pull requests

1 participant