Add CHECK_POINTER_HAS_TYPE macro, and use it to make *_data macros safer.
authorBen Pfaff <blp@gnu.org>
Sun, 9 Aug 2009 03:32:23 +0000 (20:32 -0700)
committerBen Pfaff <blp@gnu.org>
Sun, 9 Aug 2009 03:40:28 +0000 (20:40 -0700)
src/libpspp/abt.h
src/libpspp/bt.h
src/libpspp/cast.h
src/libpspp/heap.h
src/libpspp/hmap.h
src/libpspp/ll.h
src/libpspp/range-map.h
src/libpspp/tower.h

index 3801eb86636c14d2d4a73420329d7c568768d630..24d7268a2d6543a383361c50914d796e52e7b6c1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    tree paper.  */
 
 #include <stddef.h>
+#include <libpspp/cast.h>
 
 /* Returns the data structure corresponding to the given NODE,
    assuming that NODE is embedded as the given MEMBER name in
    data type STRUCT. */
-#define abt_data(NODE, STRUCT, MEMBER)                                  \
-        ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+#define abt_data(NODE, STRUCT, MEMBER)                          \
+        (CHECK_POINTER_HAS_TYPE (NODE, struct abt_node *),      \
+         UP_CAST (NODE, STRUCT, MEMBER))
 
 /* Node in an augmented binary tree. */
 struct abt_node
index 340b8760166c31fec29ea42ae8ecc50c24911806..7045632ef204e2edd228dc4dd8473174318212be 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    fully encapsulated. */
 
 #include <stddef.h>
+#include <libpspp/cast.h>
 
 /* Returns the data structure corresponding to the given NODE,
    assuming that NODE is embedded as the given MEMBER name in
    data type STRUCT. */
-#define bt_data(NODE, STRUCT, MEMBER)                                  \
-        ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+#define bt_data(NODE, STRUCT, MEMBER)                           \
+        (CHECK_POINTER_HAS_TYPE (NODE, struct bt_node *),       \
+         UP_CAST (NODE, STRUCT, MEMBER))
 
 /* Node in a balanced binary tree. */
 struct bt_node
index f74442c2cea7cb4f99c85d2a6fb3d1e026505f68..30927899c8bfb81dee56d509d16d7a5a3a72f52e 100644 (file)
 
 #include <stddef.h>
 
+/* Expands to a void expression that checks that POINTER is an
+   expression whose type is a qualified or unqualified version of
+   a type compatible with TYPE (a pointer type) and, if not,
+   causes a compiler warning to be issued (on typical compilers).
+
+   Examples:
+
+   int *ip;
+   const int *cip;
+   const int **cipp;
+   int ***ippp;
+   double *dp;
+
+   // None of these causes a warning:
+   CHECK_POINTER_HAS_TYPE (ip, int *);
+   CHECK_POINTER_HAS_TYPE (ip, const int *);
+   CHECK_POINTER_HAS_TYPE (cip, int *);
+   CHECK_POINTER_HAS_TYPE (cip, const int *);
+   CHECK_POINTER_HAS_TYPE (dp, double *);
+   CHECK_POINTER_HAS_TYPE (dp, const double *);
+   CHECK_POINTER_HAS_TYPE (cipp, const int **);
+   CHECK_POINTER_HAS_TYPE (cipp, const int *const *);
+   CHECK_POINTER_HAS_TYPE (ippp, int ***);
+   CHECK_POINTER_HAS_TYPE (ippp, int **const *);
+
+   // None of these causes a warning either, although it is unusual to
+   // const-qualify a pointer like this (it's like declaring a "const int",
+   // for example).
+   CHECK_POINTER_HAS_TYPE (ip, int *const);
+   CHECK_POINTER_HAS_TYPE (ip, const int *const);
+   CHECK_POINTER_HAS_TYPE (cip, int *const);
+   CHECK_POINTER_HAS_TYPE (cip, const int *const);
+   CHECK_POINTER_HAS_TYPE (cipp, const int **const);
+   CHECK_POINTER_HAS_TYPE (cipp, const int *const *const);
+   CHECK_POINTER_HAS_TYPE (ippp, int ***const);
+   CHECK_POINTER_HAS_TYPE (ippp, int **const *const);
+
+   // Provokes a warning because "int" is not compatible with "double":
+   CHECK_POINTER_HAS_TYPE (dp, int *);
+
+   // Provoke warnings because C's type compatibility rules only allow
+   // adding a "const" qualifier to the outermost pointer:
+   CHECK_POINTER_HAS_TYPE (ippp, const int ***);
+   CHECK_POINTER_HAS_TYPE (ippp, int *const**);
+*/
+#define CHECK_POINTER_HAS_TYPE(POINTER, TYPE)           \
+        ((void) sizeof ((TYPE) (POINTER) == (POINTER)))
+
 /* Given expressions A and B, both of which have pointer type,
    expands to a void expression that causes a compiler warning if
    A and B are not pointers to qualified or unqualified versions
-   of compatible types. */
+   of compatible types.
+
+   Examples similar to those given for CHECK_POINTER_HAS_TYPE,
+   above, can easily be devised. */
 #define CHECK_POINTER_COMPATIBILITY(A, B) ((void) sizeof ((A) == (B)))
 
 /* Given POINTER, a pointer to the given MEMBER within structure
index 134224373d2ec2dbf6536b4d7909799df59b06d6..3a3c516a03485ab7e4a5ecac923719c3425c4ee0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -70,6 +70,7 @@
 #ifndef LIBPSPP_HEAP_H
 #define LIBPSPP_HEAP_H 1
 
+#include <libpspp/cast.h>
 #include <stdbool.h>
 #include <stddef.h>
 
@@ -78,8 +79,9 @@ struct pool;
 /* Returns the data structure corresponding to the given heap
    NODE, assuming that NODE is embedded as the given MEMBER name
    in data type STRUCT. */
