From 0b0a278699196c25f4cf0f690e21c5aea2ccabfb Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sat, 8 Aug 2009 20:32:23 -0700 Subject: [PATCH] Add CHECK_POINTER_HAS_TYPE macro, and use it to make *_data macros safer. --- src/libpspp/abt.h | 8 ++++--- src/libpspp/bt.h | 8 ++++--- src/libpspp/cast.h | 53 ++++++++++++++++++++++++++++++++++++++++- src/libpspp/heap.h | 8 ++++--- src/libpspp/hmap.h | 6 +++-- src/libpspp/ll.h | 8 ++++--- src/libpspp/range-map.h | 6 +++-- src/libpspp/tower.h | 8 ++++--- 8 files changed, 85 insertions(+), 20 deletions(-) diff --git a/src/libpspp/abt.h b/src/libpspp/abt.h index 3801eb86..24d7268a 100644 --- a/src/libpspp/abt.h +++ b/src/libpspp/abt.h @@ -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 @@ -150,12 +150,14 @@ tree paper. */ #include +#include /* 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 diff --git a/src/libpspp/bt.h b/src/libpspp/bt.h index 340b8760..7045632e 100644 --- a/src/libpspp/bt.h +++ b/src/libpspp/bt.h @@ -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 @@ -24,12 +24,14 @@ fully encapsulated. */ #include +#include /* 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 diff --git a/src/libpspp/cast.h b/src/libpspp/cast.h index f74442c2..30927899 100644 --- a/src/libpspp/cast.h +++ b/src/libpspp/cast.h @@ -19,10 +19,61 @@ #include +/* 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 diff --git a/src/libpspp/heap.h b/src/libpspp/heap.h index 13422437..3a3c516a 100644 --- a/src/libpspp/heap.h +++ b/src/libpspp/heap.h @@ -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 #include #include @@ -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. */ diff --git a/src/libpspp/hmap.h b/src/libpspp/hmap.h index e73d84fd..c9e764de 100644 --- a/src/libpspp/hmap.h +++ b/src/libpspp/hmap.h @@ -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 @@ -116,12 +116,14 @@ */ #include +#include /* 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. */ diff --git a/src/libpspp/ll.h b/src/libpspp/ll.h index 65ecf55f..4d0d2eb8 100644 --- a/src/libpspp/ll.h +++ b/src/libpspp/ll.h @@ -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 #include #include +#include /* Embedded, circular doubly linked list. @@ -108,8 +109,9 @@ /* 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 diff --git a/src/libpspp/range-map.h b/src/libpspp/range-map.h index 3dd77c9f..024fe937 100644 --- a/src/libpspp/range-map.h +++ b/src/libpspp/range-map.h @@ -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 @@ -33,12 +33,14 @@ #include #include +#include /* 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 diff --git a/src/libpspp/tower.h b/src/libpspp/tower.h index 246984a2..9be8231c 100644 --- a/src/libpspp/tower.h +++ b/src/libpspp/tower.h @@ -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 @@ -51,12 +51,14 @@ #include #include +#include /* 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 -- 2.30.2