From: Paul Eggert Date: Fri, 21 Jun 2013 20:11:44 +0000 (-0700) Subject: Use C99-style flexible array members if available. X-Git-Tag: emacs-24.3.90~173^2^2~42^2~45^2~387^2~2014^2~2 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=fbe9e0b9fb6a250674e7619e9ba794e74ff5f0bc;p=emacs.git Use C99-style flexible array members if available. This avoids some subtle aliasing issues, which typically aren't a problem with GCC but may be a problem elsewhere. * lib-src/ebrowse.c (struct member, struct alias, struct sym): Use FLEXIBLE_ARRAY_MEMBER. (add_sym, add_member, make_namespace, register_namespace_alias): Use offsetof (struct, flex_array_member), not sizeof (struct), as that ports better to pre-C99 non-GCC. * src/alloc.c (sdata): New typedef, replacing the old struct sdata. It is a struct if GC_CHECK_STRING_BYTES, a union otherwise. In either case, it uses a flexible array member rather than the old struct hack. All uses changed. (SDATA_NBYTES, sweep_strings) [!GC_CHECK_STRING_BYTES]: Adjust to sdata reorganization. * src/alloc.c (VBLOCK_BYTES_MIN, allocate_vectorlike, Fgarbage_collect): Use offsetof (struct, flex_array_member), not sizeof (struct), as that ports better to pre-C99 non-GCC. * src/chartab.c (Fmake_char_table, make_sub_char_table, copy_char_table): Use CHAR_TABLE_STANDARD_SLOTS rather than its definition, as the latter has changed. * src/conf_post.h (FLEXIBLE_ARRAY_MEMBER): Move here from w32.c, and port better to pre-C99 GCC. * src/image.c (struct xpm_cached_color): * src/lisp.h (struct Lisp_Vector, struct Lisp_Bool_Vector) (struct Lisp_Char_Table, struct Lisp_Sub_Char_Table): Use FLEXIBLE_ARRAY_MEMBER. * src/lisp.h (string_bytes) [GC_CHECK_STRING_BYTES]: Move decl to top level so it gets checked against implementation. (CHAR_TABLE_STANDARD_SLOTS): Adjust to struct Lisp_Char_Table change. * src/w32.c (FLEXIBLE_ARRAY_MEMBER): Move to conf_post.h. --- diff --git a/lib-src/ChangeLog b/lib-src/ChangeLog index 0e4cf0b2833..62ee45aac51 100644 --- a/lib-src/ChangeLog +++ b/lib-src/ChangeLog @@ -1,3 +1,12 @@ +2013-06-21 Paul Eggert + + Use C99-style flexible array members if available. + * ebrowse.c (struct member, struct alias, struct sym): + Use FLEXIBLE_ARRAY_MEMBER. + (add_sym, add_member, make_namespace, register_namespace_alias): + Use offsetof (struct, flex_array_member), not sizeof (struct), as + that ports better to pre-C99 non-GCC. + 2013-05-29 Eli Zaretskii * Makefile.in (mostlyclean): Remove *.res files. diff --git a/lib-src/ebrowse.c b/lib-src/ebrowse.c index 3a237daf5f8..81d0cf0a19e 100644 --- a/lib-src/ebrowse.c +++ b/lib-src/ebrowse.c @@ -237,7 +237,7 @@ struct member char *def_regexp; /* Regular expression matching definition. */ const char *def_filename; /* File name of definition. */ int def_pos; /* Buffer position of definition. */ - char name[1]; /* Member name. */ + char name[FLEXIBLE_ARRAY_MEMBER]; /* Member name. */ }; /* Structures of this type are used to connect class structures with @@ -256,7 +256,7 @@ struct alias struct alias *next; /* Next in list. */ struct sym *namesp; /* Namespace in which defined. */ struct link *aliasee; /* List of aliased namespaces (A::B::C...). */ - char name[1]; /* Alias name. */ + char name[FLEXIBLE_ARRAY_MEMBER]; /* Alias name. */ }; /* The structure used to describe a class in the symbol table, @@ -280,7 +280,7 @@ struct sym const char *filename; /* File in which it can be found. */ const char *sfilename; /* File in which members can be found. */ struct sym *namesp; /* Namespace in which defined. . */ - char name[1]; /* Name of the class. */ + char name[FLEXIBLE_ARRAY_MEMBER]; /* Name of the class. */ }; /* Experimental: Print info for `--position-info'. We print @@ -567,8 +567,8 @@ add_sym (const char *name, struct sym *nested_in_class) puts (name); } - sym = (struct sym *) xmalloc (sizeof *sym + strlen (name)); - memset (sym, 0, sizeof *sym); + sym = xmalloc (offsetof (struct sym, name) + strlen (name) + 1); + memset (sym, 0, offsetof (struct sym, name)); strcpy (sym->name, name); sym->namesp = scope; sym->next = class_table[h]; @@ -852,7 +852,8 @@ add_global_decl (char *name, char *regexp, int pos, unsigned int hash, int var, static struct member * add_member (struct sym *cls, char *name, int var, int sc, unsigned int hash) { - struct member *m = (struct member *) xmalloc (sizeof *m + strlen (name)); + struct member *m = xmalloc (offsetof (struct member, name) + + strlen (name) + 1); struct member **list; struct member *p; struct member *prev; @@ -962,8 +963,8 @@ mark_inherited_virtual (void) static struct sym * make_namespace (char *name, struct sym *context) { - struct sym *s = (struct sym *) xmalloc (sizeof *s + strlen (name)); - memset (s, 0, sizeof *s); + struct sym *s = xmalloc (offsetof (struct sym, name) + strlen (name) + 1); + memset (s, 0, offsetof (struct sym, name)); strcpy (s->name, name); s->next = all_namespaces; s->namesp = context; @@ -1046,7 +1047,7 @@ register_namespace_alias (char *new_name, struct link *old_name) if (streq (new_name, al->name) && (al->namesp == current_namespace)) return; - al = (struct alias *) xmalloc (sizeof *al + strlen (new_name)); + al = xmalloc (offsetof (struct alias, name) + strlen (new_name) + 1); strcpy (al->name, new_name); al->next = namespace_alias_table[h]; al->namesp = current_namespace; diff --git a/src/ChangeLog b/src/ChangeLog index 4e52f5b2818..4821f5fb7eb 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,31 @@ +2013-06-21 Paul Eggert + + Use C99-style flexible array members if available. + This avoids some subtle aliasing issues, which typically + aren't a problem with GCC but may be a problem elsewhere. + * alloc.c (sdata): New typedef, replacing the old struct sdata. + It is a struct if GC_CHECK_STRING_BYTES, a union otherwise. + In either case, it uses a flexible array member rather than + the old struct hack. All uses changed. + (SDATA_NBYTES, sweep_strings) [!GC_CHECK_STRING_BYTES]: + Adjust to sdata reorganization. + * alloc.c (VBLOCK_BYTES_MIN, allocate_vectorlike, Fgarbage_collect): + Use offsetof (struct, flex_array_member), not sizeof (struct), as + that ports better to pre-C99 non-GCC. + * chartab.c (Fmake_char_table, make_sub_char_table, copy_char_table): + Use CHAR_TABLE_STANDARD_SLOTS rather than its definition, + as the latter has changed. + * conf_post.h (FLEXIBLE_ARRAY_MEMBER): Move here from w32.c, + and port better to pre-C99 GCC. + * image.c (struct xpm_cached_color): + * lisp.h (struct Lisp_Vector, struct Lisp_Bool_Vector) + (struct Lisp_Char_Table, struct Lisp_Sub_Char_Table): + Use FLEXIBLE_ARRAY_MEMBER. + * lisp.h (string_bytes) [GC_CHECK_STRING_BYTES]: + Move decl to top level so it gets checked against implementation. + (CHAR_TABLE_STANDARD_SLOTS): Adjust to struct Lisp_Char_Table change. + * w32.c (FLEXIBLE_ARRAY_MEMBER): Move to conf_post.h. + 2013-06-20 Paul Eggert * syntax.c: Integer cleanups. diff --git a/src/alloc.c b/src/alloc.c index d277dd2419b..eaef0d4b797 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -1260,7 +1260,7 @@ mark_interval (register INTERVAL i, Lisp_Object dummy) When a Lisp_String is freed during GC, it is put back on string_free_list, and its `data' member and its sdata's `string' pointer is set to null. The size of the string is recorded in the - `u.nbytes' member of the sdata. So, sdata structures that are no + `n.nbytes' member of the sdata. So, sdata structures that are no longer used, can be easily recognized, and it's easy to compact the sblocks of small strings which we do in compact_small_strings. */ @@ -1274,10 +1274,12 @@ mark_interval (register INTERVAL i, Lisp_Object dummy) #define LARGE_STRING_BYTES 1024 -/* Structure describing string memory sub-allocated from an sblock. +/* Struct or union describing string memory sub-allocated from an sblock. This is where the contents of Lisp strings are stored. */ -struct sdata +#ifdef GC_CHECK_STRING_BYTES + +typedef struct { /* Back-pointer to the string this sdata belongs to. If null, this structure is free, and the NBYTES member of the union below @@ -1287,34 +1289,42 @@ struct sdata contents. */ struct Lisp_String *string; -#ifdef GC_CHECK_STRING_BYTES - ptrdiff_t nbytes; - unsigned char data[1]; + unsigned char data[FLEXIBLE_ARRAY_MEMBER]; +} sdata; #define SDATA_NBYTES(S) (S)->nbytes #define SDATA_DATA(S) (S)->data #define SDATA_SELECTOR(member) member -#else /* not GC_CHECK_STRING_BYTES */ +#else - union +typedef union +{ + struct Lisp_String *string; + + /* When STRING is non-null. */ + struct { - /* When STRING is non-null. */ - unsigned char data[1]; + struct Lisp_String *string; + unsigned char data[FLEXIBLE_ARRAY_MEMBER]; + } u; - /* When STRING is null. */ + /* When STRING is null. */ + struct + { + struct Lisp_String *string; ptrdiff_t nbytes; - } u; + } n; +} sdata; -#define SDATA_NBYTES(S) (S)->u.nbytes +#define SDATA_NBYTES(S) (S)->n.nbytes #define SDATA_DATA(S) (S)->u.data #define SDATA_SELECTOR(member) u.member #endif /* not GC_CHECK_STRING_BYTES */ -#define SDATA_DATA_OFFSET offsetof (struct sdata, SDATA_SELECTOR (data)) -}; +#define SDATA_DATA_OFFSET offsetof (sdata, SDATA_SELECTOR (data)) /* Structure describing a block of memory which is sub-allocated to @@ -1329,10 +1339,10 @@ struct sblock /* Pointer to the next free sdata block. This points past the end of the sblock if there isn't any space left in this block. */ - struct sdata *next_free; + sdata *next_free; /* Start of data. */ - struct sdata first_data; + sdata first_data; }; /* Number of Lisp strings in a string_block structure. The 1020 is @@ -1388,7 +1398,7 @@ static EMACS_INT total_string_bytes; a pointer to the `u.data' member of its sdata structure; the structure starts at a constant offset in front of that. */ -#define SDATA_OF_STRING(S) ((struct sdata *) ((S)->data - SDATA_DATA_OFFSET)) +#define SDATA_OF_STRING(S) ((sdata *) ((S)->data - SDATA_DATA_OFFSET)) #ifdef GC_CHECK_STRING_OVERRUN @@ -1487,7 +1497,7 @@ string_bytes (struct Lisp_String *s) static void check_sblock (struct sblock *b) { - struct sdata *from, *end, *from_end; + sdata *from, *end, *from_end; end = b->next_free; @@ -1501,7 +1511,7 @@ check_sblock (struct sblock *b) same as the one recorded in the sdata structure. */ nbytes = SDATA_SIZE (from->string ? string_bytes (from->string) : SDATA_NBYTES (from)); - from_end = (struct sdata *) ((char *) from + nbytes + GC_STRING_EXTRA); + from_end = (sdata *) ((char *) from + nbytes + GC_STRING_EXTRA); } } @@ -1631,7 +1641,7 @@ void allocate_string_data (struct Lisp_String *s, EMACS_INT nchars, EMACS_INT nbytes) { - struct sdata *data, *old_data; + sdata *data, *old_data; struct sblock *b; ptrdiff_t needed, old_nbytes; @@ -1701,7 +1711,7 @@ allocate_string_data (struct Lisp_String *s, b = current_sblock; data = b->next_free; - b->next_free = (struct sdata *) ((char *) data + needed + GC_STRING_EXTRA); + b->next_free = (sdata *) ((char *) data + needed + GC_STRING_EXTRA); MALLOC_UNBLOCK_INPUT; @@ -1772,7 +1782,7 @@ sweep_strings (void) else { /* String is dead. Put it on the free-list. */ - struct sdata *data = SDATA_OF_STRING (s); + sdata *data = SDATA_OF_STRING (s); /* Save the size of S in its sdata so that we know how large that is. Reset the sdata's string @@ -1781,7 +1791,7 @@ sweep_strings (void) if (string_bytes (s) != SDATA_NBYTES (data)) emacs_abort (); #else - data->u.nbytes = STRING_BYTES (s); + data->n.nbytes = STRING_BYTES (s); #endif data->string = NULL; @@ -1862,13 +1872,13 @@ static void compact_small_strings (void) { struct sblock *b, *tb, *next; - struct sdata *from, *to, *end, *tb_end; - struct sdata *to_end, *from_end; + sdata *from, *to, *end, *tb_end; + sdata *to_end, *from_end; /* TB is the sblock we copy to, TO is the sdata within TB we copy to, and TB_END is the end of TB. */ tb = oldest_sblock; - tb_end = (struct sdata *) ((char *) tb + SBLOCK_SIZE); + tb_end = (sdata *) ((char *) tb + SBLOCK_SIZE); to = &tb->first_data; /* Step through the blocks from the oldest to the youngest. We @@ -1897,7 +1907,7 @@ compact_small_strings (void) eassert (nbytes <= LARGE_STRING_BYTES); nbytes = SDATA_SIZE (nbytes); - from_end = (struct sdata *) ((char *) from + nbytes + GC_STRING_EXTRA); + from_end = (sdata *) ((char *) from + nbytes + GC_STRING_EXTRA); #ifdef GC_CHECK_STRING_OVERRUN if (memcmp (string_overrun_cookie, @@ -1910,14 +1920,14 @@ compact_small_strings (void) if (s) { /* If TB is full, proceed with the next sblock. */ - to_end = (struct sdata *) ((char *) to + nbytes + GC_STRING_EXTRA); + to_end = (sdata *) ((char *) to + nbytes + GC_STRING_EXTRA); if (to_end > tb_end) { tb->next_free = to; tb = tb->next; - tb_end = (struct sdata *) ((char *) tb + SBLOCK_SIZE); + tb_end = (sdata *) ((char *) tb + SBLOCK_SIZE); to = &tb->first_data; - to_end = (struct sdata *) ((char *) to + nbytes + GC_STRING_EXTRA); + to_end = (sdata *) ((char *) to + nbytes + GC_STRING_EXTRA); } /* Copy, and update the string's `data' pointer. */ @@ -2581,7 +2591,7 @@ verify (VECTOR_BLOCK_SIZE <= (1 << PSEUDOVECTOR_SIZE_BITS)); /* Size of the minimal vector allocated from block. */ -#define VBLOCK_BYTES_MIN vroundup (sizeof (struct Lisp_Vector)) +#define VBLOCK_BYTES_MIN vroundup (header_size + sizeof (Lisp_Object)) /* Size of the largest vector allocated from block. */ @@ -2938,7 +2948,8 @@ allocate_vectorlike (ptrdiff_t len) else { struct large_vector *lv - = lisp_malloc (sizeof (*lv) + (len - 1) * word_size, + = lisp_malloc ((offsetof (struct large_vector, v.contents) + + len * word_size), MEM_TYPE_VECTORLIKE); lv->next.vector = large_vectors; large_vectors = lv; @@ -5416,7 +5427,8 @@ See Info node `(elisp)Garbage Collection'. */) total[4] = list3 (Qstring_bytes, make_number (1), bounded_number (total_string_bytes)); - total[5] = list3 (Qvectors, make_number (sizeof (struct Lisp_Vector)), + total[5] = list3 (Qvectors, + make_number (header_size + sizeof (Lisp_Object)), bounded_number (total_vectors)); total[6] = list4 (Qvector_slots, make_number (word_size), diff --git a/src/chartab.c b/src/chartab.c index 1c76e5a21e9..b7b9590a538 100644 --- a/src/chartab.c +++ b/src/chartab.c @@ -128,7 +128,7 @@ the char-table has no extra slot. */) n_extras = XINT (n); } - size = VECSIZE (struct Lisp_Char_Table) - 1 + n_extras; + size = CHAR_TABLE_STANDARD_SLOTS + n_extras; vector = Fmake_vector (make_number (size), init); XSETPVECTYPE (XVECTOR (vector), PVEC_CHAR_TABLE); set_char_table_parent (vector, Qnil); @@ -141,7 +141,7 @@ static Lisp_Object make_sub_char_table (int depth, int min_char, Lisp_Object defalt) { Lisp_Object table; - int size = VECSIZE (struct Lisp_Sub_Char_Table) - 1 + chartab_size[depth]; + int size = CHAR_TABLE_STANDARD_SLOTS + chartab_size[depth]; table = Fmake_vector (make_number (size), defalt); XSETPVECTYPE (XVECTOR (table), PVEC_SUB_CHAR_TABLE); @@ -207,7 +207,7 @@ copy_char_table (Lisp_Object table) ? copy_sub_char_table (XCHAR_TABLE (table)->contents[i]) : XCHAR_TABLE (table)->contents[i])); set_char_table_ascii (copy, char_table_ascii (copy)); - size -= VECSIZE (struct Lisp_Char_Table) - 1; + size -= CHAR_TABLE_STANDARD_SLOTS; for (i = 0; i < size; i++) set_char_table_extras (copy, i, XCHAR_TABLE (table)->extras[i]); diff --git a/src/conf_post.h b/src/conf_post.h index 46aea32ef30..32c4341b7a3 100644 --- a/src/conf_post.h +++ b/src/conf_post.h @@ -243,6 +243,17 @@ extern void _DebPrint (const char *fmt, ...); #define INLINE_HEADER_BEGIN _GL_INLINE_HEADER_BEGIN #define INLINE_HEADER_END _GL_INLINE_HEADER_END +/* To use the struct hack with N elements, declare the struct like this: + struct s { ...; t name[FLEXIBLE_ARRAY_MEMBER]; }; + and allocate (offsetof (struct s, name) + N * sizeof (t)) bytes. */ +#if 199901 <= __STDC_VERSION__ +# define FLEXIBLE_ARRAY_MEMBER +#elif __GNUC__ && !defined __STRICT_ANSI__ +# define FLEXIBLE_ARRAY_MEMBER 0 +#else +# define FLEXIBLE_ARRAY_MEMBER 1 +#endif + /* Use this to suppress gcc's `...may be used before initialized' warnings. */ #ifdef lint /* Use CODE only if lint checking is in effect. */ diff --git a/src/image.c b/src/image.c index f9f6ce70040..ffb3cd15e93 100644 --- a/src/image.c +++ b/src/image.c @@ -3057,7 +3057,7 @@ struct xpm_cached_color XColor color; /* Color name. */ - char name[1]; + char name[FLEXIBLE_ARRAY_MEMBER]; }; /* The hash table used for the color cache, and its bucket vector diff --git a/src/lisp.h b/src/lisp.h index e2d091e98f1..f4356cd140d 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -1073,16 +1073,20 @@ SCHARS (Lisp_Object string) { return XSTRING (string)->size; } + +#ifdef GC_CHECK_STRING_BYTES +extern ptrdiff_t string_bytes (struct Lisp_String *); +#endif LISP_INLINE ptrdiff_t STRING_BYTES (struct Lisp_String *s) { #ifdef GC_CHECK_STRING_BYTES - extern ptrdiff_t string_bytes (struct Lisp_String *); return string_bytes (s); #else return s->size_byte < 0 ? s->size : s->size_byte; #endif } + LISP_INLINE ptrdiff_t SBYTES (Lisp_Object string) { @@ -1136,7 +1140,7 @@ struct vectorlike_header struct Lisp_Vector { struct vectorlike_header header; - Lisp_Object contents[1]; + Lisp_Object contents[FLEXIBLE_ARRAY_MEMBER]; }; /* A boolvector is a kind of vectorlike, with contents are like a string. */ @@ -1149,7 +1153,7 @@ struct Lisp_Bool_Vector /* This is the size in bits. */ EMACS_INT size; /* This contains the actual bits, packed into bytes. */ - unsigned char data[1]; + unsigned char data[FLEXIBLE_ARRAY_MEMBER]; }; /* Some handy constants for calculating sizes @@ -1272,7 +1276,7 @@ struct Lisp_Char_Table Lisp_Object contents[(1 << CHARTAB_SIZE_BITS_0)]; /* These hold additional data. It is a vector. */ - Lisp_Object extras[1]; + Lisp_Object extras[FLEXIBLE_ARRAY_MEMBER]; }; struct Lisp_Sub_Char_Table @@ -1293,7 +1297,7 @@ struct Lisp_Sub_Char_Table Lisp_Object min_char; /* Use set_sub_char_table_contents to set this. */ - Lisp_Object contents[1]; + Lisp_Object contents[FLEXIBLE_ARRAY_MEMBER]; }; LISP_INLINE Lisp_Object @@ -1366,7 +1370,7 @@ struct Lisp_Subr slots. */ enum CHAR_TABLE_STANDARD_SLOTS { - CHAR_TABLE_STANDARD_SLOTS = VECSIZE (struct Lisp_Char_Table) - 1 + CHAR_TABLE_STANDARD_SLOTS = PSEUDOVECSIZE (struct Lisp_Char_Table, extras) }; /* Return the number of "extra" slots in the char table CT. */ diff --git a/src/w32.c b/src/w32.c index 7a39a617ee3..230479cd61a 100644 --- a/src/w32.c +++ b/src/w32.c @@ -3785,12 +3785,6 @@ get_rid (PSID sid) /* Caching SID and account values for faster lokup. */ -#ifdef __GNUC__ -# define FLEXIBLE_ARRAY_MEMBER -#else -# define FLEXIBLE_ARRAY_MEMBER 1 -#endif - struct w32_id { unsigned rid; struct w32_id *next;