[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] [tor/master] Use autoconf's FLEXIBLE_ARRAY_MEMBER for unspecified-length arrays



Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
Date: Thu, 6 Jan 2011 15:59:05 -0500
Subject: Use autoconf's FLEXIBLE_ARRAY_MEMBER for unspecified-length arrays
Commit: d4165ef8b4c2ea697a0b73d80efc6575c0f2279a

C99 allows a syntax for structures whose last element is of
unspecified length:
   struct s {
     int elt1;
     ...
     char last_element[];
   };

Recent (last-5-years) autoconf versions provide an
AC_C_FLEXIBLE_ARRAY_MEMBER test that defines FLEXIBLE_ARRAY_MEMBER
to either no tokens (if you have c99 flexible array support) or to 1
(if you don't).  At that point you just use offsetof
[STRUCT_OFFSET() for us] to see where last_element begins, and
allocate your structures like:

   struct s {
     int elt1;
     ...
     char last_element[FLEXIBLE_ARRAY_MEMBER];
   };

   tor_malloc(STRUCT_OFFSET(struct s, last_element) +
                                   n_elements*sizeof(char));

The advantages are:

   1) It's easier to see which structures and elements are of
      unspecified length.
   2) The compiler and related checking tools can also see which
      structures and elements are of unspecified length, in case they
      wants to try weird bounds-checking tricks or something.
   3) The compiler can warn us if we do something dumb, like try
      to stack-allocate a flexible-length structure.
---
 configure.in           |   22 ++++++++++++++++++++++
 src/common/mempool.c   |    3 ++-
 src/or/buffers.c       |    4 ++--
 src/or/connection_or.c |    3 ++-
 src/or/or.h            |   12 ++++++------
 src/or/policies.c      |    4 ++--
 6 files changed, 36 insertions(+), 12 deletions(-)

diff --git a/configure.in b/configure.in
index 6ca5531..be1ee33 100644
--- a/configure.in
+++ b/configure.in
@@ -158,6 +158,28 @@ AM_CONDITIONAL(NAT_PMP, test x$natpmp = xtrue)
 AM_CONDITIONAL(MINIUPNPC, test x$upnp = xtrue)
 AM_PROG_CC_C_O
 
+ifdef([AC_C_FLEXIBLE_ARRAY_MEMBER], [
+AC_C_FLEXIBLE_ARRAY_MEMBER
+], [
+ dnl Maybe we've got an old autoconf...
+ AC_CACHE_CHECK([for flexible array members],
+     tor_cv_c_flexarray,
+     [AC_COMPILE_IFELSE(
+       AC_LANG_PROGRAM([
+ struct abc { int a; char b[]; };
+], [
+ struct abc *def = malloc(sizeof(struct abc)+sizeof(char));
+ def->b[0] = 33;
+]),
+  [tor_cv_c_flexarray=yes],
+  [tor_cv_c_flexarray=no])])
+ if test $tor_cv_flexarray = yes ; then
+   AC_DEFINE([FLEXIBLE_ARRAY_MEMBER], [])
+ else
+   AC_DEFINE([FLEXIBLE_ARRAY_MEMBER], [1])
+ fi
+])
+
 AC_PATH_PROG([SHA1SUM], [sha1sum], none)
 AC_PATH_PROG([OPENSSL], [openssl], none)
 
diff --git a/src/common/mempool.c b/src/common/mempool.c
index c444923..520e470 100644
--- a/src/common/mempool.c
+++ b/src/common/mempool.c
@@ -137,7 +137,8 @@ struct mp_chunk_t {
   int capacity; /**< Number of items that can be fit into this chunk. */
   size_t mem_size; /**< Number of usable bytes in mem. */
   char *next_mem; /**< Pointer into part of <b>mem</b> not yet carved up. */
-  char mem[1]; /**< Storage for this chunk. (Not actual size.) */
+  /** Storage for this chunk */
+  char mem[FLEXIBLE_ARRAY_MEMBER];
 };
 
 /** Number of extra bytes needed beyond mem_size to allocate a chunk. */
diff --git a/src/or/buffers.c b/src/or/buffers.c
index 9f393b9..48acf50 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -68,8 +68,8 @@ typedef struct chunk_t {
   size_t datalen; /**< The number of bytes stored in this chunk */
   size_t memlen; /**< The number of usable bytes of storage in <b>mem</b>. */
   char *data; /**< A pointer to the first byte of data stored in <b>mem</b>. */
-  char mem[1]; /**< The actual memory used for storage in this chunk. May be
-                * more than one byte long. */
+  char mem[FLEXIBLE_ARRAY_MEMBER]; /**< The actual memory used for storage in
+                * this chunk. */
 } chunk_t;
 
 #define CHUNK_HEADER_LEN STRUCT_OFFSET(chunk_t, mem[0])
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 6c4f7ef..5b440bc 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -191,7 +191,8 @@ var_cell_pack_header(const var_cell_t *cell, char *hdr_out)
 var_cell_t *
 var_cell_new(uint16_t payload_len)
 {
-  var_cell_t *cell = tor_malloc(sizeof(var_cell_t)+payload_len-1);
+  size_t size = STRUCT_OFFSET(var_cell_t, payload) + payload_len;
+  var_cell_t *cell = tor_malloc(size);
   cell->payload_len = payload_len;
   cell->command = 0;
   cell->circ_id = 0;
diff --git a/src/or/or.h b/src/or/or.h
index 2d1fbef..8aef2d0 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -857,8 +857,8 @@ typedef struct cell_t {
 typedef struct var_cell_t {
   uint8_t command;
   circid_t circ_id;
-  uint16_t payload_len;
-  uint8_t payload[1];
+  uint16_t payload_len; /**< The actual length of <b>payload</b>. */
+  uint8_t payload[FLEXIBLE_ARRAY_MEMBER];
 } var_cell_t;
 
 /** A cell as packed for writing to the network. */
@@ -1660,11 +1660,11 @@ typedef struct short_policy_t {
   unsigned int is_accept : 1;
   /** The actual number of values in 'entries'. */
   unsigned int n_entries : 31;
-  /** An array of (probably more than 1!) short_policy_entry_t values,
-   * each descriping a range of ports that this policy accepts or rejects
-   * (depending on the value of is_accept).
+  /** An array of 0 or more short_policy_entry_t values, each descriping a
+   * range of ports that this policy accepts or rejects (depending on the
+   * value of is_accept).
    */
-  short_policy_entry_t entries[1];
+  short_policy_entry_t entries[FLEXIBLE_ARRAY_MEMBER];
 } short_policy_t;
 
 /** A microdescriptor is the smallest amount of information needed to build a
diff --git a/src/or/policies.c b/src/or/policies.c
index 46a431a..e5af788 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -1382,8 +1382,8 @@ parse_short_policy(const char *summary)
   }
 
   {
-    size_t size = sizeof(short_policy_t) +
-      sizeof(short_policy_entry_t)*(n_entries-1);
+    size_t size = STRUCT_OFFSET(short_policy_t, entries) +
+      sizeof(short_policy_entry_t)*(n_entries);
     result = tor_malloc_zero(size);
 
     tor_assert( (char*)&result->entries[n_entries-1] < ((char*)result)+size);
-- 
1.7.1