Apparently it's impolite to ask GCC to subtract two pointers.
authorGuus Sliepen <guus@tinc-vpn.org>
Sun, 13 Sep 2009 12:08:59 +0000 (14:08 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Sun, 13 Sep 2009 12:08:59 +0000 (14:08 +0200)
If two pointers do not belong to the same array, pointer subtraction gives
nonsensical results, depending on the level of optimisation and the
architecture one is compiling for. It is apparently not just subtracting the
pointer values and dividing by the size of the object, but uses some kind of
higher magic not intended for mere mortals. GCC will not warn about this at
all. Casting to void * is also a no-no, because then GCC does warn that strict
aliasing rules are being broken. The only safe way to query the ordering of two
pointers is to use the (in)equality operators.

The unsafe implementation of connection_compare() has probably caused the "old
connection_t for ... still lingering" messages. Our implementation of AVL trees
is augmented with a doubly linked list, which is normally what is traversed.
Only when deleting an old connection the tree itself is traversed.

src/connection.c

index 66eb059..283ebd7 100644 (file)
@@ -37,7 +37,7 @@ connection_t *broadcast;
 
 static int connection_compare(const connection_t *a, const connection_t *b)
 {
-       return a - b;
+       return a < b ? -1 : a == b ? 0 : 1;
 }
 
 void init_connections(void)