dlfcn: Avoid one-element flexible array in Dl_serinfo
Commit Message
On 5/23/19 2:34 AM, Florian Weimer wrote:
> +# ifdef __GNUC__
> + /* This avoids an unwanted array subscript check by the compiler,
> + while preserving the size of the type. */
> + __extension__ union
> + {
> + Dl_serpath dls_serpath[0]; /* Actually longer, dls_cnt elements. */
> + Dl_serpath __dls_serpath_pad[1];
> + };
> +# else /* !__GNUC__ */
> Dl_serpath dls_serpath[1]; /* Actually longer, dls_cnt elements. */
> +# endif /* !__GNUC__ */
Since this is actually a flexible array member, shouldn't we be using
C99's support for that if available, instead? Something like the
attached untested patch, say. We've been using a FLEXIBLE_ARRAY_MEMBER
macro in Gnulib for quite some time to do this sort of thing.
Comments
On Thu, 23 May 2019, Paul Eggert wrote:
> On 5/23/19 2:34 AM, Florian Weimer wrote:
> > +# ifdef __GNUC__
> > + /* This avoids an unwanted array subscript check by the compiler,
> > + while preserving the size of the type. */
> > + __extension__ union
> > + {
> > + Dl_serpath dls_serpath[0]; /* Actually longer, dls_cnt elements. */
> > + Dl_serpath __dls_serpath_pad[1];
> > + };
> > +# else /* !__GNUC__ */
> > Dl_serpath dls_serpath[1]; /* Actually longer, dls_cnt elements.
> > */
> > +# endif /* !__GNUC__ */
>
> Since this is actually a flexible array member, shouldn't we be using C99's
> support for that if available, instead? Something like the attached untested
> patch, say. We've been using a FLEXIBLE_ARRAY_MEMBER macro in Gnulib for quite
> some time to do this sort of thing.
Since we already have the __flexarr macro in sys/cdefs.h, I don't think
having a slightly different __GLIBC_FLEXIBLE_ARRAY_MEMBER as well seems
like a good idea.
* Paul Eggert:
> On 5/23/19 2:34 AM, Florian Weimer wrote:
>> +# ifdef __GNUC__
>> + /* This avoids an unwanted array subscript check by the compiler,
>> + while preserving the size of the type. */
>> + __extension__ union
>> + {
>> + Dl_serpath dls_serpath[0]; /* Actually longer, dls_cnt elements. */
>> + Dl_serpath __dls_serpath_pad[1];
>> + };
>> +# else /* !__GNUC__ */
>> Dl_serpath dls_serpath[1]; /* Actually longer, dls_cnt elements. */
>> +# endif /* !__GNUC__ */
>
> Since this is actually a flexible array member, shouldn't we be using
> C99's support for that if available, instead? Something like the
> attached untested patch, say. We've been using a FLEXIBLE_ARRAY_MEMBER
> macro in Gnulib for quite some time to do this sort of thing.
This changes the size of the type and is not source-code-compatible. I
have not investigated whether the change is still reasonably safe, but
usually, wo do not make such changes.
Thanks,
Florian
On 5/24/19 1:42 AM, Florian Weimer wrote:
> This changes the size of the type and is not source-code-compatible. I
> have not investigated whether the change is still reasonably safe, but
> usually, wo do not make such changes.
OK, in that case I suggest adding a comment explaining the situation,
since it is a bit of a sore thumb. Something like the following perhaps?
Or if this problem is likely to occur elsewhere, we could package the
situation up into a macro and just use the macro here.
/* An array of dls_cnt elements, each of type Dl_serpath. */
#if 0
/* With no backward-compatibility concerns we’d use the following
C99 flexible array member. However, as this data structure
predates C99 it had to contain a one-element array here, and we
don't want to change the struct's size now. */
Dl_serpath dls_serpath[];
#elif defined __GNUC__
/* Avoid an unwanted array subscript check by the compiler, while
preserving the size of the type. */
__extension__ union
{
Dl_serpath dls_serpath[0]; /* Actually longer, dls_cnt elements. */
Dl_serpath __dls_serpath_pad[1];
};
#else
Dl_serpath dls_serpath[1];
#endif
@@ -180,7 +180,7 @@ typedef struct
{
size_t dls_size; /* Size in bytes of the whole buffer. */
unsigned int dls_cnt; /* Number of elements in `dls_serpath'. */
- Dl_serpath dls_serpath[1]; /* Actually longer, dls_cnt elements. */
+ Dl_serpath dls_serpath[__GLIBC_FLEXIBLE_ARRAY_MEMBER /* dls_cnt */];
} Dl_serinfo;
#endif /* __USE_GNU */
@@ -141,6 +141,7 @@
#undef __KERNEL_STRICT_NAMES
#undef __GLIBC_USE_DEPRECATED_GETS
#undef __GLIBC_USE_DEPRECATED_SCANF
+#undef __GLIBC_FLEXIBLE_ARRAY_MEMBER
/* Suppress kernel-name space pollution unless user expressedly asks
for it. */
@@ -423,6 +424,15 @@
# define __GLIBC_USE_DEPRECATED_SCANF 0
#endif
+/* 'struct { ...; t m[__GLIBC_FLEXIBLE_ARRAY_MEMBER]; }’ declares a
+ structure with a flexible array member m at the end in C99 or later,
+ and a structure with a size-1 array member with earlier compilers. */
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+# define __GLIBC_FLEXIBLE_ARRAY_MEMBER
+#else
+# define __GLIBC_FLEXIBLE_ARRAY_MEMBER 1
+#endif
+
/* Get definitions of __STDC_* predefined macros, if the compiler has
not preincluded this header automatically. */
#include <stdc-predef.h>