structeq: fix case where we mark padding as unknown.
authorRusty Russell <rusty@rustcorp.com.au>
Wed, 26 Sep 2018 23:39:50 +0000 (09:09 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Thu, 27 Sep 2018 03:43:24 +0000 (13:13 +0930)
And change semantics: a negative number means "up to this much padding".

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ccan/structeq/structeq.h
ccan/structeq/test/compile_fail-expect-any-padding.c
ccan/structeq/test/compile_fail-unexpected-negative-padding.c [new file with mode: 0644]
ccan/structeq/test/run-with-unknown-padding.c [new file with mode: 0644]

index 6b90754c73a92fe3d203644ba9b075c8b0f5fcbd..81799539c51e45f9c2f1b9c23a1b3949b47564c1 100644 (file)
@@ -9,14 +9,15 @@
 /**
  * STRUCTEQ_DEF - define an ..._eq function to compare two structures.
  * @sname: name of the structure, and function (<sname>_eq) to define.
 /**
  * STRUCTEQ_DEF - define an ..._eq function to compare two structures.
  * @sname: name of the structure, and function (<sname>_eq) to define.
- * @padbytes: number of bytes of expected padding, or -1 if unknown.
+ * @padbytes: number of bytes of expected padding, or negative "max".
  * @...: name of every member of the structure.
  *
  * This generates a single memcmp() call in the common case where the
  * structure contains no padding.  Since it can't tell the difference between
  * padding and a missing member, @padbytes can be used to assert that
  * @...: name of every member of the structure.
  *
  * This generates a single memcmp() call in the common case where the
  * structure contains no padding.  Since it can't tell the difference between
  * padding and a missing member, @padbytes can be used to assert that
- * there isn't any, or how many we expect.  -1 means "expect some", since
- * it can be platform dependent.
+ * there isn't any, or how many we expect.  A negative number means
+ * "up to or equal to that amount of padding", as padding can be
+ * platform dependent.
  */
 #define STRUCTEQ_DEF(sname, padbytes, ...)                             \
 static inline bool CPPMAGIC_GLUE2(sname, _eq)(const struct sname *_a, \
  */
 #define STRUCTEQ_DEF(sname, padbytes, ...)                             \
 static inline bool CPPMAGIC_GLUE2(sname, _eq)(const struct sname *_a, \
@@ -25,7 +26,7 @@ static inline bool CPPMAGIC_GLUE2(sname, _eq)(const struct sname *_a, \
        BUILD_ASSERT(((padbytes) < 0 &&                                 \
                      CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, \
                                                    __VA_ARGS__))       \
        BUILD_ASSERT(((padbytes) < 0 &&                                 \
                      CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, \
                                                    __VA_ARGS__))       \
-                     > sizeof(*_a))                                    \
+                     - (padbytes) >= sizeof(*_a))                      \
                     || CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, \
                                                      __VA_ARGS__))     \
                     + (padbytes) == sizeof(*_a));                      \
                     || CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, \
                                                      __VA_ARGS__))     \
                     + (padbytes) == sizeof(*_a));                      \
index 321aef3a3f4413063c63957c1492da24173acce0..182c8607942fd54af95704f78e232fb049cd659e 100644 (file)
@@ -2,11 +2,12 @@
 
 struct mydata {
        int start, end;
 
 struct mydata {
        int start, end;
+       int pad;
 };
 #ifdef FAIL
 };
 #ifdef FAIL
-#define PADDING -1
+#define PADDING -1 /* We have more than 1 byte padding */
 #else
 #else
-#define PADDING 0
+#define PADDING sizeof(int)
 #endif
 
 STRUCTEQ_DEF(mydata, PADDING, start, end);
 #endif
 
 STRUCTEQ_DEF(mydata, PADDING, start, end);
diff --git a/ccan/structeq/test/compile_fail-unexpected-negative-padding.c b/ccan/structeq/test/compile_fail-unexpected-negative-padding.c
new file mode 100644 (file)
index 0000000..2c63b23
--- /dev/null
@@ -0,0 +1,20 @@
+#include <ccan/structeq/structeq.h>
+
+struct mydata {
+       int start, end;
+       int pad;
+};
+#ifdef FAIL
+#define PADDING -1
+#else
+#define PADDING -(int)sizeof(int)
+#endif
+
+STRUCTEQ_DEF(mydata, PADDING, start, end);
+
+int main(void)
+{
+       struct mydata a = { 0, 100 };
+
+       return mydata_eq(&a, &a);
+}
diff --git a/ccan/structeq/test/run-with-unknown-padding.c b/ccan/structeq/test/run-with-unknown-padding.c
new file mode 100644 (file)
index 0000000..c803e72
--- /dev/null
@@ -0,0 +1,39 @@
+#include <ccan/structeq/structeq.h>
+#include <ccan/tap/tap.h>
+
+/* In theory, this could be generated without padding, if alignof(int) were 0,
+ * and test would fail.  Call me when that happens. */
+struct mydata {
+       char start;
+       int end;
+};
+
+STRUCTEQ_DEF(mydata, -3, start, end);
+
+struct mydata2 {
+       char start;
+       int end;
+};
+
+STRUCTEQ_DEF(mydata2, -4, start, end);
+
+int main(void)
+{
+       struct mydata a, b;
+
+       /* This is how many tests you plan to run */
+       plan_tests(3);
+
+       a.start = 0;
+       a.end = 100;
+       ok1(mydata_eq(&a, &a));
+
+       b = a;
+       ok1(mydata_eq(&a, &b));
+
+       b.end++;
+       ok1(!mydata_eq(&a, &b));
+
+       /* This exits depending on whether all tests passed */
+       return exit_status();
+}