DISPATCH-2039 Poison the memory pool so that ASAN works better with it (#1118)
When there is a read or write to the poisoned area, the error message looks like
```
==15792==ERROR: AddressSanitizer: use-after-poison on address 0x611000034dd8 at pc 0x7fdaa75fc713 bp 0x7fff2d0c8d80 sp 0x7fff2d0c8d78
14: WRITE of size 8 at 0x611000034dd8 thread T0
14: #0 0x7fdaa75fc712 in qd_hash_internal_remove_item /home/jdanek/repos/qpid/qpid-dispatch/cmake-build-debug-asan/../src/hash.c:131:30
14: #1 0x7fdaa75fb51d in qd_hash_free /home/jdanek/repos/qpid/qpid-dispatch/cmake-build-debug-asan/../src/hash.c:146:13
[...]
```
diff --git a/src/alloc_pool.c b/src/alloc_pool.c
index a5d7ffa..c5acc8c 100644
--- a/src/alloc_pool.c
+++ b/src/alloc_pool.c
@@ -24,6 +24,7 @@
#include "config.h"
#include "entity.h"
#include "entity_cache.h"
+#include "qd_asan_interface.h"
#include "qpid/dispatch/alloc.h"
#include "qpid/dispatch/ctools.h"
@@ -345,6 +346,7 @@
//
qd_alloc_item_t *item = pop_stack(&pool->free_list);
if (item) {
+ ASAN_UNPOISON_MEMORY_REGION(&item[1], desc->total_size);
#ifdef QD_MEMORY_DEBUG
item->desc = desc;
item->backtrace_size = backtrace(item->backtrace, STACK_DEPTH);
@@ -402,6 +404,7 @@
break;
}
item->sequence = 0;
+ ASAN_POISON_MEMORY_REGION(&item[1], desc->total_size);
#if QD_MEMORY_STATS
desc->stats->held_by_threads++;
desc->stats->total_alloc_from_heap++;
@@ -412,6 +415,7 @@
item = pop_stack(&pool->free_list);
if (item) {
+ ASAN_UNPOISON_MEMORY_REGION(&item[1], desc->total_size);
#ifdef QD_MEMORY_DEBUG
item->desc = desc;
item->backtrace_size = backtrace(item->backtrace, STACK_DEPTH);
@@ -453,6 +457,7 @@
item->desc = 0;
QD_MEMORY_FILL(p, QD_MEMORY_FREE, desc->total_size);
#endif
+ ASAN_POISON_MEMORY_REGION(p, desc->total_size);
//
// If this is the thread's first pass through here, allocate the
diff --git a/src/qd_asan_interface.h b/src/qd_asan_interface.h
new file mode 100644
index 0000000..d66d096
--- /dev/null
+++ b/src/qd_asan_interface.h
@@ -0,0 +1,78 @@
+#ifndef __qd_asan_interface_h__
+#define __qd_asan_interface_h__ 1
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Defines the ASAN interface file if available. If not, defines stub macros.
+ *
+ * See #include <sanitizer/asan_interface.h> in Clang for the source.
+ */
+
+#if defined(__clang__)
+# define QD_HAS_ADDRESS_SANITIZER __has_feature(address_sanitizer)
+#elif defined (__GNUC__) && defined(__SANITIZE_ADDRESS__)
+# define QD_HAS_ADDRESS_SANITIZER __SANITIZE_ADDRESS__
+#else
+# define QD_HAS_ADDRESS_SANITIZER 0
+#endif
+
+#if QD_HAS_ADDRESS_SANITIZER
+
+void __asan_poison_memory_region(void const volatile *addr, size_t size);
+void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
+
+/// Marks a memory region as unaddressable.
+///
+/// \note Macro provided for convenience; defined as a no-op if ASan is not
+/// enabled.
+///
+/// \param addr Start of memory region.
+/// \param size Size of memory region.
+#define ASAN_POISON_MEMORY_REGION(addr, size) \
+ __asan_poison_memory_region((addr), (size))
+
+/// Marks a memory region as addressable.
+///
+/// \note Macro provided for convenience; defined as a no-op if ASan is not
+/// enabled.
+///
+/// \param addr Start of memory region.
+/// \param size Size of memory region.
+#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
+ __asan_unpoison_memory_region((addr), (size))
+
+#else // QD_HAS_ADDRESS_SANITIZER
+
+#define ASAN_POISON_MEMORY_REGION(addr, size) \
+ ((void)(addr), (void)(size))
+#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
+ ((void)(addr), (void)(size))
+
+#endif // QD_HAS_ADDRESS_SANITIZER
+
+// https://github.com/google/sanitizers/wiki/AddressSanitizer#turning-off-instrumentation
+
+#if QD_HAS_ADDRESS_SANITIZER
+# define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
+#else
+# define ATTRIBUTE_NO_SANITIZE_ADDRESS
+#endif // QD_HAS_ADDRESS_SANITIZER
+
+#endif // __qd_asan_interface_h__