-#define heap_data(NODE, STRUCT, MEMBER)                                 \
-        ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+#define heap_data(NODE, STRUCT, MEMBER)                         \
+        (CHECK_POINTER_HAS_TYPE (NODE, struct heap_node *),     \
+         UP_CAST (NODE, STRUCT, MEMBER))
 
 /* A node in a heap.  Opaque.
    One of these structures must be embedded in your heap node. */
index e73d84fd153764ec96935c6242dc2388820c5757..c9e764dec563a92df08491839259e5f061884963 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    */
 
 #include <stddef.h>
+#include <libpspp/cast.h>
 
 /* Returns the data structure corresponding to the given NODE,
    assuming that NODE is embedded as the given MEMBER name in
    data type STRUCT.  NODE must not be a null pointer. */
 #define HMAP_DATA(NODE, STRUCT, MEMBER)                         \
-  ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+        (CHECK_POINTER_HAS_TYPE (NODE, struct hmap_node *),     \
+         UP_CAST (NODE, STRUCT, MEMBER))
 
 /* Like HMAP_DATA, except that a null NODE yields a null pointer
    result. */
index 65ecf55f2cad759a50085a85e90f1e3c79cf7f02..4d0d2eb84a6ba26dd8dfd64735b9113e08a30df0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2009 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -50,6 +50,7 @@
 #include <assert.h>
 #include <stdbool.h>
 #include <stddef.h>
+#include <libpspp/cast.h>
 
 /* Embedded, circular doubly linked list.
 
 /* Returns the data structure corresponding to the given node LL,
    assuming that LL is embedded as the given MEMBER name in data
    type STRUCT. */
-#define ll_data(LL, STRUCT, MEMBER)                                    \
-        ((STRUCT *) ((char *) (LL) - offsetof (STRUCT, MEMBER)))
+#define ll_data(LL, STRUCT, MEMBER)                     \
+        (CHECK_POINTER_HAS_TYPE(LL, struct ll *),       \
+         UP_CAST(LL, STRUCT, MEMBER))
 
 /* Linked list node. */
 struct ll
index 3dd77c9ffac30f2fb85429df8a35091ce108c7ef..024fe93790e507a052e14e4990152b9b17c7ea91 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #include <stdbool.h>
 
 #include <libpspp/bt.h>
+#include <libpspp/cast.h>
 
 /* Returns the data structure corresponding to the given NODE,
    assuming that NODE is embedded as the given MEMBER name in
    data type STRUCT. */
 #define range_map_data(NODE, STRUCT, MEMBER)                            \
-        ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+        (CHECK_POINTER_HAS_TYPE (NODE, struct range_map_node *),        \
+         UP_CAST (NODE, STRUCT, MEMBER))
 
 /* A range map node, to be embedded in the data value. */
 struct range_map_node
index 246984a2c1bfd6cd1c46100fbe95f84140843a92..9be8231c98ad7c9b0c7fc217a14a513d2813aa92 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 #include <stdbool.h>
 #include <libpspp/abt.h>
+#include <libpspp/cast.h>
 
 /* Returns the data structure corresponding to the given NODE,
    assuming that NODE is embedded as the given MEMBER name in
    data type STRUCT. */
-#define tower_data(NODE, STRUCT, MEMBER)                            \
-        ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+#define tower_data(NODE, STRUCT, MEMBER)                        \
+        (CHECK_POINTER_HAS_TYPE (NODE, struct tower_node *),    \
+         UP_CAST (NODE, STRUCT, MEMBER))
 
 /* A node within a tower. */
 struct tower_node