DEBUG: list: add DEBUG_LIST to purposely corrupt list heads after delete

LIST_DELETE doesn't affect the previous pointers of the stored element.
This can sometimes hide bugs when such a pointer is reused by accident
in a LIST_NEXT() or equivalent after having been detached for example, or
ia another LIST_DELETE is performed again, something that LIST_DEL_INIT()
is immune to. By compiling with -DDEBUG_LIST, we'll replace a freshly
detached list element with two invalid pointers that will cause a crash
in case of accidental misuse. It's not enabled by default.
diff --git a/Makefile b/Makefile
index 1f1de6d..1151a08 100644
--- a/Makefile
+++ b/Makefile
@@ -223,7 +223,7 @@
 # DEBUG_MEM_STATS, DEBUG_DONT_SHARE_POOLS, DEBUG_FD, DEBUG_POOL_INTEGRITY,
 # DEBUG_NO_POOLS, DEBUG_FAIL_ALLOC, DEBUG_STRICT_ACTION=[0-3], DEBUG_HPACK,
 # DEBUG_AUTH, DEBUG_SPOE, DEBUG_UAF, DEBUG_THREAD, DEBUG_STRICT, DEBUG_DEV,
-# DEBUG_TASK, DEBUG_MEMORY_POOLS, DEBUG_POOL_TRACING, DEBUG_QPACK.
+# DEBUG_TASK, DEBUG_MEMORY_POOLS, DEBUG_POOL_TRACING, DEBUG_QPACK, DEBUG_LIST.
 DEBUG = -DDEBUG_STRICT -DDEBUG_MEMORY_POOLS
 
 #### Trace options
diff --git a/include/haproxy/list.h b/include/haproxy/list.h
index dc4f7e0..368e6d7 100644
--- a/include/haproxy/list.h
+++ b/include/haproxy/list.h
@@ -72,7 +72,12 @@
 	} while (0)
 
 /* removes an element from a list and returns it */
+#if defined(DEBUG_LIST)
+/* purposely corrupt the detached element to detect use-after-delete */
+#define LIST_DELETE(el) ({ typeof(el) __ret = (el); (el)->n->p = (el)->p; (el)->p->n = (el)->n; *(__ret) = (struct list)ILH; (__ret);})
+#else
 #define LIST_DELETE(el) ({ typeof(el) __ret = (el); (el)->n->p = (el)->p; (el)->p->n = (el)->n; (__ret); })
+#endif
 
 /* removes an element from a list, initializes it and returns it.
  * This is faster than LIST_DELETE+LIST_INIT as we avoid reloading the pointers.