With -O1 and higher, the test of atomic_exchange_explicit() doesn't work right for 64-bit variables
on i386 (and possibly other 32-bit architectures). It seems that atomic_exchange_explicit() doesn't
exchange 64-bit values properly when it's used in a loop and GCC compiler optimization is turned
on. As a workaround, we are testing ATOMIC_XCHG on a pointer size of the given architecture.
It isn't sure yet, if atomic_exchange_explicit() is safe for 64-bit variables with GCC on i386 when
not used in a loop. Therefore, ATOMIC_XCHG should not be used on general 64-bit variables until
this GCC bug is solved.
Clang and gcc -O0 don't seem to be affected by this issue.
In some build environments it may not be possible to bind to ::1. Bind
to INADDR_LOOPBACK instead, which prevents this test suite from failing
or crashing.
This commit removes the assert() in _sync() and propagates the error to
the caller.
It was possible for the test_dns_tcp() test to set up an invalid socket
descriptor and not notice that the socket was not usable, which would
cause socket reads to fail, which would trigger the assert. This can
occur in some CI environments where IPv6 networking is not available.
These tests should probably just fail instead of crashing the build.
Here is what the strace output looked like when this test asserted:
write(1, "# DNS messages over TCP\n", 24) = 24
socket(PF_INET6, SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_IP) = 3
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
setsockopt(3, SOL_IPV6, IPV6_V6ONLY, [1], 4) = 0
bind(3, {sa_family=AF_INET6, sin6_port=htons(0), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = -1 EADDRNOTAVAIL (Cannot assign requested address)
close(3) = 0
write(1, "not ok 1 - single DNS, server, create socket\n", 45) = 45
listen(-99, 5) = -1 EBADF (Bad file descriptor)
write(1, "not ok 2 - single DNS, server, start listening\n", 47) = 47
mmap(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f340dc41000
mprotect(0x7f340dc41000, 4096, PROT_NONE) = 0
clone(child_stack=0x7f340e440ff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f340e4419d0, tls=0x7f340e441700, child_tidptr=0x7f340e4419d0) = 80049
write(1, "ok 3 - single DNS, server, start handler\n", 41) = 41
getsockname(-99, 0x7fffc7378760, 0x7fffc737867c) = -1 EBADF (Bad file descriptor)
write(1, "not ok 4 - check getsockname return\n", 36) = 36
socket(PF_UNSPEC, SOCK_STREAM|SOCK_NONBLOCK, 0) = -1 EAFNOSUPPORT (Address family not supported by protocol)
write(1, "not ok 5 - single DNS, client, create connected socket\n", 55) = 55
write(2, "test_net: contrib/test_net.c:410: _sync: Assertion `r == sizeof(buf)' failed.\n", 78) = 78
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f340ec4d000
rt_sigprocmask(SIG_UNBLOCK, [ABRT], NULL, 8) = 0
tgkill(80048, 80048, SIGABRT) = 0
--- SIGABRT {si_signo=SIGABRT, si_code=SI_TKILL, si_pid=80048, si_uid=0} ---
+++ killed by SIGABRT (core dumped) +++
(I commented out all of the test_*() calls in main() except the call to
test_dns_tcp(), so the test numbering on stdout is off.)
This keeps the test_net program from assert()'ing on IPv4-only and
IPv4/IPv6 machines, but perhaps a better solution would be to have
the loop in test_dns_tcp() skip to the next test case if required
socket operations fail.
both knot and gnutls (at least until [3.4](https://gitlab.com/gnutls/gnutls/-/blob/gnutls_3_4_x/gl/base64.c)) define they own base64_{en,de}code{_alloc}.
When linking with ODR violation detection, it fails with:
```
ld.lld: error: duplicate symbol: base64_encode
stderr: ld.lld: error: duplicate symbol: base64_encode
```
This diff put the base64* functions under `knot_` namespace to avoid the
conflict.
It's not at all necessary to repeatedly search from the root,
though this optimization makes the code a bit more complex.
Even here, technically the last memcmp() wouldn't need to start at the
beginning, but I didn't want to overcomplicate this.
A COW transaction allows a trie to be used for reading concurrently
while a modified version of the trie is being prepared. The change
can be committed by swapping the new trie root in place of the old one.
Internally, this feature uses one bit reference counts to identify which
parts of the trie are shared between the old and new versions, which
parts are new-only (so can be mutated) and which parts are old-only
(and will be free()d after commit).
No functional change.
The point of this commit is to make it possible to stash a few
flags in leaf nodes as well as branch nodes, though we don't
yet exercise this possibility in any meaningful way.
This fixes a foolish mistake in the original qp trie data structure
declarations: the combination of unions and bitfields is a complete
disaster for portability, and it gets into dangerous territory wrt
compiler optimization. Instead, we just use a big enough word (uint64_t)
which is broken up into fields using accessor macros and inline functions,
and cast it to a pointer when necessary. We don't actually care about
the detailed layout in memory, just the numeric value, so a union was
the wrong tool.