Asynchronous Multicast Delegates in C++

 codeproject.com  4/22/2017 12:06:00 AM 
Hi Dave, Looks like a great library. I'm running into a few issues that I'd like to report.

Crashes on Win10 + Ubuntu (Release mode)

Not sure what's going on here, but when I build in debug mode, running 'main' completes with no issues. However, if I run in release mode, the program crashes. It has something to do with the (**i) on this line:
void MemberFuncThreeArgs(const TestStruct& value, float f, int** i)
{ cout << "MemberFuncThreeArgs " << value.x << " " << f << " " << (**i) << endl;
}
I've tried this on Win10 and on Ubuntu 16.04 (both 64 bit machines), and both work fine in debug mode but crash when doing a release build. The stack trace on Windows is something like (according to VS2015):
TestClass::MemberFuncThreeArgs(const TestStruct & value, float f, int **i) Line 133
DelegateLib::DelegateMemberAsync3<TestClass, TestStruct const&, float, int**>::DelegateInvoke(DelegateLib::DelegateMsgBase** msg) Line 396
WorkerThread::Process() Line 128
On Ubuntu, running 'main' (release build) shows this:
$ ./main
FreeFuncInt 123
MemberFunc 123
MemberFunc 123
FreeFuncInt 123
MemberFunc 123
FreeFuncPtrPtrTestStruct 123
MemberFunc 123
MemberFuncThreeArgs 123 1.23 4209168
*** Error in `./main': free(): invalid pointer: 0x0000000000465188 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f409bf3b7e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x7fe0a)[0x7f409bf43e0a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f409bf4798c]
./main[0x403fdb]
./main[0x462d84]
/usr/lib/x86_64-linux-gnu/libstdc++.so.6(+0xb8c80)[0x7f409c55bc80]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x76ba)[0x7f409c82c6ba]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x6d)[0x7f409bfca82d]
======= Memory map: ========
~~~ snip ~~~
Other than the few notes I make below, I haven't modified the source. It is fair to assume that both debug and release targets should behave the same (i.e. not crash)? I'm wondering what is special about the release builds on both platforms. Is there an optimization bug happening?

Capitalization note:

Delegate/xallocator.cpp, line 1 should read:
#include "Allocator.h"
and not
#include "allocator.h"
The capitalization matters on *nix systems.

Visual Studio 2015 Release Configuration

Note that the Visual Studio 2015 "Release" configuration is missing a few Additonal Include Directories, which are present in the "Debug" config:
$(SolutionDir)..\.
$(SolutionDir)..\Examples
$(SolutionDir)..\Delegate
$(SolutionDir)..\Port

Valgrind output (Ubuntu) RELEASE

$ valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./main
==32562== Memcheck, a memory error detector
==32562== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==32562== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==32562== Command: ./main
==32562== FreeFuncInt 123
MemberFunc 123
MemberFunc 123
FreeFuncInt 123
MemberFunc 123
FreeFuncPtrPtrTestStruct 123
MemberFunc 123
MemberFuncThreeArgs 123 1.23 4209168
==32562== Thread 2:
==32562== Invalid free() / delete / delete[] / realloc()
==32562== at 0x4C2F24B: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==32562== by 0x403FDA: DelegateLib::DelegateMemberAsync3<TestClass, TestStruct const&, float, int**>::DelegateInvoke(DelegateLib::DelegateMsgBase**) (in /home/matty/Documents/dev/thirdparty-delegate/AsyncMulticastDelegate/release/main)
==32562== by 0x462D83: WorkerThread::Process() (in /home/matty/Documents/dev/thirdparty-delegate/AsyncMulticastDelegate/release/main)
==32562== by 0x510FC7F: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==32562== by 0x4E416B9: start_thread (pthread_create.c:333)
==32562== by 0x56F582C: clone (clone.S:109)
==32562== Address 0x465188 is 16 bytes inside data symbol "_ZTVN11DelegateLib20DelegateMemberAsync2I9TestClassRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEiEE"
==32562== MemberFuncNoCopy 999
MemberFuncStdString Hello world 2016
Hello world 2016
MemberFuncStdString Hello world using shared_ptr 2016
MemberFuncStdString Function async invoked on deleted object. Bug! 2016
MemberFuncStdString Function async invoked using smart pointer. Bug solved! 2016
CallbackFunction 0
CallbackFunction 1
CallbackFunction 2
CallbackFunction 3
CallbackFunction 2
CallbackFunction 3
CallbackFunction 0
CallbackFunction 1
==32562== ==32562== HEAP SUMMARY:
==32562== in use at exit: 72,708 bytes in 2 blocks
==32562== total heap usage: 513,062 allocs, 513,061 frees, 35,533,562 bytes allocated
==32562== ==32562== Thread 1:
==32562== 4 bytes in 1 blocks are definitely lost in loss record 1 of 2
==32562== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==32562== by 0x404F52: DelegateLib::DelegateMemberAsync3<TestClass, TestStruct const&, float, int**>::operator()(TestStruct const&, float, int**) (in /home/matty/Documents/dev/thirdparty-delegate/AsyncMulticastDelegate/release/main)
==32562== by 0x401EC4: main (in /home/matty/Documents/dev/thirdparty-delegate/AsyncMulticastDelegate/release/main)
==32562== ==32562== 72,704 bytes in 1 blocks are still reachable in loss record 2 of 2
==32562== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==32562== by 0x50E0EFF: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==32562== by 0x40104E9: call_init.part.0 (dl-init.c:72)
==32562== by 0x40105FA: call_init (dl-init.c:30)
==32562== by 0x40105FA: _dl_init (dl-init.c:120)
==32562== by 0x4000CF9: ??? (in /lib/x86_64-linux-gnu/ld-2.23.so)
==32562== ==32562== LEAK SUMMARY:
==32562== definitely lost: 4 bytes in 1 blocks
==32562== indirectly lost: 0 bytes in 0 blocks
==32562== possibly lost: 0 bytes in 0 blocks
==32562== still reachable: 72,704 bytes in 1 blocks
==32562== suppressed: 0 bytes in 0 blocks
==32562== ==32562== For counts of detected and suppressed errors, rerun with: -v
==32562== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

Valgrind output (Ubuntu) DEBUG

$ valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./main
==33117== Memcheck, a memory error detector
==33117== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==33117== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==33117== Command: ./main
==33117== FreeFuncInt 123
MemberFunc 123
MemberFunc 123
FreeFuncInt 123
MemberFunc 123
FreeFuncPtrPtrTestStruct 123
MemberFunc 123
MemberFuncThreeArgs 123 1.23 555
MemberFuncNoCopy 999
MemberFuncStdString Hello world 2016
Hello world 2016
MemberFuncStdString Hello world using shared_ptr 2016
MemberFuncStdString Function async invoked on deleted object. Bug! 2016
MemberFuncStdString Function async invoked using smart pointer. Bug solved! 2016
CallbackFunction 0
CallbackFunction 1
CallbackFunction 2
CallbackFunction 3
CallbackFunction 2
CallbackFunction 3
CallbackFunction 0
CallbackFunction 1
==33117== ==33117== HEAP SUMMARY:
==33117== in use at exit: 72,704 bytes in 1 blocks
==33117== total heap usage: 513,062 allocs, 513,061 frees, 35,533,562 bytes allocated
==33117== ==33117== 72,704 bytes in 1 blocks are still reachable in loss record 1 of 1
==33117== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==33117== by 0x50E0EFF: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==33117== by 0x40104E9: call_init.part.0 (dl-init.c:72)
==33117== by 0x40105FA: call_init (dl-init.c:30)
==33117== by 0x40105FA: _dl_init (dl-init.c:120)
==33117== by 0x4000CF9: ??? (in /lib/x86_64-linux-gnu/ld-2.23.so)
==33117== ==33117== LEAK SUMMARY:
==33117== definitely lost: 0 bytes in 0 blocks
==33117== indirectly lost: 0 bytes in 0 blocks
==33117== possibly lost: 0 bytes in 0 blocks
==33117== still reachable: 72,704 bytes in 1 blocks
==33117== suppressed: 0 bytes in 0 blocks
==33117== ==33117== For counts of detected and suppressed errors, rerun with: -v
==33117== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

« Go back