[ccan] container_of_var() macro broken for compilers without typeof()

Rusty Russell rusty at rustcorp.com.au
Wed Nov 10 17:22:52 EST 2010


On Wed, 10 Nov 2010 08:13:21 am Delio Brignoli wrote:
> Hello Rusty,
> 
> Thanks for setting up ccan. The code I am developing is using list.h and has to compile on windows with Visual C and GCC on linux, but the container_of_var() macro will not work for compilers that #define HAVE_TYPEOF 0, because (a) the #ifdef is always true (maybe this is deliberate)

Erk, no, but explains why I didn't see this!  I've added a TODO to add this
to ccanlint to check; thanks!

> and (b) 'containing_type' is undefined.
> I understand this cannot be fixed (*) but I was wondering if the #else branch should contain and #error to display an explicit error message.
> 
> (*) except by changing the list's interface, which I suspect would not be a popular solution.

Oh no, it can be fixed, here's the quick patch I'm putting in now.  I'm
testing the rest of the tree with !HAVE_TYPEOF too..

Thanks for the report!
Rusty.

diff --git a/ccan/check_type/check_type.h b/ccan/check_type/check_type.h
index d0dc0d4..8840567 100644
--- a/ccan/check_type/check_type.h
+++ b/ccan/check_type/check_type.h
@@ -51,7 +51,7 @@
 #define check_types_match(expr1, expr2)		\
 	((typeof(expr1) *)0 != (typeof(expr2) *)0)
 #else
-#include "build_assert/build_assert.h"
+#include <ccan/build_assert/build_assert.h>
 /* Without typeof, we can only test the sizes. */
 #define check_type(expr, type)					\
 	EXPR_BUILD_ASSERT(sizeof(expr) == sizeof(type))
diff --git a/ccan/container_of/container_of.h b/ccan/container_of/container_of.h
index de3f450..2a6b1cd 100644
--- a/ccan/container_of/container_of.h
+++ b/ccan/container_of/container_of.h
@@ -51,12 +51,13 @@
  *		return i;
  *	}
  */
-#ifdef HAVE_TYPEOF
+#if HAVE_TYPEOF
 #define container_of_var(member_ptr, var, member) \
 	container_of(member_ptr, typeof(*var), member)
 #else
-#define container_of_var(member_ptr, var, member) \
-	((void *)((char *)(member_ptr) - offsetof(containing_type, member)))
+#define container_of_var(member_ptr, var, member)		\
+	((void *)((char *)(member_ptr)				\
+		  - ((char *)&(var)->member - (char *)(var))))
 #endif
 
 #endif /* CCAN_CONTAINER_OF_H */
diff --git a/ccan/container_of/test/compile_fail-var-types.c b/ccan/container_of/test/compile_fail-var-types.c
index f9312b6..b7f395c 100644
--- a/ccan/container_of/test/compile_fail-var-types.c
+++ b/ccan/container_of/test/compile_fail-var-types.c
@@ -14,6 +14,9 @@ int main(int argc, char *argv[])
 #ifdef FAIL
 	/* b is a char, but intp is an int * */
 	foop = container_of_var(intp, foop, b);
+#if !HAVE_TYPEOF
+#error "Unfortunately we don't fail if we don't have typeof."
+#endif
 #else
 	foop = NULL;
 #endif


More information about the ccan mailing list