Commit fbe9e0b9 authored by Paul Eggert's avatar 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.
* 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.
parent cad5d1cb
2013-06-21 Paul Eggert <eggert@cs.ucla.edu>
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 <eliz@gnu.org>
* Makefile.in (mostlyclean): Remove *.res files.
......
......@@ -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;
......
2013-06-21 Paul Eggert <eggert@cs.ucla.edu>
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 <eggert@cs.ucla.edu>
* syntax.c: Integer cleanups.
......
......@@ -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),
......
......@@ -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]);
......
......@@ -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. */
......
......@@ -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
......
......@@ -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. */
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment