Handle duplicate TypeId registration issue more gracefully
This is a spin-off of the conversation we had on MR !1027 (comment 1031357534).
Currently, a duplicate TypeId registration results in an assert
assert failed. cond="m_namemap.count (name) == 0", msg="Trying to allocate twice the same uid: ns3::CounterCalculator<uint32_t>", +0.000000000s -1 file=H:/tools/source/ns-3-dev/src/core/model/type-id.cc, line=387
However, it is not clear why does this happen, where does it happen and how it can be fixed.
Using stacktrace, we can trace back where the TypeId registration for each duplicated template instance came from:
H:\tools\source\ns-3-dev\build\examples\stats\ns3-dev-wifi-example-sim-debug.exe
0# 0x00007FFCD939620C in H:\tools\source\ns-3-dev\build\lib\libns3-dev-core-debug.dll
1# 0x00007FFCD92EF6A0 in H:\tools\source\ns-3-dev\build\lib\libns3-dev-core-debug.dll
2# 0x00007FFCD92F791C in H:\tools\source\ns-3-dev\build\lib\libns3-dev-core-debug.dll
3# 0x00007FF7D7A7FB11 in H:\tools\source\ns-3-dev\build\examples\stats\ns3-dev-wifi-example-sim-debug.exe # << directly from the wifi-example-sim.cc file
4# 0x00007FF7D7A7F5C3 in H:\tools\source\ns-3-dev\build\examples\stats\ns3-dev-wifi-example-sim-debug.exe
5# 0x00007FF7D7A7D60F in H:\tools\source\ns-3-dev\build\examples\stats\ns3-dev-wifi-example-sim-debug.exe
6# 0x00007FF7D7A7311F in H:\tools\source\ns-3-dev\build\examples\stats\ns3-dev-wifi-example-sim-debug.exe
7# 0x00007FF7D7A713AE in H:\tools\source\ns-3-dev\build\examples\stats\ns3-dev-wifi-example-sim-debug.exe
8# 0x00007FF7D7A714E6 in H:\tools\source\ns-3-dev\build\examples\stats\ns3-dev-wifi-example-sim-debug.exe
9# 0x00007FFD59EE7034 in C:\Windows\System32\KERNEL32.DLL
10# 0x00007FFD5ABC2651 in C:\Windows\SYSTEM32\ntdll.dll
0# 0x00007FFCD939620C in H:\tools\source\ns-3-dev\build\lib\libns3-dev-core-debug.dll
1# 0x00007FFCD92EF6A0 in H:\tools\source\ns-3-dev\build\lib\libns3-dev-core-debug.dll
2# 0x00007FFCD92F791C in H:\tools\source\ns-3-dev\build\lib\libns3-dev-core-debug.dll
3# 0x00007FFCDBCBD581 in H:\tools\source\ns-3-dev\build\lib\libns3-dev-network-debug.dll # << indirectly from the PacketCounterCalculator
4# 0x00007FFCDBCD956F in H:\tools\source\ns-3-dev\build\lib\libns3-dev-network-debug.dll
5# 0x00007FFCDBC56B77 in H:\tools\source\ns-3-dev\build\lib\libns3-dev-network-debug.dll
6# 0x00007FF7D7A7F803 in H:\tools\source\ns-3-dev\build\examples\stats\ns3-dev-wifi-example-sim-debug.exe
7# 0x00007FF7D7A7D75F in H:\tools\source\ns-3-dev\build\examples\stats\ns3-dev-wifi-example-sim-debug.exe
8# 0x00007FF7D7A73302 in H:\tools\source\ns-3-dev\build\examples\stats\ns3-dev-wifi-example-sim-debug.exe
9# 0x00007FF7D7A713AE in H:\tools\source\ns-3-dev\build\examples\stats\ns3-dev-wifi-example-sim-debug.exe
10# 0x00007FF7D7A714E6 in H:\tools\source\ns-3-dev\build\examples\stats\ns3-dev-wifi-example-sim-debug.exe
11# 0x00007FFD59EE7034 in C:\Windows\System32\KERNEL32.DLL
12# 0x00007FFD5ABC2651 in C:\Windows\SYSTEM32\ntdll.dll
Now we know it happened because both the program and the DLL have their own template instances for CounterCalculator<uint32_t>.
The problem is usually handled by exporting the template declaration in the header and performing the template instantiation in a source file, which guarantees only one instance of the template exists.
//.h file
namespace ns3
{
extern template class CounterCalculator<uint32_t>;
}
//.cc file
#include <ns3/.h file>
namespace ns3
{
NS_OBJECT_TEMPLATE_CLASS_DEFINE (CounterCalculator, uint32_t);
}
Not sure if we should document that, or include stack-tracing for debugging (as shown in the example), or try to handle duplicate TypeId's by returning the first registered (which could cause problems if class/instance members are accessed directly, since the unregistered instance can be used by mistake).