public inbox for elfutils@sourceware.org
 help / color / mirror / Atom feed
* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-07 22:24 Mark Wielaard
  0 siblings, 0 replies; 34+ messages in thread
From: Mark Wielaard @ 2015-10-07 22:24 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 251 bytes --]

On Tue, Oct 06, 2015 at 04:17:16PM -0700, Chih-hung Hsieh wrote:
> Please take a look of the new attached 0007*patch.

Thanks, pushed to master. I thought Alexander had a good point,
but we can deal with that in a later patch.

Cheers,

Mark

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-27  8:30 Mark Wielaard
  0 siblings, 0 replies; 34+ messages in thread
From: Mark Wielaard @ 2015-10-27  8:30 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 1080 bytes --]

On Mon, 2015-10-26 at 23:00 +0300, Alexander Cherepanov wrote:
> On 2015-10-07 18:23, Mark Wielaard wrote:
> >>> You can build and run elfutils
> >>> and the tests with configure --enable-sanitize-undefined to use ubsan
> >>> checking.
> >>
> >> Nice.
> >
> > I am using it together with the afl fuzzer for finding issues.
> > And it found some nasty ones.
> 
> Glad to hear it. Are you keeping the found samples? It would be nice to 
> have them publicly available as a base for fuzzing other projects too.

No sorry. I probably should. What I usually do is either pick one of the
crashers from an old bug like
https://bugzilla.redhat.com/show_bug.cgi?id=1170810
and strip any unneeded sections from the file (the afl tools don't seem
to be able to reduce these automatically, so you'll have to create a
minimal valid ELF file by hand). Or when I write a new testcase I build
everything with --enable-sanitize-undefined and run the test under afl
with a minimal testfile that is also used in the testsuite as input for
a couple of days.

Cheers,

Mark

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-26 20:00 Alexander Cherepanov
  0 siblings, 0 replies; 34+ messages in thread
From: Alexander Cherepanov @ 2015-10-26 20:00 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 1560 bytes --]

On 2015-10-07 18:23, Mark Wielaard wrote:
> On Wed, 2015-10-07 at 02:24 +0300, Alexander Cherepanov wrote:
>> On 2015-10-05 21:45, Mark Wielaard wrote:
>>> On Fri, Oct 02, 2015 at 12:10:47AM +0300, Alexander Cherepanov wrote:
>>>> Given that the current approach (before the patch) already required to write
>>>> superfluous "->" perhaps an approach requiring a superfluous "*" will fit?
>>>> Like this:
>>>>
>>>>     void *data = malloc (...);
>>>>     T32 (*a32)[n] = data;
>>>>     T64 (*a64)[n] = data;
>>>>
>>>> Then the use looks like "(*a32)[i].member". Clang seems to be happy and its
>>>> UBSAN works fine.
>>>
>>> If that works that would probably be preferred since then ubsan can see
>>> the array bounds and help catch issues.
>>
>> I believe it was not working in gcc 4.9. It works in newer gcc?
>
> I am currently using gcc 5.1 where it definitely works.
> -fsanitize=undefined finds array accesses outside variable arrays just
> fine. It didn't work with gcc 4.8 though. I thought it also worked with
> 4.9, but haven't checked.

Ok, thanks. Indeed, a fresh gcc (and clang) is worth switching to.

>>> You can build and run elfutils
>>> and the tests with configure --enable-sanitize-undefined to use ubsan
>>> checking.
>>
>> Nice.
>
> I am using it together with the afl fuzzer for finding issues.
> And it found some nasty ones.

Glad to hear it. Are you keeping the found samples? It would be nice to 
have them publicly available as a base for fuzzing other projects too.

-- 
Alexander Cherepanov

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-08  7:04 Mark Wielaard
  0 siblings, 0 replies; 34+ messages in thread
From: Mark Wielaard @ 2015-10-08  7:04 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 140 bytes --]

On Wed, 2015-10-07 at 16:46 -0700, Chih-hung Hsieh wrote:
> Your 0001-Allocate*path looked very clean to me.

Thanks, pushed to master.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-07 23:46 Chih-Hung Hsieh
  0 siblings, 0 replies; 34+ messages in thread
From: Chih-Hung Hsieh @ 2015-10-07 23:46 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 3484 bytes --]

Mark,

Your 0001-Allocate*path looked very clean to me.
I look forward to this change for merging into Android.
After this, the only thing clang complains about should be the nested
functions.

Yes, it is good to use new tools for additional checks, as long as there is
still a way to compile with older gcc and clang on Android. Sometimes we
add #ifdef ANDROID or #ifdef __clang__ to port an external project into
Android, but I would like to minimize those changes. Thanks.

-- chh


On Wed, Oct 7, 2015 at 3:45 PM, Mark Wielaard <mjw@redhat.com> wrote:

> On Wed, 2015-10-07 at 09:15 -0700, Chih-hung Hsieh wrote:
> > > I am currently using gcc 5.1 where it definitely works.
> > > -fsanitize=undefined finds array accesses outside variable arrays just
> > > fine. It didn't work with gcc 4.8 though. I thought it also worked with
> > > 4.9, but haven't checked.
> > >
> > What errors were reported from gcc?
> > I tested the modified elfutils with
> >   gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04)
> >  and did not see any error.
>
> gcc 4.8 is a bit old. You probably should use a newer gcc release.
> The configure --enable-sanitize-undefined check will make sure GCC is
> recent enough to support -fsanitize=undefined (it will tell you at the
> end whether or not it succeeded). The GCC ubsan sanitizer works at
> runtime, so if there were still issues in the codebase that would be
> triggered by one of the testcases then a test during make chec would
> fail. When building/running by hand you'll see something like: runtime
> error: index 16 out of bounds for type 'int [*]' indicating that it was
> a variable bound array indexed beyond the end. Obviously no known issues
> are left in the code base at this time. But several were found by
> building with--enable-sanitize-undefined and running a fuzzer over
> various elfutils tools. There is a long list of different undefined
> behavior issues gcc -fsanitize=undefined can catch:
>
> https://gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc/Debugging-Options.html#index-fsanitize_003dundefined-652
>
> > On the other hand, it would be better not to depend on gcc 5.1 features,
> as
> > Android is staying with gcc 4.9 and moving forward with clang.
>
> For elfutils we definitely want to depend on making sure the code is
> warning free and sanitizer error free with the latest GCC release. It
> would be silly not to because newer gcc versions produce better code,
> have more accurate warnings and through the sanitizers catch lots of
> tricky issues not caught by older gcc releases or other compilers.
>
> That doesn't mean we shouldn't support older compilers. The last release
> was tested on various architectures against versions going all the way
> back to gcc 4.1 (although I like to drop supporting such ancient
> compilers at some point, my suggestion is to only test explicitly
> against gcc 4.4+ starting from 0.164 and not make warnings on older
> versions release blockers). Likewise it might be interesting to see if
> we can support clang even though it is missing some features at the
> moment we depend on. As long as it improves the code (and I think your
> patches up to now have, if only because we are forced to reevaluate the
> code and fix any latent issues we find). And we did even add two
> warnings that clang found to gcc, so we can rely on GCC 6 once it is
> released to catch even more issues for us.
>
> Cheers,
>
> Mark
>

[-- Attachment #2: attachment.html --]
[-- Type: text/html, Size: 4181 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-07 22:45 Mark Wielaard
  0 siblings, 0 replies; 34+ messages in thread
From: Mark Wielaard @ 2015-10-07 22:45 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 2805 bytes --]

On Wed, 2015-10-07 at 09:15 -0700, Chih-hung Hsieh wrote:
> > I am currently using gcc 5.1 where it definitely works.
> > -fsanitize=undefined finds array accesses outside variable arrays just
> > fine. It didn't work with gcc 4.8 though. I thought it also worked with
> > 4.9, but haven't checked.
> >
> What errors were reported from gcc?
> I tested the modified elfutils with
>   gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04)
>  and did not see any error.

gcc 4.8 is a bit old. You probably should use a newer gcc release.
The configure --enable-sanitize-undefined check will make sure GCC is
recent enough to support -fsanitize=undefined (it will tell you at the
end whether or not it succeeded). The GCC ubsan sanitizer works at
runtime, so if there were still issues in the codebase that would be
triggered by one of the testcases then a test during make chec would
fail. When building/running by hand you'll see something like: runtime
error: index 16 out of bounds for type 'int [*]' indicating that it was
a variable bound array indexed beyond the end. Obviously no known issues
are left in the code base at this time. But several were found by
building with--enable-sanitize-undefined and running a fuzzer over
various elfutils tools. There is a long list of different undefined
behavior issues gcc -fsanitize=undefined can catch:
https://gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc/Debugging-Options.html#index-fsanitize_003dundefined-652

> On the other hand, it would be better not to depend on gcc 5.1 features, as
> Android is staying with gcc 4.9 and moving forward with clang.

For elfutils we definitely want to depend on making sure the code is
warning free and sanitizer error free with the latest GCC release. It
would be silly not to because newer gcc versions produce better code,
have more accurate warnings and through the sanitizers catch lots of
tricky issues not caught by older gcc releases or other compilers.

That doesn't mean we shouldn't support older compilers. The last release
was tested on various architectures against versions going all the way
back to gcc 4.1 (although I like to drop supporting such ancient
compilers at some point, my suggestion is to only test explicitly
against gcc 4.4+ starting from 0.164 and not make warnings on older
versions release blockers). Likewise it might be interesting to see if
we can support clang even though it is missing some features at the
moment we depend on. As long as it improves the code (and I think your
patches up to now have, if only because we are forced to reevaluate the
code and fix any latent issues we find). And we did even add two
warnings that clang found to gcc, so we can rely on GCC 6 once it is
released to catch even more issues for us.

Cheers,

Mark

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-07 22:35 Roland McGrath
  0 siblings, 0 replies; 34+ messages in thread
From: Roland McGrath @ 2015-10-07 22:35 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 23 bytes --]

Looks sensible to me.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-07 22:29 Mark Wielaard
  0 siblings, 0 replies; 34+ messages in thread
From: Mark Wielaard @ 2015-10-07 22:29 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 726 bytes --]

On Wed, Oct 07, 2015 at 02:38:45AM +0300, Alexander Cherepanov wrote:
> If the amount of allocated memory is explicitly calculated as above it's
> potentially possible to use exact amount, e.g. phnum * sizeof (Elf32_Phdr)
> for p32 (and assign NULL to p64) or phnum * MAX (sizeof (Elf64_Phdr) for p64
> (and assign NULL to p32). I'm not familiar with the codebase enough to judge
> if it's feasible. Just to make sure that this aspect is not overlooked.

Thanks that is a good point. I think originally it was thought that
the number of headers would always be small, so it wouldn't really
matter. But it seems like a good idea to only allocate what we really
need. The attached patch does this.

Cheers,

Mark

[-- Attachment #2: 0001-Allocate-exact-amount-of-bytes-for-phdrs-and-shdrs.patch --]
[-- Type: text/plain, Size: 10149 bytes --]

>From f22df508fce15d79820aaacd5300f0e916f52e5c Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mjw@redhat.com>
Date: Thu, 8 Oct 2015 00:16:03 +0200
Subject: [PATCH] Allocate exact amount of bytes for phdrs and shdrs.

Signed-off-by: Mark Wielaard <mjw@redhat.com>
---
 libdwfl/ChangeLog                    | 10 +++++++
 libdwfl/dwfl_module_getdwarf.c       | 51 ++++++++++++++++++------------------
 libdwfl/dwfl_segment_report_module.c | 13 ++++-----
 libdwfl/elf-from-memory.c            | 16 +++++------
 src/ChangeLog                        |  6 +++++
 src/unstrip.c                        | 18 +++++--------
 6 files changed, 61 insertions(+), 53 deletions(-)

diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 949a372..ee41405 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,13 @@
+2015-10-07  Mark Wielaard  <mjw@redhat.com>
+
+	* dwfl_module_getdwarf.c (MAX): Removed.
+	(find_prelink_address_sync): Allocate exact amount of bytes for
+	phdrs and shdrs.
+	* dwfl_segment_report_module.c (dwfl_segment_report_module):
+	Likewise for phdrs.
+	* elf-from-memory.c (MAX): Removed.
+	(elf_from_remote_memory): Allocate exact amount of bytes for phdrs.
+
 2015-10-05  Chih-Hung Hsieh <chh@google.com>
 
 	* dwfl_module_getdwarf.c (find_prelink_address_sync): Do not use
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index c339040..a359057 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -34,10 +34,6 @@
 #include "../libdw/libdwP.h"	/* DWARF_E_* values are here.  */
 #include "../libelf/libelfP.h"
 
-#ifndef MAX
-# define MAX(a, b) ((a) > (b) ? (a) : (b))
-#endif
-
 static inline Dwfl_Error
 open_elf_file (Elf **elf, int *fd, char **name)
 {
@@ -371,15 +367,13 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
   src.d_size = phnum * phentsize;
 
   GElf_Addr undo_interp = 0;
+  bool class32 = ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32;
   {
-    if (unlikely (phnum >
-                  SIZE_MAX / MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr))))
+    size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr);
+    if (unlikely (phnum > SIZE_MAX / phdr_size))
       return DWFL_E_NOMEM;
-    const size_t phdrs_bytes =
-        phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+    const size_t phdrs_bytes = phnum * phdr_size;
     void *phdrs = malloc (phdrs_bytes);
-    Elf32_Phdr (*p32)[phnum] = phdrs;
-    Elf64_Phdr (*p64)[phnum] = phdrs;
     if (unlikely (phdrs == NULL))
       return DWFL_E_NOMEM;
     dst.d_buf = phdrs;
@@ -390,8 +384,9 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
 	free (phdrs);
 	return DWFL_E_LIBELF;
       }
-    if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
+    if (class32)
       {
+	Elf32_Phdr (*p32)[phnum] = phdrs;
 	for (uint_fast16_t i = 0; i < phnum; ++i)
 	  if ((*p32)[i].p_type == PT_INTERP)
 	    {
@@ -401,6 +396,7 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
       }
     else
       {
+	Elf64_Phdr (*p64)[phnum] = phdrs;
 	for (uint_fast16_t i = 0; i < phnum; ++i)
 	  if ((*p64)[i].p_type == PT_INTERP)
 	    {
@@ -418,14 +414,11 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
   src.d_type = ELF_T_SHDR;
   src.d_size = gelf_fsize (mod->main.elf, ELF_T_SHDR, shnum - 1, EV_CURRENT);
 
-  if (unlikely (shnum - 1  >
-                SIZE_MAX / MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr))))
+  size_t shdr_size = class32 ? sizeof (Elf32_Shdr) : sizeof (Elf64_Shdr);
+  if (unlikely (shnum - 1  > SIZE_MAX / shdr_size))
     return DWFL_E_NOMEM;
-  const size_t shdrs_bytes =
-      (shnum - 1) * MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr));
+  const size_t shdrs_bytes = (shnum - 1) * shdr_size;
   void *shdrs = malloc (shdrs_bytes);
-  Elf32_Shdr (*s32)[shnum - 1] = shdrs;
-  Elf64_Shdr (*s64)[shnum - 1] = shdrs;
   if (unlikely (shdrs == NULL))
     return DWFL_E_NOMEM;
   dst.d_buf = shdrs;
@@ -490,16 +483,22 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
       mod->main.address_sync = highest;
 
       highest = 0;
-      if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
-	for (size_t i = 0; i < shnum - 1; ++i)
-	  consider_shdr (undo_interp, (*s32)[i].sh_type,
-			 (*s32)[i].sh_flags, (*s32)[i].sh_addr,
-			 (*s32)[i].sh_size);
+      if (class32)
+	{
+	  Elf32_Shdr (*s32)[shnum - 1] = shdrs;
+	  for (size_t i = 0; i < shnum - 1; ++i)
+	    consider_shdr (undo_interp, (*s32)[i].sh_type,
+			   (*s32)[i].sh_flags, (*s32)[i].sh_addr,
+			   (*s32)[i].sh_size);
+	}
       else
-	for (size_t i = 0; i < shnum - 1; ++i)
-	  consider_shdr (undo_interp, (*s64)[i].sh_type,
-			 (*s64)[i].sh_flags, (*s64)[i].sh_addr,
-			 (*s64)[i].sh_size);
+	{
+	  Elf64_Shdr (*s64)[shnum - 1] = shdrs;
+	  for (size_t i = 0; i < shnum - 1; ++i)
+	    consider_shdr (undo_interp, (*s64)[i].sh_type,
+			   (*s64)[i].sh_flags, (*s64)[i].sh_addr,
+			   (*s64)[i].sh_size);
+	}
 
       if (highest > file->vaddr)
 	file->address_sync = highest;
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index 92f691d..ca86c31 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -408,14 +408,12 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
   xlatefrom.d_buf = ph_buffer;
 
-  if (unlikely (phnum >
-                SIZE_MAX / MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr))))
+  bool class32 = ei_class == ELFCLASS32;
+  size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr);
+  if (unlikely (phnum > SIZE_MAX / phdr_size))
     return finish ();
-  const size_t phdrsp_bytes =
-      phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+  const size_t phdrsp_bytes = phnum * phdr_size;
   phdrsp = malloc (phdrsp_bytes);
-  Elf32_Phdr (*p32)[phnum] = phdrsp;
-  Elf64_Phdr (*p64)[phnum] = phdrsp;
   if (unlikely (phdrsp == NULL))
     return finish ();
 
@@ -577,6 +575,9 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	break;
       }
   }
+
+  Elf32_Phdr (*p32)[phnum] = phdrsp;
+  Elf64_Phdr (*p64)[phnum] = phdrsp;
   if (ei_class == ELFCLASS32)
     {
       if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
diff --git a/libdwfl/elf-from-memory.c b/libdwfl/elf-from-memory.c
index 5be21bb..dd42e95 100644
--- a/libdwfl/elf-from-memory.c
+++ b/libdwfl/elf-from-memory.c
@@ -38,10 +38,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#ifndef MAX
-# define MAX(a, b) ((a) > (b) ? (a) : (b))
-#endif
-
 /* Reconstruct an ELF file by reading the segments out of remote memory
    based on the ELF file header at EHDR_VMA and the ELF program headers it
    points to.  If not null, *LOADBASEP is filled in with the difference
@@ -195,17 +191,15 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
       xlatefrom.d_buf = buffer;
     }
 
-  if (unlikely (phnum >
-                SIZE_MAX / MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr))))
+  bool class32 = ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32;
+  size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr);
+  if (unlikely (phnum > SIZE_MAX / phdr_size))
     {
       free (buffer);
       goto no_memory;
     }
-  const size_t phdrsp_bytes =
-      phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+  const size_t phdrsp_bytes = phnum * phdr_size;
   phdrsp = malloc (phdrsp_bytes);
-  Elf32_Phdr (*p32)[phnum] = phdrsp;
-  Elf64_Phdr (*p64)[phnum] = phdrsp;
   if (unlikely (phdrsp == NULL))
     {
       free (buffer);
@@ -221,6 +215,8 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
   GElf_Off segments_end_mem = 0;
   GElf_Addr loadbase = ehdr_vma;
   bool found_base = false;
+  Elf32_Phdr (*p32)[phnum] = phdrsp;
+  Elf64_Phdr (*p64)[phnum] = phdrsp;
   switch (ehdr.e32.e_ident[EI_CLASS])
     {
       /* Sanity checks segments and calculates segment_end,
diff --git a/src/ChangeLog b/src/ChangeLog
index e674401..f577885 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,9 @@
+2015-10-07  Mark Wielaard  <mjw@redhat.com>
+
+	* unstrip.c (MAX): Removed.
+	(find_alloc_sections_prelink): Allocate exact amount of bytes for
+	shdrs.
+
 2015-10-05  Chih-Hung Hsieh <chh@google.com>
 
 	* unstrip.c (find_alloc_sections_prelink): Do not allocate
diff --git a/src/unstrip.c b/src/unstrip.c
index 2a35dec..b725987 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -54,10 +54,6 @@
 # define _(str) gettext (str)
 #endif
 
-#ifndef MAX
-# define MAX(a, b) ((a) > (b) ? (a) : (b))
-#endif
-
 /* Name and version of program.  */
 static void print_version (FILE *stream, struct argp_state *state);
 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
@@ -1017,15 +1013,13 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	error (EXIT_FAILURE, 0, _("invalid contents in '%s' section"),
 	       ".gnu.prelink_undo");
 
-      if (unlikely ((shnum - 1) >
-                    SIZE_MAX / MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr))))
+      bool class32 = ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32;
+      size_t shsize = class32 ? sizeof (Elf32_Shdr) : sizeof (Elf64_Shdr);
+      if (unlikely ((shnum - 1) > SIZE_MAX / shsize))
 	error (EXIT_FAILURE, 0, _("overflow with shnum = %zu in '%s' section"),
 	       (size_t) shnum, ".gnu.prelink_undo");
-      const size_t shdr_bytes =
-          (shnum - 1) * MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr));
+      const size_t shdr_bytes = (shnum - 1) * shsize;
       void *shdr = xmalloc (shdr_bytes);
-      Elf32_Shdr (*s32)[shnum - 1] = shdr;
-      Elf64_Shdr (*s64)[shnum - 1] = shdr;
       dst.d_buf = shdr;
       dst.d_size = shdr_bytes;
       ELF_CHECK (gelf_xlatetom (main, &dst, &src,
@@ -1036,7 +1030,9 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
       for (size_t i = 0; i < shnum - 1; ++i)
 	{
 	  struct section *sec = &undo_sections[undo_nalloc];
-	  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
+	  Elf32_Shdr (*s32)[shnum - 1] = shdr;
+	  Elf64_Shdr (*s64)[shnum - 1] = shdr;
+	  if (class32)
 	    {
 #define COPY(field) sec->shdr.field = (*s32)[i].field
 	      COPY (sh_name);
-- 
2.4.3


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-07 16:15 Chih-Hung Hsieh
  0 siblings, 0 replies; 34+ messages in thread
From: Chih-Hung Hsieh @ 2015-10-07 16:15 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 977 bytes --]

>
> > >>    void *data = malloc (...);
> > >>    T32 (*a32)[n] = data;
> > >>    T64 (*a64)[n] = data;
> > >>
> > >> Then the use looks like "(*a32)[i].member". Clang seems to be happy
> and its
> > >> UBSAN works fine.
> > >
> > > If that works that would probably be preferred since then ubsan can see
> > > the array bounds and help catch issues.
> >
> > I believe it was not working in gcc 4.9. It works in newer gcc?
>
> I am currently using gcc 5.1 where it definitely works.
> -fsanitize=undefined finds array accesses outside variable arrays just
> fine. It didn't work with gcc 4.8 though. I thought it also worked with
> 4.9, but haven't checked.
>

What errors were reported from gcc?
I tested the modified elfutils with
  gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04)
 and did not see any error.

On the other hand, it would be better not to depend on gcc 5.1 features, as
Android is staying with gcc 4.9 and moving forward with clang.

[-- Attachment #2: attachment.html --]
[-- Type: text/html, Size: 1493 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-07 15:23 Mark Wielaard
  0 siblings, 0 replies; 34+ messages in thread
From: Mark Wielaard @ 2015-10-07 15:23 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 1267 bytes --]

On Wed, 2015-10-07 at 02:24 +0300, Alexander Cherepanov wrote:
> On 2015-10-05 21:45, Mark Wielaard wrote:
> > On Fri, Oct 02, 2015 at 12:10:47AM +0300, Alexander Cherepanov wrote:
> >> Given that the current approach (before the patch) already required to write
> >> superfluous "->" perhaps an approach requiring a superfluous "*" will fit?
> >> Like this:
> >>
> >>    void *data = malloc (...);
> >>    T32 (*a32)[n] = data;
> >>    T64 (*a64)[n] = data;
> >>
> >> Then the use looks like "(*a32)[i].member". Clang seems to be happy and its
> >> UBSAN works fine.
> >
> > If that works that would probably be preferred since then ubsan can see
> > the array bounds and help catch issues.
> 
> I believe it was not working in gcc 4.9. It works in newer gcc?

I am currently using gcc 5.1 where it definitely works.
-fsanitize=undefined finds array accesses outside variable arrays just
fine. It didn't work with gcc 4.8 though. I thought it also worked with
4.9, but haven't checked.

> > You can build and run elfutils
> > and the tests with configure --enable-sanitize-undefined to use ubsan
> > checking.
> 
> Nice.

I am using it together with the afl fuzzer for finding issues.
And it found some nasty ones.

Cheers,

Mark

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-06 23:38 Alexander Cherepanov
  0 siblings, 0 replies; 34+ messages in thread
From: Alexander Cherepanov @ 2015-10-06 23:38 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 845 bytes --]

On 2015-10-07 02:17, Chih-hung Hsieh wrote:
 > +    if (unlikely (phnum >
 > +                  SIZE_MAX / MAX (sizeof (Elf32_Phdr), sizeof 
(Elf64_Phdr))))
 > +      return DWFL_E_NOMEM;
 > +    const size_t phdrs_bytes =
 > +        phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
 > +    void *phdrs = malloc (phdrs_bytes);
 > +    Elf32_Phdr (*p32)[phnum] = phdrs;
 > +    Elf64_Phdr (*p64)[phnum] = phdrs;

If the amount of allocated memory is explicitly calculated as above it's 
potentially possible to use exact amount, e.g. phnum * sizeof 
(Elf32_Phdr) for p32 (and assign NULL to p64) or phnum * MAX (sizeof 
(Elf64_Phdr) for p64 (and assign NULL to p32). I'm not familiar with the 
codebase enough to judge if it's feasible. Just to make sure that this 
aspect is not overlooked.

-- 
Alexander Cherepanov

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-06 23:24 Alexander Cherepanov
  0 siblings, 0 replies; 34+ messages in thread
From: Alexander Cherepanov @ 2015-10-06 23:24 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 2716 bytes --]

On 2015-10-05 21:45, Mark Wielaard wrote:
> On Fri, Oct 02, 2015 at 12:10:47AM +0300, Alexander Cherepanov wrote:
>> On 2015-09-16 18:25, Mark Wielaard wrote:
>>> On Fri, 2015-09-11 at 12:22 -0700, Roland McGrath wrote:
>>>> It looks fine to me from a quick skim, but Mark should review and test it too.
>>>
>>> I am not super enthusiastic about this change, it seems to just take
>>> away type/size information that the compiler/bounds checking tools can
>>> use.
>>
>> I'm not sure I fully understand the problem. As I understand it unions of
>> VLAs are not Ok while VLAs are Ok and even desirable due to bounds checking,
>> right?
>
> There are two issues. First with GCC VLA types are OK and desired compared
> to types not using bounds. But if such a VLAs might be unbounded then they
> should not be stack allocated (this is enforced by building with
> -Wstack-usage except for a couple of files that haven't been converted).

Great.

> Secondly there are people who want to use clang to build elfutils.

Yes, this nice to have.

> clang
> doesn't support various GNU extensions used in the code like VLAs. So
> for those people any VLA type seems problematic.

VLAs are in C99 (but optional in C11) and are supported by clang[1]. But 
VLAs inside structs/unions are prohibited by the standards, are a gcc 
extension and are not supported by clang.

[1] http://clang.llvm.org/compatibility.html#vla

>> Why not just use VLAs of unions? Cold memory?
>
> I am not sure clang supports such VLA types.

Yes, it should work.

> If it does, then I would say
> VLAs of unions are preferred above a type that doesn't include bounds.

In comparison with a pointer-to-array (classical Pascal) approach it has 
pros and cons.

Pros:
- shorter declaration (no malloc, no calculations).
Cons:
- bounded arrays only;
- requires more memory (for 32-bit case);
- non-continuous memory (for 32-bit case).

Not sure if these cons are important.

>> Given that the current approach (before the patch) already required to write
>> superfluous "->" perhaps an approach requiring a superfluous "*" will fit?
>> Like this:
>>
>>    void *data = malloc (...);
>>    T32 (*a32)[n] = data;
>>    T64 (*a64)[n] = data;
>>
>> Then the use looks like "(*a32)[i].member". Clang seems to be happy and its
>> UBSAN works fine.
>
> If that works that would probably be preferred since then ubsan can see
> the array bounds and help catch issues.

I believe it was not working in gcc 4.9. It works in newer gcc?

> You can build and run elfutils
> and the tests with configure --enable-sanitize-undefined to use ubsan
> checking.

Nice.

-- 
Alexander Cherepanov

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-06 23:17 Chih-Hung Hsieh
  0 siblings, 0 replies; 34+ messages in thread
From: Chih-Hung Hsieh @ 2015-10-06 23:17 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 2723 bytes --]

Mark,

I appreciate your efforts to make these and other changes about nested
functions. We can see soon elfutils will compile with clang/llvm on Android.
Please take a look of the new attached 0007*patch.
Thanks.


On Tue, Oct 6, 2015 at 2:25 PM, Mark Wielaard <mjw@redhat.com> wrote:

> On Mon, 2015-10-05 at 14:15 -0700, Chih-hung Hsieh wrote:
> > Please review attached 0006*patch with the new changed I mentioned
> > previously. Thanks.
>
> Very nice. Now we get to keep the array bounds.
> You forgot them in one place though:
>
> > diff --git a/libelf/elf_getarsym.c b/libelf/elf_getarsym.c
> > index 1ab94ca..f5ee3cb 100644
> > --- a/libelf/elf_getarsym.c
> > +++ b/libelf/elf_getarsym.c
> > @@ -201,11 +201,7 @@ elf_getarsym (Elf *elf, size_t *ptr)
> >        elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len);
> >        if (elf->state.ar.ar_sym != NULL)
> >         {
> > -         union
> > -         {
> > -           uint32_t u32[n];
> > -           uint64_t u64[n];
> > -         } *file_data;
> > +         void *file_data; /* unit32_t[n] or uint64_t[n] */
> >           char *str_data;
> >           size_t sz = n * w;
> >
> > @@ -272,7 +268,7 @@ elf_getarsym (Elf *elf, size_t *ptr)
> >               arsym[cnt].as_name = str_data;
> >               if (index64_p)
> >                 {
> > -                 uint64_t tmp = file_data->u64[cnt];
> > +                 uint64_t tmp = ((uint64_t *) file_data)[cnt];
> >                   if (__BYTE_ORDER == __LITTLE_ENDIAN)
> >                     tmp = bswap_64 (tmp);
> >
> > @@ -294,9 +290,9 @@ elf_getarsym (Elf *elf, size_t *ptr)
> >                     }
> >                 }
> >               else if (__BYTE_ORDER == __LITTLE_ENDIAN)
> > -               arsym[cnt].as_off = bswap_32 (file_data->u32[cnt]);
> > +               arsym[cnt].as_off = bswap_32 (((uint32_t *)
> file_data)[cnt]);
> >               else
> > -               arsym[cnt].as_off = file_data->u32[cnt];
> > +               arsym[cnt].as_off = ((uint32_t *) file_data)[cnt];
> >
> >               arsym[cnt].as_hash = _dl_elf_hash (str_data);
> >               str_data = rawmemchr (str_data, '\0') + 1;
>
> Can you use the same pattern here so we keep the [n] bound?
>
> And one nitpick (sorry):
>
> > @@ -1013,13 +1017,17 @@ find_alloc_sections_prelink (Elf *debug,
> Elf_Data *debug_shstrtab,
> > [...]
> > +      Elf32_Shdr (*s32)[shnum - 1] = shdr;
> > +      Elf64_Shdr (*s64) [shnum - 1]= shdr;
>
>                          ^-----------^
> Move that space please.
>
> We are really there now, sorry for the somewhat long review/please
> rewrite (yet again) cycle.
>
> Thanks,
>
> Mark
>

[-- Attachment #2: attachment.html --]
[-- Type: text/html, Size: 3605 bytes --]

[-- Attachment #3: 0007-Do-without-union-of-variable-length-arrays.patch --]
[-- Type: application/octet-stream, Size: 28284 bytes --]

From 3a943b651ac63cfb3827bb2667c8582aec5335ee Mon Sep 17 00:00:00 2001
From: Chih-Hung Hsieh <chh@google.com>
Date: Tue, 6 Oct 2015 15:53:15 -0700
Subject: [PATCH] Do without union of variable length arrays.

Prepare to compile with clang.

A union like
  { T32 a32[n]; T64 a64[n]; } u;
is expanded to
  size_t nbytes = n * MAX(sizeof(T32), sizeof(T64));
  void *data = malloc(nbytes);
  T32 (*a32)[n] = data;
  T64 (*a64)[n] = data;

Signed-off-by: Chih-Hung Hsieh <chh@google.com>
---
 libdwfl/ChangeLog                    | 10 +++++
 libdwfl/dwfl_module_getdwarf.c       | 56 +++++++++++++----------
 libdwfl/dwfl_segment_report_module.c | 69 ++++++++++++++--------------
 libdwfl/elf-from-memory.c            | 53 ++++++++++++----------
 libdwfl/link_map.c                   | 87 ++++++++++++++----------------------
 libelf/ChangeLog                     |  5 +++
 libelf/elf_getarsym.c                | 14 +++---
 src/ChangeLog                        |  8 ++++
 src/readelf.c                        | 26 +++++++----
 src/unstrip.c                        | 27 +++++++----
 10 files changed, 194 insertions(+), 161 deletions(-)

diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index ed1156e..949a372 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,13 @@
+2015-10-05  Chih-Hung Hsieh <chh@google.com>
+
+	* dwfl_module_getdwarf.c (find_prelink_address_sync): Do not use
+	union of variable length arrays.
+	* dwfl_segment_report_module.c (dwfl_segment_report_module): Likewise.
+	* elf-from-memory.c (elf_from_remote_memory): Likewise.
+	* link_map.c (auxv_format_probe): Likewise.
+	* link_map.c (report_r_debug): Likewise.
+	* link_map.c (dwfl_link_map_report): Likewise.
+
 2015-09-18  Chih-Hung Hsieh  <chh@google.com>
 
 	* relocate.c (relocate_section): Move nested function "relocate"
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index dba9d66..c339040 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -34,6 +34,10 @@
 #include "../libdw/libdwP.h"	/* DWARF_E_* values are here.  */
 #include "../libelf/libelfP.h"
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 static inline Dwfl_Error
 open_elf_file (Elf **elf, int *fd, char **name)
 {
@@ -368,16 +372,18 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
 
   GElf_Addr undo_interp = 0;
   {
-    typedef union
-    {
-      Elf32_Phdr p32[phnum];
-      Elf64_Phdr p64[phnum];
-    } phdr;
-    phdr *phdrs = malloc (sizeof (phdr));
+    if (unlikely (phnum >
+                  SIZE_MAX / MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr))))
+      return DWFL_E_NOMEM;
+    const size_t phdrs_bytes =
+        phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+    void *phdrs = malloc (phdrs_bytes);
+    Elf32_Phdr (*p32)[phnum] = phdrs;
+    Elf64_Phdr (*p64)[phnum] = phdrs;
     if (unlikely (phdrs == NULL))
       return DWFL_E_NOMEM;
     dst.d_buf = phdrs;
-    dst.d_size = sizeof (phdr);
+    dst.d_size = phdrs_bytes;
     if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
 				 ehdr.e32.e_ident[EI_DATA]) == NULL))
       {
@@ -387,18 +393,18 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
     if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
       {
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  if (phdrs->p32[i].p_type == PT_INTERP)
+	  if ((*p32)[i].p_type == PT_INTERP)
 	    {
-	      undo_interp = phdrs->p32[i].p_vaddr;
+	      undo_interp = (*p32)[i].p_vaddr;
 	      break;
 	    }
       }
     else
       {
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  if (phdrs->p64[i].p_type == PT_INTERP)
+	  if ((*p64)[i].p_type == PT_INTERP)
 	    {
-	      undo_interp = phdrs->p64[i].p_vaddr;
+	      undo_interp = (*p64)[i].p_vaddr;
 	      break;
 	    }
       }
@@ -412,16 +418,18 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
   src.d_type = ELF_T_SHDR;
   src.d_size = gelf_fsize (mod->main.elf, ELF_T_SHDR, shnum - 1, EV_CURRENT);
 
-  typedef union
-  {
-    Elf32_Shdr s32[shnum - 1];
-    Elf64_Shdr s64[shnum - 1];
-  } shdr;
-  shdr *shdrs = malloc (sizeof (shdr));
+  if (unlikely (shnum - 1  >
+                SIZE_MAX / MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr))))
+    return DWFL_E_NOMEM;
+  const size_t shdrs_bytes =
+      (shnum - 1) * MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr));
+  void *shdrs = malloc (shdrs_bytes);
+  Elf32_Shdr (*s32)[shnum - 1] = shdrs;
+  Elf64_Shdr (*s64)[shnum - 1] = shdrs;
   if (unlikely (shdrs == NULL))
     return DWFL_E_NOMEM;
   dst.d_buf = shdrs;
-  dst.d_size = sizeof (shdr);
+  dst.d_size = shdrs_bytes;
   if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
 			       ehdr.e32.e_ident[EI_DATA]) == NULL))
     {
@@ -484,14 +492,14 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
       highest = 0;
       if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
 	for (size_t i = 0; i < shnum - 1; ++i)
-	  consider_shdr (undo_interp, shdrs->s32[i].sh_type,
-			 shdrs->s32[i].sh_flags, shdrs->s32[i].sh_addr,
-			 shdrs->s32[i].sh_size);
+	  consider_shdr (undo_interp, (*s32)[i].sh_type,
+			 (*s32)[i].sh_flags, (*s32)[i].sh_addr,
+			 (*s32)[i].sh_size);
       else
 	for (size_t i = 0; i < shnum - 1; ++i)
-	  consider_shdr (undo_interp, shdrs->s64[i].sh_type,
-			 shdrs->s64[i].sh_flags, shdrs->s64[i].sh_addr,
-			 shdrs->s64[i].sh_size);
+	  consider_shdr (undo_interp, (*s64)[i].sh_type,
+			 (*s64)[i].sh_flags, (*s64)[i].sh_addr,
+			 (*s64)[i].sh_size);
 
       if (highest > file->vaddr)
 	file->address_sync = highest;
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index a0f07ad..92f691d 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -53,6 +53,10 @@
 # define MY_ELFDATA	ELFDATA2MSB
 #endif
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 
 /* Return user segment index closest to ADDR but not above it.
    If NEXT, return the closest to ADDR but not below it.  */
@@ -404,19 +408,19 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
   xlatefrom.d_buf = ph_buffer;
 
-  typedef union
-  {
-    Elf32_Phdr p32[phnum];
-    Elf64_Phdr p64[phnum];
-  } phdrsn;
-
-  phdrsp = malloc (sizeof (phdrsn));
+  if (unlikely (phnum >
+                SIZE_MAX / MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr))))
+    return finish ();
+  const size_t phdrsp_bytes =
+      phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+  phdrsp = malloc (phdrsp_bytes);
+  Elf32_Phdr (*p32)[phnum] = phdrsp;
+  Elf64_Phdr (*p64)[phnum] = phdrsp;
   if (unlikely (phdrsp == NULL))
     return finish ();
-  phdrsn *phdrs = (phdrsn *) phdrsp;
 
-  xlateto.d_buf = phdrs;
-  xlateto.d_size = sizeof (phdrsn);
+  xlateto.d_buf = phdrsp;
+  xlateto.d_size = phdrsp_bytes;
 
   /* Track the bounds of the file visible in memory.  */
   GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end.  */
@@ -579,10 +583,10 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	found_bias = false;	/* Trigger error check.  */
       else
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  consider_phdr (phdrs->p32[i].p_type,
-			 phdrs->p32[i].p_vaddr, phdrs->p32[i].p_memsz,
-			 phdrs->p32[i].p_offset, phdrs->p32[i].p_filesz,
-			 phdrs->p32[i].p_align);
+	  consider_phdr ((*p32)[i].p_type,
+			 (*p32)[i].p_vaddr, (*p32)[i].p_memsz,
+			 (*p32)[i].p_offset, (*p32)[i].p_filesz,
+			 (*p32)[i].p_align);
     }
   else
     {
@@ -590,10 +594,10 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	found_bias = false;	/* Trigger error check.  */
       else
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  consider_phdr (phdrs->p64[i].p_type,
-			 phdrs->p64[i].p_vaddr, phdrs->p64[i].p_memsz,
-			 phdrs->p64[i].p_offset, phdrs->p64[i].p_filesz,
-			 phdrs->p64[i].p_align);
+	  consider_phdr ((*p64)[i].p_type,
+			 (*p64)[i].p_vaddr, (*p64)[i].p_memsz,
+			 (*p64)[i].p_offset, (*p64)[i].p_filesz,
+			 (*p64)[i].p_align);
     }
 
   finish_portion (&ph_buffer, &ph_buffer_size);
@@ -749,44 +753,39 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
   const size_t dyn_entsize = (ei_class == ELFCLASS32
 			      ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
-  void *dyns = NULL;
   void *dyn_data = NULL;
   size_t dyn_data_size = 0;
   if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
       && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz))
     {
-      typedef union
-      {
-	Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
-	Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
-      } dynn;
-      dyns = malloc (sizeof (dynn));
+      void *dyns = malloc (dyn_filesz);
+      Elf32_Dyn (*d32)[dyn_filesz / sizeof (Elf32_Dyn)] = dyns;
+      Elf64_Dyn (*d64)[dyn_filesz / sizeof (Elf64_Dyn)] = dyns;
       if (unlikely (dyns == NULL))
 	return finish ();
-      dynn *dyn = (dynn *) dyns;
 
       xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
       xlatefrom.d_buf = (void *) dyn_data;
       xlatefrom.d_size = dyn_filesz;
-      xlateto.d_buf = dyn;
-      xlateto.d_size = sizeof (dynn);
+      xlateto.d_buf = dyns;
+      xlateto.d_size = dyn_filesz;
 
       if (ei_class == ELFCLASS32)
 	{
 	  if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
 	    for (size_t i = 0; i < dyn_filesz / sizeof (Elf32_Dyn); ++i)
-	      if (consider_dyn (dyn->d32[i].d_tag, dyn->d32[i].d_un.d_val))
+	      if (consider_dyn ((*d32)[i].d_tag, (*d32)[i].d_un.d_val))
 		break;
 	}
       else
 	{
 	  if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
 	    for (size_t i = 0; i < dyn_filesz / sizeof (Elf64_Dyn); ++i)
-	      if (consider_dyn (dyn->d64[i].d_tag, dyn->d64[i].d_un.d_val))
+	      if (consider_dyn ((*d64)[i].d_tag, (*d64)[i].d_un.d_val))
 		break;
 	}
+      free (dyns);
     }
-  free (dyns);
   finish_portion (&dyn_data, &dyn_data_size);
 
   /* We'll use the name passed in or a stupid default if not DT_SONAME.  */
@@ -901,12 +900,12 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
 	  if (ei_class == ELFCLASS32)
 	    for (uint_fast16_t i = 0; i < phnum; ++i)
-	      read_phdr (phdrs->p32[i].p_type, phdrs->p32[i].p_vaddr,
-			 phdrs->p32[i].p_offset, phdrs->p32[i].p_filesz);
+	      read_phdr ((*p32)[i].p_type, (*p32)[i].p_vaddr,
+			 (*p32)[i].p_offset, (*p32)[i].p_filesz);
 	  else
 	    for (uint_fast16_t i = 0; i < phnum; ++i)
-	      read_phdr (phdrs->p64[i].p_type, phdrs->p64[i].p_vaddr,
-			 phdrs->p64[i].p_offset, phdrs->p64[i].p_filesz);
+	      read_phdr ((*p64)[i].p_type, (*p64)[i].p_vaddr,
+			 (*p64)[i].p_offset, (*p64)[i].p_filesz);
 	}
       else
 	{
diff --git a/libdwfl/elf-from-memory.c b/libdwfl/elf-from-memory.c
index ed8f6e9..5be21bb 100644
--- a/libdwfl/elf-from-memory.c
+++ b/libdwfl/elf-from-memory.c
@@ -38,6 +38,10 @@
 #include <stdlib.h>
 #include <string.h>
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 /* Reconstruct an ELF file by reading the segments out of remote memory
    based on the ELF file header at EHDR_VMA and the ELF program headers it
    points to.  If not null, *LOADBASEP is filled in with the difference
@@ -191,22 +195,25 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
       xlatefrom.d_buf = buffer;
     }
 
-  typedef union
-  {
-    Elf32_Phdr p32[phnum];
-    Elf64_Phdr p64[phnum];
-  } phdrsn;
-
-  phdrsp = malloc (sizeof (phdrsn));
+  if (unlikely (phnum >
+                SIZE_MAX / MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr))))
+    {
+      free (buffer);
+      goto no_memory;
+    }
+  const size_t phdrsp_bytes =
+      phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+  phdrsp = malloc (phdrsp_bytes);
+  Elf32_Phdr (*p32)[phnum] = phdrsp;
+  Elf64_Phdr (*p64)[phnum] = phdrsp;
   if (unlikely (phdrsp == NULL))
     {
       free (buffer);
       goto no_memory;
     }
-  phdrsn *phdrs = (phdrsn *) phdrsp;
 
-  xlateto.d_buf = phdrs;
-  xlateto.d_size = sizeof (phdrsn);
+  xlateto.d_buf = phdrsp;
+  xlateto.d_size = phdrsp_bytes;
 
   /* Scan for PT_LOAD segments to find the total size of the file image.  */
   size_t contents_size = 0;
@@ -249,9 +256,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 			  ehdr.e32.e_ident[EI_DATA]) == NULL)
 	goto libelf_error;
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p32[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset,
-			      phdrs->p32[i].p_filesz, phdrs->p32[i].p_memsz))
+	if ((*p32)[i].p_type == PT_LOAD)
+	  if (handle_segment ((*p32)[i].p_vaddr, (*p32)[i].p_offset,
+			      (*p32)[i].p_filesz, (*p32)[i].p_memsz))
 	    goto bad_elf;
       break;
 
@@ -260,9 +267,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 			  ehdr.e64.e_ident[EI_DATA]) == NULL)
 	goto libelf_error;
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p64[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset,
-			      phdrs->p64[i].p_filesz, phdrs->p64[i].p_memsz))
+	if ((*p64)[i].p_type == PT_LOAD)
+	  if (handle_segment ((*p64)[i].p_vaddr, (*p64)[i].p_offset,
+			      (*p64)[i].p_filesz, (*p64)[i].p_memsz))
 	    goto bad_elf;
       break;
 
@@ -315,9 +322,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 
     case ELFCLASS32:
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p32[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset,
-			      phdrs->p32[i].p_filesz))
+	if ((*p32)[i].p_type == PT_LOAD)
+	  if (handle_segment ((*p32)[i].p_vaddr, (*p32)[i].p_offset,
+			      (*p32)[i].p_filesz))
 	    goto read_error;
 
       /* If the segments visible in memory didn't include the section
@@ -342,9 +349,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 
     case ELFCLASS64:
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p64[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset,
-			      phdrs->p64[i].p_filesz))
+	if ((*p64)[i].p_type == PT_LOAD)
+	  if (handle_segment ((*p64)[i].p_vaddr, (*p64)[i].p_offset,
+			      (*p64)[i].p_filesz))
 	    goto read_error;
 
       /* If the segments visible in memory didn't include the section
@@ -373,7 +380,7 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
     }
 
   free (phdrsp);
-  phdrs = phdrsp = NULL;
+  phdrsp = NULL;
 
   /* Now we have the image.  Open libelf on it.  */
 
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index 030c600..9f0b4a2 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -48,20 +48,16 @@ static bool
 auxv_format_probe (const void *auxv, size_t size,
 		   uint_fast8_t *elfclass, uint_fast8_t *elfdata)
 {
-  const union
-  {
-    char buf[size];
-    Elf32_auxv_t a32[size / sizeof (Elf32_auxv_t)];
-    Elf64_auxv_t a64[size / sizeof (Elf64_auxv_t)];
-  } *u = auxv;
+  const Elf32_auxv_t (*a32)[size / sizeof (Elf32_auxv_t)] = (void *) auxv;
+  const Elf64_auxv_t (*a64)[size / sizeof (Elf64_auxv_t)] = (void *) auxv;
 
   inline bool check64 (size_t i)
   {
     /* The AUXV pointer might not even be naturally aligned for 64-bit
        data, because note payloads in a core file are not aligned.  */
 
-    uint64_t type = read_8ubyte_unaligned_noncvt (&u->a64[i].a_type);
-    uint64_t val = read_8ubyte_unaligned_noncvt (&u->a64[i].a_un.a_val);
+    uint64_t type = read_8ubyte_unaligned_noncvt (&(*a64)[i].a_type);
+    uint64_t val = read_8ubyte_unaligned_noncvt (&(*a64)[i].a_un.a_val);
 
     if (type == BE64 (PROBE_TYPE)
 	&& val == BE64 (PROBE_VAL64))
@@ -85,8 +81,8 @@ auxv_format_probe (const void *auxv, size_t size,
     /* The AUXV pointer might not even be naturally aligned for 32-bit
        data, because note payloads in a core file are not aligned.  */
 
-    uint32_t type = read_4ubyte_unaligned_noncvt (&u->a32[i].a_type);
-    uint32_t val = read_4ubyte_unaligned_noncvt (&u->a32[i].a_un.a_val);
+    uint32_t type = read_4ubyte_unaligned_noncvt (&(*a32)[i].a_type);
+    uint32_t val = read_4ubyte_unaligned_noncvt (&(*a32)[i].a_un.a_val);
 
     if (type == BE32 (PROBE_TYPE)
 	&& val == BE32 (PROBE_VAL32))
@@ -280,29 +276,26 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
 	  return true;
       }
 
-    const union
-    {
-      Elf32_Addr a32[n];
-      Elf64_Addr a64[n];
-    } *in = vaddr - read_vaddr + buffer;
+    Elf32_Addr (*a32)[n] = vaddr - read_vaddr + buffer;
+    Elf64_Addr (*a64)[n] = (void *) a32;
 
     if (elfclass == ELFCLASS32)
       {
 	if (elfdata == ELFDATA2MSB)
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (&in->a32[i]));
+	    addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (&(*a32)[i]));
 	else
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (&in->a32[i]));
+	    addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (&(*a32)[i]));
       }
     else
       {
 	if (elfdata == ELFDATA2MSB)
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (&in->a64[i]));
+	    addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (&(*a64)[i]));
 	else
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (&in->a64[i]));
+	    addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (&(*a64)[i]));
       }
 
     return false;
@@ -861,13 +854,15 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	    }
 	  if (in_ok)
 	    {
-	      typedef union
-	      {
-		Elf32_Phdr p32;
-		Elf64_Phdr p64;
-		char data[phnum * phent];
-	      } data_buf;
-	      data_buf *buf = malloc (sizeof (data_buf));
+	      if (unlikely (phnum > SIZE_MAX / phent))
+		{
+		  __libdwfl_seterrno (DWFL_E_NOMEM);
+		  return false;
+		}
+	      size_t nbytes = phnum * phent;
+	      void *buf = malloc (nbytes);
+	      Elf32_Phdr (*p32)[phnum] = buf;
+	      Elf64_Phdr (*p64)[phnum] = buf;
 	      if (unlikely (buf == NULL))
 		{
 		  __libdwfl_seterrno (DWFL_E_NOMEM);
@@ -886,25 +881,20 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 			  (&out, &in, elfdata) != NULL))
 		{
 		  /* We are looking for PT_DYNAMIC.  */
-		  const union
-		  {
-		    Elf32_Phdr p32[phnum];
-		    Elf64_Phdr p64[phnum];
-		  } *u = (void *) buf;
 		  if (elfclass == ELFCLASS32)
 		    {
 		      for (size_t i = 0; i < phnum; ++i)
-			if (consider_phdr (u->p32[i].p_type,
-					   u->p32[i].p_vaddr,
-					   u->p32[i].p_filesz))
+			if (consider_phdr ((*p32)[i].p_type,
+					   (*p32)[i].p_vaddr,
+					   (*p32)[i].p_filesz))
 			  break;
 		    }
 		  else
 		    {
 		      for (size_t i = 0; i < phnum; ++i)
-			if (consider_phdr (u->p64[i].p_type,
-					   u->p64[i].p_vaddr,
-					   u->p64[i].p_filesz))
+			if (consider_phdr ((*p64)[i].p_type,
+					   (*p64)[i].p_vaddr,
+					   (*p64)[i].p_filesz))
 			  break;
 		    }
 		}
@@ -955,13 +945,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	  if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size,
 				  dyn_vaddr, dyn_filesz, memory_callback_arg))
 	    {
-	      typedef union
-	      {
-		Elf32_Dyn d32;
-		Elf64_Dyn d64;
-		char data[dyn_filesz];
-	      } data_buf;
-	      data_buf *buf = malloc (sizeof (data_buf));
+	      void *buf = malloc (dyn_filesz);
+	      Elf32_Dyn (*d32)[dyn_filesz / sizeof (Elf32_Dyn)] = buf;
+	      Elf64_Dyn (*d64)[dyn_filesz / sizeof (Elf64_Dyn)] = buf;
 	      if (unlikely (buf == NULL))
 		{
 		  __libdwfl_seterrno (DWFL_E_NOMEM);
@@ -980,18 +966,13 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 			  (&out, &in, elfdata) != NULL))
 		{
 		  /* We are looking for DT_DEBUG.  */
-		  const union
-		  {
-		    Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
-		    Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
-		  } *u = (void *) buf;
 		  if (elfclass == ELFCLASS32)
 		    {
 		      size_t n = dyn_filesz / sizeof (Elf32_Dyn);
 		      for (size_t i = 0; i < n; ++i)
-			if (u->d32[i].d_tag == DT_DEBUG)
+			if ((*d32)[i].d_tag == DT_DEBUG)
 			  {
-			    r_debug_vaddr = u->d32[i].d_un.d_val;
+			    r_debug_vaddr = (*d32)[i].d_un.d_val;
 			    break;
 			  }
 		    }
@@ -999,9 +980,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 		    {
 		      size_t n = dyn_filesz / sizeof (Elf64_Dyn);
 		      for (size_t i = 0; i < n; ++i)
-			if (u->d64[i].d_tag == DT_DEBUG)
+			if ((*d64)[i].d_tag == DT_DEBUG)
 			  {
-			    r_debug_vaddr = u->d64[i].d_un.d_val;
+			    r_debug_vaddr = (*d64)[i].d_un.d_val;
 			    break;
 			  }
 		    }
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 52cc598..0b80572 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,8 @@
+2015-10-05  Chih-Hung Hsieh <chh@google.com>
+
+	* elf_getarsym.c (elf_getarsym): Do not use
+	union of variable length arrays.
+
 2015-09-24  Jose E. Marchesi  <jose.marchesi@oracle.com>
 
 	* Makefile.am (AM_CFLAGS): Use -fPIC instead of -fpic to avoid
diff --git a/libelf/elf_getarsym.c b/libelf/elf_getarsym.c
index 1ab94ca..65c67cc 100644
--- a/libelf/elf_getarsym.c
+++ b/libelf/elf_getarsym.c
@@ -201,11 +201,7 @@ elf_getarsym (Elf *elf, size_t *ptr)
       elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len);
       if (elf->state.ar.ar_sym != NULL)
 	{
-	  union
-	  {
-	    uint32_t u32[n];
-	    uint64_t u64[n];
-	  } *file_data;
+	  void *file_data; /* unit32_t[n] or uint64_t[n] */
 	  char *str_data;
 	  size_t sz = n * w;
 
@@ -267,12 +263,14 @@ elf_getarsym (Elf *elf, size_t *ptr)
 
 	  /* Now we can build the data structure.  */
 	  Elf_Arsym *arsym = elf->state.ar.ar_sym;
+	  uint64_t (*u64)[n] = file_data;
+	  uint32_t (*u32)[n] = file_data;
 	  for (size_t cnt = 0; cnt < n; ++cnt)
 	    {
 	      arsym[cnt].as_name = str_data;
 	      if (index64_p)
 		{
-		  uint64_t tmp = file_data->u64[cnt];
+		  uint64_t tmp = (*u64)[cnt];
 		  if (__BYTE_ORDER == __LITTLE_ENDIAN)
 		    tmp = bswap_64 (tmp);
 
@@ -294,9 +292,9 @@ elf_getarsym (Elf *elf, size_t *ptr)
 		    }
 		}
 	      else if (__BYTE_ORDER == __LITTLE_ENDIAN)
-		arsym[cnt].as_off = bswap_32 (file_data->u32[cnt]);
+		arsym[cnt].as_off = bswap_32 ((*u32)[cnt]);
 	      else
-		arsym[cnt].as_off = file_data->u32[cnt];
+		arsym[cnt].as_off = (*u32)[cnt];
 
 	      arsym[cnt].as_hash = _dl_elf_hash (str_data);
 	      str_data = rawmemchr (str_data, '\0') + 1;
diff --git a/src/ChangeLog b/src/ChangeLog
index 411c70b..7362879 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,11 @@
+2015-10-05  Chih-Hung Hsieh <chh@google.com>
+
+	* unstrip.c (find_alloc_sections_prelink): Do not allocate
+	on stack union types with variable length arrays; use xmalloc
+	for such dynamic sized objects.
+	* readelf.c (handle_core_item): Likewise, but use alloca
+	for small variable size data object and add assert(count < 128).
+
 2015-10-02  Mark Wielaard  <mjw@redhat.com>
 
 	* unstrip.c (copy_elided_sections): Use SH_INFO_LINK_P, not just
diff --git a/src/readelf.c b/src/readelf.c
index 33274f3..fe7bc39 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -8370,6 +8370,9 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 		  unsigned int colno, size_t *repeated_size)
 {
   uint_fast16_t count = item->count ?: 1;
+  /* Ebl_Core_Item count is always a small number.
+     Make sure the backend didn't put in some large bogus value.  */
+  assert (count < 128);
 
 #define TYPES								      \
   DO_TYPE (BYTE, Byte, "0x%.2" PRIx8, "%" PRId8);			      \
@@ -8379,11 +8382,16 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
   DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64);			      \
   DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64)
 
-#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name[count]
-  union { TYPES; } value;
+#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name
+  typedef union { TYPES; } value_t;
+  void *data = alloca (count * sizeof (value_t));
+#undef DO_TYPE
+
+#define DO_TYPE(NAME, Name, hex, dec) \
+    GElf_##Name *value_##Name __attribute__((unused)) = data
+  TYPES;
 #undef DO_TYPE
 
-  void *data = &value;
   size_t size = gelf_fsize (core, item->type, count, EV_CURRENT);
   size_t convsize = size;
   if (repeated_size != NULL)
@@ -8414,7 +8422,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
 	    colno = print_core_item (colno, ',', WRAP_COLUMN,		      \
-				     0, item->name, dec, value.Name[0]); \
+				     0, item->name, dec, value_##Name[0]); \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8430,7 +8438,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
 	    colno = print_core_item (colno, ',', WRAP_COLUMN,		      \
-				     0, item->name, hex, value.Name[0]);      \
+				     0, item->name, hex, value_##Name[0]);      \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8520,8 +8528,8 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 	{
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
-	    sec = value.Name[0];					      \
-	    usec = value.Name[1];					      \
+	    sec = value_##Name[0];					      \
+	    usec = value_##Name[1];					      \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8551,12 +8559,12 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
     case 'c':
       assert (count == 1);
       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
-			       "%c", value.Byte[0]);
+			       "%c", value_Byte[0]);
       break;
 
     case 's':
       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
-			       "%.*s", (int) count, value.Byte);
+			       "%.*s", (int) count, value_Byte);
       break;
 
     case '\n':
diff --git a/src/unstrip.c b/src/unstrip.c
index d193708..2a35dec 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -54,6 +54,10 @@
 # define _(str) gettext (str)
 #endif
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 /* Name and version of program.  */
 static void print_version (FILE *stream, struct argp_state *state);
 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
@@ -1013,13 +1017,17 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	error (EXIT_FAILURE, 0, _("invalid contents in '%s' section"),
 	       ".gnu.prelink_undo");
 
-      union
-      {
-	Elf32_Shdr s32[shnum - 1];
-	Elf64_Shdr s64[shnum - 1];
-      } shdr;
-      dst.d_buf = &shdr;
-      dst.d_size = sizeof shdr;
+      if (unlikely ((shnum - 1) >
+                    SIZE_MAX / MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr))))
+	error (EXIT_FAILURE, 0, _("overflow with shnum = %zu in '%s' section"),
+	       (size_t) shnum, ".gnu.prelink_undo");
+      const size_t shdr_bytes =
+          (shnum - 1) * MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr));
+      void *shdr = xmalloc (shdr_bytes);
+      Elf32_Shdr (*s32)[shnum - 1] = shdr;
+      Elf64_Shdr (*s64)[shnum - 1] = shdr;
+      dst.d_buf = shdr;
+      dst.d_size = shdr_bytes;
       ELF_CHECK (gelf_xlatetom (main, &dst, &src,
 				main_ehdr->e_ident[EI_DATA]) != NULL,
 		 _("cannot read '.gnu.prelink_undo' section: %s"));
@@ -1030,7 +1038,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	  struct section *sec = &undo_sections[undo_nalloc];
 	  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
 	    {
-#define COPY(field) sec->shdr.field = shdr.s32[i].field
+#define COPY(field) sec->shdr.field = (*s32)[i].field
 	      COPY (sh_name);
 	      COPY (sh_type);
 	      COPY (sh_flags);
@@ -1044,7 +1052,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 #undef	COPY
 	    }
 	  else
-	    sec->shdr = shdr.s64[i];
+	    sec->shdr = (*s64)[i];
 	  if (sec->shdr.sh_flags & SHF_ALLOC)
 	    {
 	      sec->shdr.sh_addr += bias;
@@ -1057,6 +1065,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	}
       qsort (undo_sections, undo_nalloc,
 	     sizeof undo_sections[0], compare_sections_nonrel);
+      free (shdr);
     }
 
   bool fail = false;
-- 
2.6.0.rc2.230.g3dd15c0


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-06 21:25 Mark Wielaard
  0 siblings, 0 replies; 34+ messages in thread
From: Mark Wielaard @ 2015-10-06 21:25 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 2304 bytes --]

On Mon, 2015-10-05 at 14:15 -0700, Chih-hung Hsieh wrote:
> Please review attached 0006*patch with the new changed I mentioned
> previously. Thanks.

Very nice. Now we get to keep the array bounds.
You forgot them in one place though:

> diff --git a/libelf/elf_getarsym.c b/libelf/elf_getarsym.c
> index 1ab94ca..f5ee3cb 100644
> --- a/libelf/elf_getarsym.c
> +++ b/libelf/elf_getarsym.c
> @@ -201,11 +201,7 @@ elf_getarsym (Elf *elf, size_t *ptr)
>        elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len);
>        if (elf->state.ar.ar_sym != NULL)
>         {
> -         union
> -         {
> -           uint32_t u32[n];
> -           uint64_t u64[n];
> -         } *file_data;
> +         void *file_data; /* unit32_t[n] or uint64_t[n] */
>           char *str_data;
>           size_t sz = n * w;
>  
> @@ -272,7 +268,7 @@ elf_getarsym (Elf *elf, size_t *ptr)
>               arsym[cnt].as_name = str_data;
>               if (index64_p)
>                 {
> -                 uint64_t tmp = file_data->u64[cnt];
> +                 uint64_t tmp = ((uint64_t *) file_data)[cnt];
>                   if (__BYTE_ORDER == __LITTLE_ENDIAN)
>                     tmp = bswap_64 (tmp);
>  
> @@ -294,9 +290,9 @@ elf_getarsym (Elf *elf, size_t *ptr)
>                     }
>                 }
>               else if (__BYTE_ORDER == __LITTLE_ENDIAN)
> -               arsym[cnt].as_off = bswap_32 (file_data->u32[cnt]);
> +               arsym[cnt].as_off = bswap_32 (((uint32_t *) file_data)[cnt]);
>               else
> -               arsym[cnt].as_off = file_data->u32[cnt];
> +               arsym[cnt].as_off = ((uint32_t *) file_data)[cnt];
>  
>               arsym[cnt].as_hash = _dl_elf_hash (str_data);
>               str_data = rawmemchr (str_data, '\0') + 1;

Can you use the same pattern here so we keep the [n] bound?

And one nitpick (sorry):

> @@ -1013,13 +1017,17 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
> [...]
> +      Elf32_Shdr (*s32)[shnum - 1] = shdr;
> +      Elf64_Shdr (*s64) [shnum - 1]= shdr;

                         ^-----------^
Move that space please.

We are really there now, sorry for the somewhat long review/please
rewrite (yet again) cycle.

Thanks,

Mark

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-05 21:15 Chih-Hung Hsieh
  0 siblings, 0 replies; 34+ messages in thread
From: Chih-Hung Hsieh @ 2015-10-05 21:15 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 2690 bytes --]

Please review attached 0006*patch with the new changed I mentioned
previously. Thanks.



On Mon, Oct 5, 2015 at 12:04 PM, Chih-hung Hsieh <chh@google.com> wrote:

> I will prepare a new patch with the suggested changes:
>
> (a) more efficient overflow check like
>         if (num > SIZE_MAX / elem_size)
>
> (b) replacing union of VLA with pointers to arrays like
>          void *data = malloc (...);
>          T32 (*a32)[n] = data;
>          T64 (*a64)[n] = data;
>
> Please feel free to suggest better solutions.
> Thanks.
>
>
> On Mon, Oct 5, 2015 at 11:45 AM, Mark Wielaard <mjw@redhat.com> wrote:
>
>> On Fri, Oct 02, 2015 at 12:10:47AM +0300, Alexander Cherepanov wrote:
>> > On 2015-09-16 18:25, Mark Wielaard wrote:
>> > >On Fri, 2015-09-11 at 12:22 -0700, Roland McGrath wrote:
>> > >>It looks fine to me from a quick skim, but Mark should review and
>> test it too.
>> > >
>> > >I am not super enthusiastic about this change, it seems to just take
>> > >away type/size information that the compiler/bounds checking tools can
>> > >use.
>> >
>> > I'm not sure I fully understand the problem. As I understand it unions
>> of
>> > VLAs are not Ok while VLAs are Ok and even desirable due to bounds
>> checking,
>> > right?
>>
>> There are two issues. First with GCC VLA types are OK and desired compared
>> to types not using bounds. But if such a VLAs might be unbounded then they
>> should not be stack allocated (this is enforced by building with
>> -Wstack-usage except for a couple of files that haven't been converted).
>> Secondly there are people who want to use clang to build elfutils. clang
>> doesn't support various GNU extensions used in the code like VLAs. So
>> for those people any VLA type seems problematic.
>>
>> > Why not just use VLAs of unions? Cold memory?
>>
>> I am not sure clang supports such VLA types. If it does, then I would say
>> VLAs of unions are preferred above a type that doesn't include bounds.
>>
>> > Given that the current approach (before the patch) already required to
>> write
>> > superfluous "->" perhaps an approach requiring a superfluous "*" will
>> fit?
>> > Like this:
>> >
>> >   void *data = malloc (...);
>> >   T32 (*a32)[n] = data;
>> >   T64 (*a64)[n] = data;
>> >
>> > Then the use looks like "(*a32)[i].member". Clang seems to be happy and
>> its
>> > UBSAN works fine.
>>
>> If that works that would probably be preferred since then ubsan can see
>> the array bounds and help catch issues. You can build and run elfutils
>> and the tests with configure --enable-sanitize-undefined to use ubsan
>> checking.
>>
>> Cheers,
>>
>> Mark
>>
>
>

[-- Attachment #2: attachment.html --]
[-- Type: text/html, Size: 3675 bytes --]

[-- Attachment #3: 0006-Do-without-union-of-variable-length-arrays.patch --]
[-- Type: application/octet-stream, Size: 28107 bytes --]

From cb112045776779e44b609ca7dc2d9e5032019c28 Mon Sep 17 00:00:00 2001
From: Chih-Hung Hsieh <chh@google.com>
Date: Mon, 5 Oct 2015 13:48:00 -0700
Subject: [PATCH] Do without union of variable length arrays.

Prepare to compile with clang.

A union like
  { T32 a32[n]; T64 a64[n]; } u;
is expanded to
  size_t nbytes = n * MAX(sizeof(T32), sizeof(T64));
  void *data = malloc(nbytes);
  T32 (*a32)[n] = data;
  T64 (*a64)[n] = data;

Signed-off-by: Chih-Hung Hsieh <chh@google.com>
---
 libdwfl/ChangeLog                    | 10 +++++
 libdwfl/dwfl_module_getdwarf.c       | 56 +++++++++++++----------
 libdwfl/dwfl_segment_report_module.c | 69 ++++++++++++++--------------
 libdwfl/elf-from-memory.c            | 53 ++++++++++++----------
 libdwfl/link_map.c                   | 87 ++++++++++++++----------------------
 libelf/ChangeLog                     |  5 +++
 libelf/elf_getarsym.c                | 12 ++---
 src/ChangeLog                        |  8 ++++
 src/readelf.c                        | 26 +++++++----
 src/unstrip.c                        | 27 +++++++----
 10 files changed, 192 insertions(+), 161 deletions(-)

diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index ed1156e..949a372 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,13 @@
+2015-10-05  Chih-Hung Hsieh <chh@google.com>
+
+	* dwfl_module_getdwarf.c (find_prelink_address_sync): Do not use
+	union of variable length arrays.
+	* dwfl_segment_report_module.c (dwfl_segment_report_module): Likewise.
+	* elf-from-memory.c (elf_from_remote_memory): Likewise.
+	* link_map.c (auxv_format_probe): Likewise.
+	* link_map.c (report_r_debug): Likewise.
+	* link_map.c (dwfl_link_map_report): Likewise.
+
 2015-09-18  Chih-Hung Hsieh  <chh@google.com>
 
 	* relocate.c (relocate_section): Move nested function "relocate"
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index dba9d66..c339040 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -34,6 +34,10 @@
 #include "../libdw/libdwP.h"	/* DWARF_E_* values are here.  */
 #include "../libelf/libelfP.h"
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 static inline Dwfl_Error
 open_elf_file (Elf **elf, int *fd, char **name)
 {
@@ -368,16 +372,18 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
 
   GElf_Addr undo_interp = 0;
   {
-    typedef union
-    {
-      Elf32_Phdr p32[phnum];
-      Elf64_Phdr p64[phnum];
-    } phdr;
-    phdr *phdrs = malloc (sizeof (phdr));
+    if (unlikely (phnum >
+                  SIZE_MAX / MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr))))
+      return DWFL_E_NOMEM;
+    const size_t phdrs_bytes =
+        phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+    void *phdrs = malloc (phdrs_bytes);
+    Elf32_Phdr (*p32)[phnum] = phdrs;
+    Elf64_Phdr (*p64)[phnum] = phdrs;
     if (unlikely (phdrs == NULL))
       return DWFL_E_NOMEM;
     dst.d_buf = phdrs;
-    dst.d_size = sizeof (phdr);
+    dst.d_size = phdrs_bytes;
     if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
 				 ehdr.e32.e_ident[EI_DATA]) == NULL))
       {
@@ -387,18 +393,18 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
     if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
       {
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  if (phdrs->p32[i].p_type == PT_INTERP)
+	  if ((*p32)[i].p_type == PT_INTERP)
 	    {
-	      undo_interp = phdrs->p32[i].p_vaddr;
+	      undo_interp = (*p32)[i].p_vaddr;
 	      break;
 	    }
       }
     else
       {
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  if (phdrs->p64[i].p_type == PT_INTERP)
+	  if ((*p64)[i].p_type == PT_INTERP)
 	    {
-	      undo_interp = phdrs->p64[i].p_vaddr;
+	      undo_interp = (*p64)[i].p_vaddr;
 	      break;
 	    }
       }
@@ -412,16 +418,18 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
   src.d_type = ELF_T_SHDR;
   src.d_size = gelf_fsize (mod->main.elf, ELF_T_SHDR, shnum - 1, EV_CURRENT);
 
-  typedef union
-  {
-    Elf32_Shdr s32[shnum - 1];
-    Elf64_Shdr s64[shnum - 1];
-  } shdr;
-  shdr *shdrs = malloc (sizeof (shdr));
+  if (unlikely (shnum - 1  >
+                SIZE_MAX / MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr))))
+    return DWFL_E_NOMEM;
+  const size_t shdrs_bytes =
+      (shnum - 1) * MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr));
+  void *shdrs = malloc (shdrs_bytes);
+  Elf32_Shdr (*s32)[shnum - 1] = shdrs;
+  Elf64_Shdr (*s64)[shnum - 1] = shdrs;
   if (unlikely (shdrs == NULL))
     return DWFL_E_NOMEM;
   dst.d_buf = shdrs;
-  dst.d_size = sizeof (shdr);
+  dst.d_size = shdrs_bytes;
   if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
 			       ehdr.e32.e_ident[EI_DATA]) == NULL))
     {
@@ -484,14 +492,14 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
       highest = 0;
       if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
 	for (size_t i = 0; i < shnum - 1; ++i)
-	  consider_shdr (undo_interp, shdrs->s32[i].sh_type,
-			 shdrs->s32[i].sh_flags, shdrs->s32[i].sh_addr,
-			 shdrs->s32[i].sh_size);
+	  consider_shdr (undo_interp, (*s32)[i].sh_type,
+			 (*s32)[i].sh_flags, (*s32)[i].sh_addr,
+			 (*s32)[i].sh_size);
       else
 	for (size_t i = 0; i < shnum - 1; ++i)
-	  consider_shdr (undo_interp, shdrs->s64[i].sh_type,
-			 shdrs->s64[i].sh_flags, shdrs->s64[i].sh_addr,
-			 shdrs->s64[i].sh_size);
+	  consider_shdr (undo_interp, (*s64)[i].sh_type,
+			 (*s64)[i].sh_flags, (*s64)[i].sh_addr,
+			 (*s64)[i].sh_size);
 
       if (highest > file->vaddr)
 	file->address_sync = highest;
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index a0f07ad..92f691d 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -53,6 +53,10 @@
 # define MY_ELFDATA	ELFDATA2MSB
 #endif
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 
 /* Return user segment index closest to ADDR but not above it.
    If NEXT, return the closest to ADDR but not below it.  */
@@ -404,19 +408,19 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
   xlatefrom.d_buf = ph_buffer;
 
-  typedef union
-  {
-    Elf32_Phdr p32[phnum];
-    Elf64_Phdr p64[phnum];
-  } phdrsn;
-
-  phdrsp = malloc (sizeof (phdrsn));
+  if (unlikely (phnum >
+                SIZE_MAX / MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr))))
+    return finish ();
+  const size_t phdrsp_bytes =
+      phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+  phdrsp = malloc (phdrsp_bytes);
+  Elf32_Phdr (*p32)[phnum] = phdrsp;
+  Elf64_Phdr (*p64)[phnum] = phdrsp;
   if (unlikely (phdrsp == NULL))
     return finish ();
-  phdrsn *phdrs = (phdrsn *) phdrsp;
 
-  xlateto.d_buf = phdrs;
-  xlateto.d_size = sizeof (phdrsn);
+  xlateto.d_buf = phdrsp;
+  xlateto.d_size = phdrsp_bytes;
 
   /* Track the bounds of the file visible in memory.  */
   GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end.  */
@@ -579,10 +583,10 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	found_bias = false;	/* Trigger error check.  */
       else
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  consider_phdr (phdrs->p32[i].p_type,
-			 phdrs->p32[i].p_vaddr, phdrs->p32[i].p_memsz,
-			 phdrs->p32[i].p_offset, phdrs->p32[i].p_filesz,
-			 phdrs->p32[i].p_align);
+	  consider_phdr ((*p32)[i].p_type,
+			 (*p32)[i].p_vaddr, (*p32)[i].p_memsz,
+			 (*p32)[i].p_offset, (*p32)[i].p_filesz,
+			 (*p32)[i].p_align);
     }
   else
     {
@@ -590,10 +594,10 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	found_bias = false;	/* Trigger error check.  */
       else
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  consider_phdr (phdrs->p64[i].p_type,
-			 phdrs->p64[i].p_vaddr, phdrs->p64[i].p_memsz,
-			 phdrs->p64[i].p_offset, phdrs->p64[i].p_filesz,
-			 phdrs->p64[i].p_align);
+	  consider_phdr ((*p64)[i].p_type,
+			 (*p64)[i].p_vaddr, (*p64)[i].p_memsz,
+			 (*p64)[i].p_offset, (*p64)[i].p_filesz,
+			 (*p64)[i].p_align);
     }
 
   finish_portion (&ph_buffer, &ph_buffer_size);
@@ -749,44 +753,39 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
   const size_t dyn_entsize = (ei_class == ELFCLASS32
 			      ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
-  void *dyns = NULL;
   void *dyn_data = NULL;
   size_t dyn_data_size = 0;
   if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
       && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz))
     {
-      typedef union
-      {
-	Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
-	Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
-      } dynn;
-      dyns = malloc (sizeof (dynn));
+      void *dyns = malloc (dyn_filesz);
+      Elf32_Dyn (*d32)[dyn_filesz / sizeof (Elf32_Dyn)] = dyns;
+      Elf64_Dyn (*d64)[dyn_filesz / sizeof (Elf64_Dyn)] = dyns;
       if (unlikely (dyns == NULL))
 	return finish ();
-      dynn *dyn = (dynn *) dyns;
 
       xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
       xlatefrom.d_buf = (void *) dyn_data;
       xlatefrom.d_size = dyn_filesz;
-      xlateto.d_buf = dyn;
-      xlateto.d_size = sizeof (dynn);
+      xlateto.d_buf = dyns;
+      xlateto.d_size = dyn_filesz;
 
       if (ei_class == ELFCLASS32)
 	{
 	  if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
 	    for (size_t i = 0; i < dyn_filesz / sizeof (Elf32_Dyn); ++i)
-	      if (consider_dyn (dyn->d32[i].d_tag, dyn->d32[i].d_un.d_val))
+	      if (consider_dyn ((*d32)[i].d_tag, (*d32)[i].d_un.d_val))
 		break;
 	}
       else
 	{
 	  if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
 	    for (size_t i = 0; i < dyn_filesz / sizeof (Elf64_Dyn); ++i)
-	      if (consider_dyn (dyn->d64[i].d_tag, dyn->d64[i].d_un.d_val))
+	      if (consider_dyn ((*d64)[i].d_tag, (*d64)[i].d_un.d_val))
 		break;
 	}
+      free (dyns);
     }
-  free (dyns);
   finish_portion (&dyn_data, &dyn_data_size);
 
   /* We'll use the name passed in or a stupid default if not DT_SONAME.  */
@@ -901,12 +900,12 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
 	  if (ei_class == ELFCLASS32)
 	    for (uint_fast16_t i = 0; i < phnum; ++i)
-	      read_phdr (phdrs->p32[i].p_type, phdrs->p32[i].p_vaddr,
-			 phdrs->p32[i].p_offset, phdrs->p32[i].p_filesz);
+	      read_phdr ((*p32)[i].p_type, (*p32)[i].p_vaddr,
+			 (*p32)[i].p_offset, (*p32)[i].p_filesz);
 	  else
 	    for (uint_fast16_t i = 0; i < phnum; ++i)
-	      read_phdr (phdrs->p64[i].p_type, phdrs->p64[i].p_vaddr,
-			 phdrs->p64[i].p_offset, phdrs->p64[i].p_filesz);
+	      read_phdr ((*p64)[i].p_type, (*p64)[i].p_vaddr,
+			 (*p64)[i].p_offset, (*p64)[i].p_filesz);
 	}
       else
 	{
diff --git a/libdwfl/elf-from-memory.c b/libdwfl/elf-from-memory.c
index ed8f6e9..5be21bb 100644
--- a/libdwfl/elf-from-memory.c
+++ b/libdwfl/elf-from-memory.c
@@ -38,6 +38,10 @@
 #include <stdlib.h>
 #include <string.h>
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 /* Reconstruct an ELF file by reading the segments out of remote memory
    based on the ELF file header at EHDR_VMA and the ELF program headers it
    points to.  If not null, *LOADBASEP is filled in with the difference
@@ -191,22 +195,25 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
       xlatefrom.d_buf = buffer;
     }
 
-  typedef union
-  {
-    Elf32_Phdr p32[phnum];
-    Elf64_Phdr p64[phnum];
-  } phdrsn;
-
-  phdrsp = malloc (sizeof (phdrsn));
+  if (unlikely (phnum >
+                SIZE_MAX / MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr))))
+    {
+      free (buffer);
+      goto no_memory;
+    }
+  const size_t phdrsp_bytes =
+      phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+  phdrsp = malloc (phdrsp_bytes);
+  Elf32_Phdr (*p32)[phnum] = phdrsp;
+  Elf64_Phdr (*p64)[phnum] = phdrsp;
   if (unlikely (phdrsp == NULL))
     {
       free (buffer);
       goto no_memory;
     }
-  phdrsn *phdrs = (phdrsn *) phdrsp;
 
-  xlateto.d_buf = phdrs;
-  xlateto.d_size = sizeof (phdrsn);
+  xlateto.d_buf = phdrsp;
+  xlateto.d_size = phdrsp_bytes;
 
   /* Scan for PT_LOAD segments to find the total size of the file image.  */
   size_t contents_size = 0;
@@ -249,9 +256,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 			  ehdr.e32.e_ident[EI_DATA]) == NULL)
 	goto libelf_error;
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p32[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset,
-			      phdrs->p32[i].p_filesz, phdrs->p32[i].p_memsz))
+	if ((*p32)[i].p_type == PT_LOAD)
+	  if (handle_segment ((*p32)[i].p_vaddr, (*p32)[i].p_offset,
+			      (*p32)[i].p_filesz, (*p32)[i].p_memsz))
 	    goto bad_elf;
       break;
 
@@ -260,9 +267,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 			  ehdr.e64.e_ident[EI_DATA]) == NULL)
 	goto libelf_error;
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p64[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset,
-			      phdrs->p64[i].p_filesz, phdrs->p64[i].p_memsz))
+	if ((*p64)[i].p_type == PT_LOAD)
+	  if (handle_segment ((*p64)[i].p_vaddr, (*p64)[i].p_offset,
+			      (*p64)[i].p_filesz, (*p64)[i].p_memsz))
 	    goto bad_elf;
       break;
 
@@ -315,9 +322,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 
     case ELFCLASS32:
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p32[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset,
-			      phdrs->p32[i].p_filesz))
+	if ((*p32)[i].p_type == PT_LOAD)
+	  if (handle_segment ((*p32)[i].p_vaddr, (*p32)[i].p_offset,
+			      (*p32)[i].p_filesz))
 	    goto read_error;
 
       /* If the segments visible in memory didn't include the section
@@ -342,9 +349,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 
     case ELFCLASS64:
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p64[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset,
-			      phdrs->p64[i].p_filesz))
+	if ((*p64)[i].p_type == PT_LOAD)
+	  if (handle_segment ((*p64)[i].p_vaddr, (*p64)[i].p_offset,
+			      (*p64)[i].p_filesz))
 	    goto read_error;
 
       /* If the segments visible in memory didn't include the section
@@ -373,7 +380,7 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
     }
 
   free (phdrsp);
-  phdrs = phdrsp = NULL;
+  phdrsp = NULL;
 
   /* Now we have the image.  Open libelf on it.  */
 
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index 030c600..9f0b4a2 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -48,20 +48,16 @@ static bool
 auxv_format_probe (const void *auxv, size_t size,
 		   uint_fast8_t *elfclass, uint_fast8_t *elfdata)
 {
-  const union
-  {
-    char buf[size];
-    Elf32_auxv_t a32[size / sizeof (Elf32_auxv_t)];
-    Elf64_auxv_t a64[size / sizeof (Elf64_auxv_t)];
-  } *u = auxv;
+  const Elf32_auxv_t (*a32)[size / sizeof (Elf32_auxv_t)] = (void *) auxv;
+  const Elf64_auxv_t (*a64)[size / sizeof (Elf64_auxv_t)] = (void *) auxv;
 
   inline bool check64 (size_t i)
   {
     /* The AUXV pointer might not even be naturally aligned for 64-bit
        data, because note payloads in a core file are not aligned.  */
 
-    uint64_t type = read_8ubyte_unaligned_noncvt (&u->a64[i].a_type);
-    uint64_t val = read_8ubyte_unaligned_noncvt (&u->a64[i].a_un.a_val);
+    uint64_t type = read_8ubyte_unaligned_noncvt (&(*a64)[i].a_type);
+    uint64_t val = read_8ubyte_unaligned_noncvt (&(*a64)[i].a_un.a_val);
 
     if (type == BE64 (PROBE_TYPE)
 	&& val == BE64 (PROBE_VAL64))
@@ -85,8 +81,8 @@ auxv_format_probe (const void *auxv, size_t size,
     /* The AUXV pointer might not even be naturally aligned for 32-bit
        data, because note payloads in a core file are not aligned.  */
 
-    uint32_t type = read_4ubyte_unaligned_noncvt (&u->a32[i].a_type);
-    uint32_t val = read_4ubyte_unaligned_noncvt (&u->a32[i].a_un.a_val);
+    uint32_t type = read_4ubyte_unaligned_noncvt (&(*a32)[i].a_type);
+    uint32_t val = read_4ubyte_unaligned_noncvt (&(*a32)[i].a_un.a_val);
 
     if (type == BE32 (PROBE_TYPE)
 	&& val == BE32 (PROBE_VAL32))
@@ -280,29 +276,26 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
 	  return true;
       }
 
-    const union
-    {
-      Elf32_Addr a32[n];
-      Elf64_Addr a64[n];
-    } *in = vaddr - read_vaddr + buffer;
+    Elf32_Addr (*a32)[n] = vaddr - read_vaddr + buffer;
+    Elf64_Addr (*a64)[n] = (void *) a32;
 
     if (elfclass == ELFCLASS32)
       {
 	if (elfdata == ELFDATA2MSB)
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (&in->a32[i]));
+	    addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (&(*a32)[i]));
 	else
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (&in->a32[i]));
+	    addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (&(*a32)[i]));
       }
     else
       {
 	if (elfdata == ELFDATA2MSB)
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (&in->a64[i]));
+	    addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (&(*a64)[i]));
 	else
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (&in->a64[i]));
+	    addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (&(*a64)[i]));
       }
 
     return false;
@@ -861,13 +854,15 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	    }
 	  if (in_ok)
 	    {
-	      typedef union
-	      {
-		Elf32_Phdr p32;
-		Elf64_Phdr p64;
-		char data[phnum * phent];
-	      } data_buf;
-	      data_buf *buf = malloc (sizeof (data_buf));
+	      if (unlikely (phnum > SIZE_MAX / phent))
+		{
+		  __libdwfl_seterrno (DWFL_E_NOMEM);
+		  return false;
+		}
+	      size_t nbytes = phnum * phent;
+	      void *buf = malloc (nbytes);
+	      Elf32_Phdr (*p32)[phnum] = buf;
+	      Elf64_Phdr (*p64)[phnum] = buf;
 	      if (unlikely (buf == NULL))
 		{
 		  __libdwfl_seterrno (DWFL_E_NOMEM);
@@ -886,25 +881,20 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 			  (&out, &in, elfdata) != NULL))
 		{
 		  /* We are looking for PT_DYNAMIC.  */
-		  const union
-		  {
-		    Elf32_Phdr p32[phnum];
-		    Elf64_Phdr p64[phnum];
-		  } *u = (void *) buf;
 		  if (elfclass == ELFCLASS32)
 		    {
 		      for (size_t i = 0; i < phnum; ++i)
-			if (consider_phdr (u->p32[i].p_type,
-					   u->p32[i].p_vaddr,
-					   u->p32[i].p_filesz))
+			if (consider_phdr ((*p32)[i].p_type,
+					   (*p32)[i].p_vaddr,
+					   (*p32)[i].p_filesz))
 			  break;
 		    }
 		  else
 		    {
 		      for (size_t i = 0; i < phnum; ++i)
-			if (consider_phdr (u->p64[i].p_type,
-					   u->p64[i].p_vaddr,
-					   u->p64[i].p_filesz))
+			if (consider_phdr ((*p64)[i].p_type,
+					   (*p64)[i].p_vaddr,
+					   (*p64)[i].p_filesz))
 			  break;
 		    }
 		}
@@ -955,13 +945,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	  if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size,
 				  dyn_vaddr, dyn_filesz, memory_callback_arg))
 	    {
-	      typedef union
-	      {
-		Elf32_Dyn d32;
-		Elf64_Dyn d64;
-		char data[dyn_filesz];
-	      } data_buf;
-	      data_buf *buf = malloc (sizeof (data_buf));
+	      void *buf = malloc (dyn_filesz);
+	      Elf32_Dyn (*d32)[dyn_filesz / sizeof (Elf32_Dyn)] = buf;
+	      Elf64_Dyn (*d64)[dyn_filesz / sizeof (Elf64_Dyn)] = buf;
 	      if (unlikely (buf == NULL))
 		{
 		  __libdwfl_seterrno (DWFL_E_NOMEM);
@@ -980,18 +966,13 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 			  (&out, &in, elfdata) != NULL))
 		{
 		  /* We are looking for DT_DEBUG.  */
-		  const union
-		  {
-		    Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
-		    Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
-		  } *u = (void *) buf;
 		  if (elfclass == ELFCLASS32)
 		    {
 		      size_t n = dyn_filesz / sizeof (Elf32_Dyn);
 		      for (size_t i = 0; i < n; ++i)
-			if (u->d32[i].d_tag == DT_DEBUG)
+			if ((*d32)[i].d_tag == DT_DEBUG)
 			  {
-			    r_debug_vaddr = u->d32[i].d_un.d_val;
+			    r_debug_vaddr = (*d32)[i].d_un.d_val;
 			    break;
 			  }
 		    }
@@ -999,9 +980,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 		    {
 		      size_t n = dyn_filesz / sizeof (Elf64_Dyn);
 		      for (size_t i = 0; i < n; ++i)
-			if (u->d64[i].d_tag == DT_DEBUG)
+			if ((*d64)[i].d_tag == DT_DEBUG)
 			  {
-			    r_debug_vaddr = u->d64[i].d_un.d_val;
+			    r_debug_vaddr = (*d64)[i].d_un.d_val;
 			    break;
 			  }
 		    }
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 1916877..e4eaf5e 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,8 @@
+2015-10-05  Chih-Hung Hsieh <chh@google.com>
+
+	* elf_getarsym.c (elf_getarsym): Do not use
+	union of variable length arrays.
+
 2015-09-23  Mark Wielaard  <mjw@redhat.com>
 
 	* elf32_getehdr.c (getehdr_wrlock): Mark as internal_function.
diff --git a/libelf/elf_getarsym.c b/libelf/elf_getarsym.c
index 1ab94ca..f5ee3cb 100644
--- a/libelf/elf_getarsym.c
+++ b/libelf/elf_getarsym.c
@@ -201,11 +201,7 @@ elf_getarsym (Elf *elf, size_t *ptr)
       elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len);
       if (elf->state.ar.ar_sym != NULL)
 	{
-	  union
-	  {
-	    uint32_t u32[n];
-	    uint64_t u64[n];
-	  } *file_data;
+	  void *file_data; /* unit32_t[n] or uint64_t[n] */
 	  char *str_data;
 	  size_t sz = n * w;
 
@@ -272,7 +268,7 @@ elf_getarsym (Elf *elf, size_t *ptr)
 	      arsym[cnt].as_name = str_data;
 	      if (index64_p)
 		{
-		  uint64_t tmp = file_data->u64[cnt];
+		  uint64_t tmp = ((uint64_t *) file_data)[cnt];
 		  if (__BYTE_ORDER == __LITTLE_ENDIAN)
 		    tmp = bswap_64 (tmp);
 
@@ -294,9 +290,9 @@ elf_getarsym (Elf *elf, size_t *ptr)
 		    }
 		}
 	      else if (__BYTE_ORDER == __LITTLE_ENDIAN)
-		arsym[cnt].as_off = bswap_32 (file_data->u32[cnt]);
+		arsym[cnt].as_off = bswap_32 (((uint32_t *) file_data)[cnt]);
 	      else
-		arsym[cnt].as_off = file_data->u32[cnt];
+		arsym[cnt].as_off = ((uint32_t *) file_data)[cnt];
 
 	      arsym[cnt].as_hash = _dl_elf_hash (str_data);
 	      str_data = rawmemchr (str_data, '\0') + 1;
diff --git a/src/ChangeLog b/src/ChangeLog
index 49aa3f7..347d220 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,11 @@
+2015-10-05  Chih-Hung Hsieh <chh@google.com>
+
+	* unstrip.c (find_alloc_sections_prelink): Do not allocate
+	on stack union types with variable length arrays; use xmalloc
+	for such dynamic sized objects.
+	* readelf.c (handle_core_item): Likewise, but use alloca
+	for small variable size data object and add assert(count < 128).
+
 2015-09-22  Mark Wielaard  <mjw@redhat.com>
 
 	* strip.c (cleanup_debug): Remove old-style function definitions.
diff --git a/src/readelf.c b/src/readelf.c
index 33274f3..fe7bc39 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -8370,6 +8370,9 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 		  unsigned int colno, size_t *repeated_size)
 {
   uint_fast16_t count = item->count ?: 1;
+  /* Ebl_Core_Item count is always a small number.
+     Make sure the backend didn't put in some large bogus value.  */
+  assert (count < 128);
 
 #define TYPES								      \
   DO_TYPE (BYTE, Byte, "0x%.2" PRIx8, "%" PRId8);			      \
@@ -8379,11 +8382,16 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
   DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64);			      \
   DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64)
 
-#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name[count]
-  union { TYPES; } value;
+#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name
+  typedef union { TYPES; } value_t;
+  void *data = alloca (count * sizeof (value_t));
+#undef DO_TYPE
+
+#define DO_TYPE(NAME, Name, hex, dec) \
+    GElf_##Name *value_##Name __attribute__((unused)) = data
+  TYPES;
 #undef DO_TYPE
 
-  void *data = &value;
   size_t size = gelf_fsize (core, item->type, count, EV_CURRENT);
   size_t convsize = size;
   if (repeated_size != NULL)
@@ -8414,7 +8422,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
 	    colno = print_core_item (colno, ',', WRAP_COLUMN,		      \
-				     0, item->name, dec, value.Name[0]); \
+				     0, item->name, dec, value_##Name[0]); \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8430,7 +8438,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
 	    colno = print_core_item (colno, ',', WRAP_COLUMN,		      \
-				     0, item->name, hex, value.Name[0]);      \
+				     0, item->name, hex, value_##Name[0]);      \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8520,8 +8528,8 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 	{
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
-	    sec = value.Name[0];					      \
-	    usec = value.Name[1];					      \
+	    sec = value_##Name[0];					      \
+	    usec = value_##Name[1];					      \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8551,12 +8559,12 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
     case 'c':
       assert (count == 1);
       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
-			       "%c", value.Byte[0]);
+			       "%c", value_Byte[0]);
       break;
 
     case 's':
       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
-			       "%.*s", (int) count, value.Byte);
+			       "%.*s", (int) count, value_Byte);
       break;
 
     case '\n':
diff --git a/src/unstrip.c b/src/unstrip.c
index 82bcdd8..c4484ab 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -54,6 +54,10 @@
 # define _(str) gettext (str)
 #endif
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 /* Name and version of program.  */
 static void print_version (FILE *stream, struct argp_state *state);
 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
@@ -1013,13 +1017,17 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	error (EXIT_FAILURE, 0, _("invalid contents in '%s' section"),
 	       ".gnu.prelink_undo");
 
-      union
-      {
-	Elf32_Shdr s32[shnum - 1];
-	Elf64_Shdr s64[shnum - 1];
-      } shdr;
-      dst.d_buf = &shdr;
-      dst.d_size = sizeof shdr;
+      if (unlikely ((shnum - 1) >
+                    SIZE_MAX / MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr))))
+	error (EXIT_FAILURE, 0, _("overflow with shnum = %zu in '%s' section"),
+	       (size_t) shnum, ".gnu.prelink_undo");
+      const size_t shdr_bytes =
+          (shnum - 1) * MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr));
+      void *shdr = xmalloc (shdr_bytes);
+      Elf32_Shdr (*s32)[shnum - 1] = shdr;
+      Elf64_Shdr (*s64) [shnum - 1]= shdr;
+      dst.d_buf = shdr;
+      dst.d_size = shdr_bytes;
       ELF_CHECK (gelf_xlatetom (main, &dst, &src,
 				main_ehdr->e_ident[EI_DATA]) != NULL,
 		 _("cannot read '.gnu.prelink_undo' section: %s"));
@@ -1030,7 +1038,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	  struct section *sec = &undo_sections[undo_nalloc];
 	  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
 	    {
-#define COPY(field) sec->shdr.field = shdr.s32[i].field
+#define COPY(field) sec->shdr.field = (*s32)[i].field
 	      COPY (sh_name);
 	      COPY (sh_type);
 	      COPY (sh_flags);
@@ -1044,7 +1052,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 #undef	COPY
 	    }
 	  else
-	    sec->shdr = shdr.s64[i];
+	    sec->shdr = (*s64)[i];
 	  if (sec->shdr.sh_flags & SHF_ALLOC)
 	    {
 	      sec->shdr.sh_addr += bias;
@@ -1057,6 +1065,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	}
       qsort (undo_sections, undo_nalloc,
 	     sizeof undo_sections[0], compare_sections_nonrel);
+      free (shdr);
     }
 
   bool fail = false;
-- 
2.6.0.rc2.230.g3dd15c0


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-05 19:04 Chih-Hung Hsieh
  0 siblings, 0 replies; 34+ messages in thread
From: Chih-Hung Hsieh @ 2015-10-05 19:04 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 2432 bytes --]

I will prepare a new patch with the suggested changes:

(a) more efficient overflow check like
        if (num > SIZE_MAX / elem_size)

(b) replacing union of VLA with pointers to arrays like
         void *data = malloc (...);
         T32 (*a32)[n] = data;
         T64 (*a64)[n] = data;

Please feel free to suggest better solutions.
Thanks.


On Mon, Oct 5, 2015 at 11:45 AM, Mark Wielaard <mjw@redhat.com> wrote:

> On Fri, Oct 02, 2015 at 12:10:47AM +0300, Alexander Cherepanov wrote:
> > On 2015-09-16 18:25, Mark Wielaard wrote:
> > >On Fri, 2015-09-11 at 12:22 -0700, Roland McGrath wrote:
> > >>It looks fine to me from a quick skim, but Mark should review and test
> it too.
> > >
> > >I am not super enthusiastic about this change, it seems to just take
> > >away type/size information that the compiler/bounds checking tools can
> > >use.
> >
> > I'm not sure I fully understand the problem. As I understand it unions of
> > VLAs are not Ok while VLAs are Ok and even desirable due to bounds
> checking,
> > right?
>
> There are two issues. First with GCC VLA types are OK and desired compared
> to types not using bounds. But if such a VLAs might be unbounded then they
> should not be stack allocated (this is enforced by building with
> -Wstack-usage except for a couple of files that haven't been converted).
> Secondly there are people who want to use clang to build elfutils. clang
> doesn't support various GNU extensions used in the code like VLAs. So
> for those people any VLA type seems problematic.
>
> > Why not just use VLAs of unions? Cold memory?
>
> I am not sure clang supports such VLA types. If it does, then I would say
> VLAs of unions are preferred above a type that doesn't include bounds.
>
> > Given that the current approach (before the patch) already required to
> write
> > superfluous "->" perhaps an approach requiring a superfluous "*" will
> fit?
> > Like this:
> >
> >   void *data = malloc (...);
> >   T32 (*a32)[n] = data;
> >   T64 (*a64)[n] = data;
> >
> > Then the use looks like "(*a32)[i].member". Clang seems to be happy and
> its
> > UBSAN works fine.
>
> If that works that would probably be preferred since then ubsan can see
> the array bounds and help catch issues. You can build and run elfutils
> and the tests with configure --enable-sanitize-undefined to use ubsan
> checking.
>
> Cheers,
>
> Mark
>

[-- Attachment #2: attachment.html --]
[-- Type: text/html, Size: 3130 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-05 18:53 Mark Wielaard
  0 siblings, 0 replies; 34+ messages in thread
From: Mark Wielaard @ 2015-10-05 18:53 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 509 bytes --]

On Fri, Oct 02, 2015 at 04:17:43PM +0200, Florian Weimer wrote:
> On 09/08/2015 11:08 PM, Chih-Hung Hsieh wrote:
> > +    void *phdrs = malloc (phnum * sizeof (phdr_u));
> 
> If you change this code anyway, it's sensible to check for integer
> overflow in the size computation.

This is now done in a couple of places in the update patch.
But it would indeed be nice to do this consistently everywhere we
replace a VLA type sizeof allocation with a (n * element size) allocation.

Thanks,

Mark

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-05 18:45 Mark Wielaard
  0 siblings, 0 replies; 34+ messages in thread
From: Mark Wielaard @ 2015-10-05 18:45 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 1900 bytes --]

On Fri, Oct 02, 2015 at 12:10:47AM +0300, Alexander Cherepanov wrote:
> On 2015-09-16 18:25, Mark Wielaard wrote:
> >On Fri, 2015-09-11 at 12:22 -0700, Roland McGrath wrote:
> >>It looks fine to me from a quick skim, but Mark should review and test it too.
> >
> >I am not super enthusiastic about this change, it seems to just take
> >away type/size information that the compiler/bounds checking tools can
> >use.
> 
> I'm not sure I fully understand the problem. As I understand it unions of
> VLAs are not Ok while VLAs are Ok and even desirable due to bounds checking,
> right?

There are two issues. First with GCC VLA types are OK and desired compared
to types not using bounds. But if such a VLAs might be unbounded then they
should not be stack allocated (this is enforced by building with
-Wstack-usage except for a couple of files that haven't been converted).
Secondly there are people who want to use clang to build elfutils. clang
doesn't support various GNU extensions used in the code like VLAs. So
for those people any VLA type seems problematic.
 
> Why not just use VLAs of unions? Cold memory?

I am not sure clang supports such VLA types. If it does, then I would say
VLAs of unions are preferred above a type that doesn't include bounds.

> Given that the current approach (before the patch) already required to write
> superfluous "->" perhaps an approach requiring a superfluous "*" will fit?
> Like this:
> 
>   void *data = malloc (...);
>   T32 (*a32)[n] = data;
>   T64 (*a64)[n] = data;
> 
> Then the use looks like "(*a32)[i].member". Clang seems to be happy and its
> UBSAN works fine.

If that works that would probably be preferred since then ubsan can see
the array bounds and help catch issues. You can build and run elfutils
and the tests with configure --enable-sanitize-undefined to use ubsan
checking.

Cheers,

Mark

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-05 18:32 Mark Wielaard
  0 siblings, 0 replies; 34+ messages in thread
From: Mark Wielaard @ 2015-10-05 18:32 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 880 bytes --]

On 01.10.2015 23:45, Alexander Cherepanov wrote:
>On 2015-09-17 12:40, Mark Wielaard wrote:
>>>* Now const size_t is used instead of const int for malloc argument
>>>type.
>>
>>Thanks. I am still interested in the overflow issue. I believe since we
>>are using unsigned arithmetic and we know the size is always > 0, it
>>should be as simple as doing:
>>
>>   const size_t elem_size = ... sizeof (...);
>>   const size_t bytes = num * elem_size;
>>   if (unlikely (bytes / elem_size != num))
>>     return E_NOMEM;
>>   ... malloc (bytes);
>
>Sorry, I'm late to the party but why not check it before multiplication
>in a usual way:
>
>if (num > SIZE_MAX / elem_size)
>   return E_NOMEM;
>
>IIUC elem_size is a compile time constant so the whole division is
>computed by compiler.

I had not thought of that. Yes, that is a nicer check.

Thanks,

Mark

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-02 16:32 Alexander Cherepanov
  0 siblings, 0 replies; 34+ messages in thread
From: Alexander Cherepanov @ 2015-10-02 16:32 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 910 bytes --]

[Fixed typo and restored lost Cc, sorry.]

On 01.10.2015 23:45, Alexander Cherepanov wrote:
> On 2015-09-17 12:40, Mark Wielaard wrote:
>>> * Now const size_t is used instead of const int for malloc argument
>>> type.
>>
>> Thanks. I am still interested in the overflow issue. I believe since we
>> are using unsigned arithmetic and we know the size is always > 0, it
>> should be as simple as doing:
>>
>>    const size_t elem_size = ... sizeof (...);
>>    const size_t bytes = num * elem_size;
>>    if (unlikely (bytes / elem_size != num))
>>      return E_NOMEM;
>>    ... malloc (bytes);
>
> Sorry, I'm late to the party but why hot check it before multiplication

s/hot/not/

> in a usual way:
>
> if (num > SIZE_MAX / elem_size)
>    return E_NOMEM;
>
> IIUC elem_size is a compile time constant so the whole division is
> computed by compiler.

-- 
Alexander Cherepanov

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-02 14:17 Florian Weimer
  0 siblings, 0 replies; 34+ messages in thread
From: Florian Weimer @ 2015-10-02 14:17 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 229 bytes --]

On 09/08/2015 11:08 PM, Chih-Hung Hsieh wrote:
> +    void *phdrs = malloc (phnum * sizeof (phdr_u));

If you change this code anyway, it's sensible to check for integer
overflow in the size computation.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-01 23:01 Chih-Hung Hsieh
  0 siblings, 0 replies; 34+ messages in thread
From: Chih-Hung Hsieh @ 2015-10-01 23:01 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 1357 bytes --]

On Thu, Oct 1, 2015 at 2:10 PM, Alexander Cherepanov <ch3root@openwall.com>
wrote:

> On 2015-09-16 18:25, Mark Wielaard wrote:
>
>> On Fri, 2015-09-11 at 12:22 -0700, Roland McGrath wrote:
>>
>>> It looks fine to me from a quick skim, but Mark should review and test
>>> it too.
>>>
>>
>> I am not super enthusiastic about this change, it seems to just take
>> away type/size information that the compiler/bounds checking tools can
>> use.
>>
>
> I'm not sure I fully understand the problem. As I understand it unions of
> VLAs are not Ok while VLAs are Ok and even desirable due to bounds
> checking, right?
>
> Why not just use VLAs of unions? Cold memory?
>

I think this does not work because some part of elfutils walks through an
array of T32 (or an array of T64), not an array of union of T32 and T64.


>
> Given that the current approach (before the patch) already required to
> write superfluous "->" perhaps an approach requiring a superfluous "*" will
> fit? Like this:
>
>   void *data = malloc (...);
>   T32 (*a32)[n] = data;
>   T64 (*a64)[n] = data;
>
> Then the use looks like "(*a32)[i].member". Clang seems to be happy and
> its UBSAN works fine.


This looks fine to me. I don't mind either way.
Anyone else prefers a32[i]  or (*a32)[i]?

-- chh



>
>
> --
> Alexander Cherepanov
>

[-- Attachment #2: attachment.html --]
[-- Type: text/html, Size: 2345 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-01 21:10 Alexander Cherepanov
  0 siblings, 0 replies; 34+ messages in thread
From: Alexander Cherepanov @ 2015-10-01 21:10 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 940 bytes --]

On 2015-09-16 18:25, Mark Wielaard wrote:
> On Fri, 2015-09-11 at 12:22 -0700, Roland McGrath wrote:
>> It looks fine to me from a quick skim, but Mark should review and test it too.
>
> I am not super enthusiastic about this change, it seems to just take
> away type/size information that the compiler/bounds checking tools can
> use.

I'm not sure I fully understand the problem. As I understand it unions 
of VLAs are not Ok while VLAs are Ok and even desirable due to bounds 
checking, right?

Why not just use VLAs of unions? Cold memory?

Given that the current approach (before the patch) already required to 
write superfluous "->" perhaps an approach requiring a superfluous "*" 
will fit? Like this:

   void *data = malloc (...);
   T32 (*a32)[n] = data;
   T64 (*a64)[n] = data;

Then the use looks like "(*a32)[i].member". Clang seems to be happy and 
its UBSAN works fine.

-- 
Alexander Cherepanov

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-01 20:45 Alexander Cherepanov
  0 siblings, 0 replies; 34+ messages in thread
From: Alexander Cherepanov @ 2015-10-01 20:45 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 768 bytes --]

On 2015-09-17 12:40, Mark Wielaard wrote:
>> * Now const size_t is used instead of const int for malloc argument type.
>
> Thanks. I am still interested in the overflow issue. I believe since we
> are using unsigned arithmetic and we know the size is always > 0, it
> should be as simple as doing:
>
>    const size_t elem_size = ... sizeof (...);
>    const size_t bytes = num * elem_size;
>    if (unlikely (bytes / elem_size != num))
>      return E_NOMEM;
>    ... malloc (bytes);

Sorry, I'm late to the party but why hot check it before multiplication 
in a usual way:

if (num > SIZE_MAX / elem_size)
   return E_NOMEM;

IIUC elem_size is a compile time constant so the whole division is 
computed by compiler.

-- 
Alexander Cherepanov

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-01 19:04 Chih-Hung Hsieh
  0 siblings, 0 replies; 34+ messages in thread
From: Chih-Hung Hsieh @ 2015-10-01 19:04 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 709 bytes --]

Thanks. I updated ChangLog files in the new attached 0005*patch file.

I think we mean the new assert(count<128) statement in readelf.c.
It is now explained in ChangeLog that assert was added because alloca was
used for the new dynamic allocation. For other malloc and xmalloc, overflow
tests were added.




On Thu, Oct 1, 2015 at 10:22 AM, Roland McGrath <roland@hack.frob.com>
wrote:

> In ChangeLog entries, "Likewise" should be followed by a period.
>
> You have some readelf changes that are not directly part of avoiding
> unions.  They are also not described in the src/ChangeLog entry.
> Please post those separately and describe their justifications.
>
>
> Thanks,
> Roland
>

[-- Attachment #2: attachment.html --]
[-- Type: text/html, Size: 1089 bytes --]

[-- Attachment #3: 0005-Do-without-union-of-variable-length-arrays.patch --]
[-- Type: application/octet-stream, Size: 27292 bytes --]

From 30a9133b266a2597f1c143e6acfb02153c06201b Mon Sep 17 00:00:00 2001
From: Chih-Hung Hsieh <chh@google.com>
Date: Wed, 30 Sep 2015 16:50:42 -0700
Subject: [PATCH] Do without union of variable length arrays.

Prepare to compile with clang.

A union like
  { T32 a32[n]; T64 a64[n]; } u;
is expanded to
  void *data = malloc (...);
  T32 *a32 = data;
  T64 *a64 = data;
or
  size_t nbytes = n * MAX(sizeof(T32), sizeof(T64));
  void *data = malloc(nbytes);
  T32 *a32 = data;
  T64 *a64 = data;

Signed-off-by: Chih-Hung Hsieh <chh@google.com>
---
 libdwfl/ChangeLog                    | 10 +++++
 libdwfl/dwfl_module_getdwarf.c       | 53 ++++++++++++----------
 libdwfl/dwfl_segment_report_module.c | 69 ++++++++++++++--------------
 libdwfl/elf-from-memory.c            | 47 +++++++++----------
 libdwfl/link_map.c                   | 87 ++++++++++++++----------------------
 libelf/ChangeLog                     |  5 +++
 libelf/elf_getarsym.c                | 12 ++---
 src/ChangeLog                        |  8 ++++
 src/readelf.c                        | 26 +++++++----
 src/unstrip.c                        | 27 +++++++----
 10 files changed, 183 insertions(+), 161 deletions(-)

diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index f34087c..5ca7363 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,13 @@
+2015-10-01  Chih-Hung Hsieh <chh@google.com>
+
+	* dwfl_module_getdwarf.c (find_prelink_address_sync): Do not use
+	union of variable length arrays.
+	* dwfl_segment_report_module.c (dwfl_segment_report_module): Likewise.
+	* elf-from-memory.c (elf_from_remote_memory): Likewise.
+	* link_map.c (auxv_format_probe): Likewise.
+	* link_map.c (report_r_debug): Likewise.
+	* link_map.c (dwfl_link_map_report): Likewise.
+
 2015-09-22  Mark Wielaard  <mjw@redhat.com>
 
 	* core-file.c: Remove old-style function definitions.
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index dba9d66..74cb19f 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -34,6 +34,10 @@
 #include "../libdw/libdwP.h"	/* DWARF_E_* values are here.  */
 #include "../libelf/libelfP.h"
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 static inline Dwfl_Error
 open_elf_file (Elf **elf, int *fd, char **name)
 {
@@ -368,16 +372,18 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
 
   GElf_Addr undo_interp = 0;
   {
-    typedef union
-    {
-      Elf32_Phdr p32[phnum];
-      Elf64_Phdr p64[phnum];
-    } phdr;
-    phdr *phdrs = malloc (sizeof (phdr));
+    const size_t phdrs_bytes =
+        phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+    if (unlikely (phdrs_bytes / phnum != 
+                  MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr))))
+      return DWFL_E_NOMEM;
+    void *phdrs = malloc (phdrs_bytes);
+    Elf32_Phdr *p32 = phdrs;
+    Elf64_Phdr *p64 = phdrs;
     if (unlikely (phdrs == NULL))
       return DWFL_E_NOMEM;
     dst.d_buf = phdrs;
-    dst.d_size = sizeof (phdr);
+    dst.d_size = phdrs_bytes;
     if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
 				 ehdr.e32.e_ident[EI_DATA]) == NULL))
       {
@@ -387,18 +393,18 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
     if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
       {
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  if (phdrs->p32[i].p_type == PT_INTERP)
+	  if (p32[i].p_type == PT_INTERP)
 	    {
-	      undo_interp = phdrs->p32[i].p_vaddr;
+	      undo_interp = p32[i].p_vaddr;
 	      break;
 	    }
       }
     else
       {
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  if (phdrs->p64[i].p_type == PT_INTERP)
+	  if (p64[i].p_type == PT_INTERP)
 	    {
-	      undo_interp = phdrs->p64[i].p_vaddr;
+	      undo_interp = p64[i].p_vaddr;
 	      break;
 	    }
       }
@@ -412,16 +418,15 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
   src.d_type = ELF_T_SHDR;
   src.d_size = gelf_fsize (mod->main.elf, ELF_T_SHDR, shnum - 1, EV_CURRENT);
 
-  typedef union
-  {
-    Elf32_Shdr s32[shnum - 1];
-    Elf64_Shdr s64[shnum - 1];
-  } shdr;
-  shdr *shdrs = malloc (sizeof (shdr));
+  const size_t shdrs_bytes =
+      (shnum - 1) * MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr));
+  void *shdrs = malloc (shdrs_bytes);
+  Elf32_Shdr *s32 = shdrs;
+  Elf64_Shdr *s64 = shdrs;
   if (unlikely (shdrs == NULL))
     return DWFL_E_NOMEM;
   dst.d_buf = shdrs;
-  dst.d_size = sizeof (shdr);
+  dst.d_size = shdrs_bytes;
   if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
 			       ehdr.e32.e_ident[EI_DATA]) == NULL))
     {
@@ -484,14 +489,14 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
       highest = 0;
       if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
 	for (size_t i = 0; i < shnum - 1; ++i)
-	  consider_shdr (undo_interp, shdrs->s32[i].sh_type,
-			 shdrs->s32[i].sh_flags, shdrs->s32[i].sh_addr,
-			 shdrs->s32[i].sh_size);
+	  consider_shdr (undo_interp, s32[i].sh_type,
+			 s32[i].sh_flags, s32[i].sh_addr,
+			 s32[i].sh_size);
       else
 	for (size_t i = 0; i < shnum - 1; ++i)
-	  consider_shdr (undo_interp, shdrs->s64[i].sh_type,
-			 shdrs->s64[i].sh_flags, shdrs->s64[i].sh_addr,
-			 shdrs->s64[i].sh_size);
+	  consider_shdr (undo_interp, s64[i].sh_type,
+			 s64[i].sh_flags, s64[i].sh_addr,
+			 s64[i].sh_size);
 
       if (highest > file->vaddr)
 	file->address_sync = highest;
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index a0f07ad..613f779 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -53,6 +53,10 @@
 # define MY_ELFDATA	ELFDATA2MSB
 #endif
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 
 /* Return user segment index closest to ADDR but not above it.
    If NEXT, return the closest to ADDR but not below it.  */
@@ -404,19 +408,19 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
   xlatefrom.d_buf = ph_buffer;
 
-  typedef union
-  {
-    Elf32_Phdr p32[phnum];
-    Elf64_Phdr p64[phnum];
-  } phdrsn;
-
-  phdrsp = malloc (sizeof (phdrsn));
+  const size_t phdrsp_bytes =
+      phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+  if (unlikely (phdrsp_bytes / phnum !=
+                MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr))))
+    return finish ();
+  phdrsp = malloc (phdrsp_bytes);
+  Elf32_Phdr *p32 = phdrsp;
+  Elf64_Phdr *p64 = phdrsp;
   if (unlikely (phdrsp == NULL))
     return finish ();
-  phdrsn *phdrs = (phdrsn *) phdrsp;
 
-  xlateto.d_buf = phdrs;
-  xlateto.d_size = sizeof (phdrsn);
+  xlateto.d_buf = phdrsp;
+  xlateto.d_size = phdrsp_bytes;
 
   /* Track the bounds of the file visible in memory.  */
   GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end.  */
@@ -579,10 +583,10 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	found_bias = false;	/* Trigger error check.  */
       else
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  consider_phdr (phdrs->p32[i].p_type,
-			 phdrs->p32[i].p_vaddr, phdrs->p32[i].p_memsz,
-			 phdrs->p32[i].p_offset, phdrs->p32[i].p_filesz,
-			 phdrs->p32[i].p_align);
+	  consider_phdr (p32[i].p_type,
+			 p32[i].p_vaddr, p32[i].p_memsz,
+			 p32[i].p_offset, p32[i].p_filesz,
+			 p32[i].p_align);
     }
   else
     {
@@ -590,10 +594,10 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	found_bias = false;	/* Trigger error check.  */
       else
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  consider_phdr (phdrs->p64[i].p_type,
-			 phdrs->p64[i].p_vaddr, phdrs->p64[i].p_memsz,
-			 phdrs->p64[i].p_offset, phdrs->p64[i].p_filesz,
-			 phdrs->p64[i].p_align);
+	  consider_phdr (p64[i].p_type,
+			 p64[i].p_vaddr, p64[i].p_memsz,
+			 p64[i].p_offset, p64[i].p_filesz,
+			 p64[i].p_align);
     }
 
   finish_portion (&ph_buffer, &ph_buffer_size);
@@ -749,44 +753,39 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
   const size_t dyn_entsize = (ei_class == ELFCLASS32
 			      ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
-  void *dyns = NULL;
   void *dyn_data = NULL;
   size_t dyn_data_size = 0;
   if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
       && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz))
     {
-      typedef union
-      {
-	Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
-	Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
-      } dynn;
-      dyns = malloc (sizeof (dynn));
+      void *dyns = malloc (dyn_filesz);
+      Elf32_Dyn *d32 = dyns;
+      Elf64_Dyn *d64 = dyns;
       if (unlikely (dyns == NULL))
 	return finish ();
-      dynn *dyn = (dynn *) dyns;
 
       xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
       xlatefrom.d_buf = (void *) dyn_data;
       xlatefrom.d_size = dyn_filesz;
-      xlateto.d_buf = dyn;
-      xlateto.d_size = sizeof (dynn);
+      xlateto.d_buf = dyns;
+      xlateto.d_size = dyn_filesz;
 
       if (ei_class == ELFCLASS32)
 	{
 	  if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
 	    for (size_t i = 0; i < dyn_filesz / sizeof (Elf32_Dyn); ++i)
-	      if (consider_dyn (dyn->d32[i].d_tag, dyn->d32[i].d_un.d_val))
+	      if (consider_dyn (d32[i].d_tag, d32[i].d_un.d_val))
 		break;
 	}
       else
 	{
 	  if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
 	    for (size_t i = 0; i < dyn_filesz / sizeof (Elf64_Dyn); ++i)
-	      if (consider_dyn (dyn->d64[i].d_tag, dyn->d64[i].d_un.d_val))
+	      if (consider_dyn (d64[i].d_tag, d64[i].d_un.d_val))
 		break;
 	}
+      free (dyns);
     }
-  free (dyns);
   finish_portion (&dyn_data, &dyn_data_size);
 
   /* We'll use the name passed in or a stupid default if not DT_SONAME.  */
@@ -901,12 +900,12 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
 	  if (ei_class == ELFCLASS32)
 	    for (uint_fast16_t i = 0; i < phnum; ++i)
-	      read_phdr (phdrs->p32[i].p_type, phdrs->p32[i].p_vaddr,
-			 phdrs->p32[i].p_offset, phdrs->p32[i].p_filesz);
+	      read_phdr (p32[i].p_type, p32[i].p_vaddr,
+			 p32[i].p_offset, p32[i].p_filesz);
 	  else
 	    for (uint_fast16_t i = 0; i < phnum; ++i)
-	      read_phdr (phdrs->p64[i].p_type, phdrs->p64[i].p_vaddr,
-			 phdrs->p64[i].p_offset, phdrs->p64[i].p_filesz);
+	      read_phdr (p64[i].p_type, p64[i].p_vaddr,
+			 p64[i].p_offset, p64[i].p_filesz);
 	}
       else
 	{
diff --git a/libdwfl/elf-from-memory.c b/libdwfl/elf-from-memory.c
index ed8f6e9..52d8395 100644
--- a/libdwfl/elf-from-memory.c
+++ b/libdwfl/elf-from-memory.c
@@ -38,6 +38,10 @@
 #include <stdlib.h>
 #include <string.h>
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 /* Reconstruct an ELF file by reading the segments out of remote memory
    based on the ELF file header at EHDR_VMA and the ELF program headers it
    points to.  If not null, *LOADBASEP is filled in with the difference
@@ -191,22 +195,19 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
       xlatefrom.d_buf = buffer;
     }
 
-  typedef union
-  {
-    Elf32_Phdr p32[phnum];
-    Elf64_Phdr p64[phnum];
-  } phdrsn;
-
-  phdrsp = malloc (sizeof (phdrsn));
+  const size_t phdrsp_bytes =
+      phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+  phdrsp = malloc (phdrsp_bytes);
+  Elf32_Phdr *p32 = phdrsp;
+  Elf64_Phdr *p64 = phdrsp;
   if (unlikely (phdrsp == NULL))
     {
       free (buffer);
       goto no_memory;
     }
-  phdrsn *phdrs = (phdrsn *) phdrsp;
 
-  xlateto.d_buf = phdrs;
-  xlateto.d_size = sizeof (phdrsn);
+  xlateto.d_buf = phdrsp;
+  xlateto.d_size = phdrsp_bytes;
 
   /* Scan for PT_LOAD segments to find the total size of the file image.  */
   size_t contents_size = 0;
@@ -249,9 +250,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 			  ehdr.e32.e_ident[EI_DATA]) == NULL)
 	goto libelf_error;
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p32[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset,
-			      phdrs->p32[i].p_filesz, phdrs->p32[i].p_memsz))
+	if (p32[i].p_type == PT_LOAD)
+	  if (handle_segment (p32[i].p_vaddr, p32[i].p_offset,
+			      p32[i].p_filesz, p32[i].p_memsz))
 	    goto bad_elf;
       break;
 
@@ -260,9 +261,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 			  ehdr.e64.e_ident[EI_DATA]) == NULL)
 	goto libelf_error;
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p64[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset,
-			      phdrs->p64[i].p_filesz, phdrs->p64[i].p_memsz))
+	if (p64[i].p_type == PT_LOAD)
+	  if (handle_segment (p64[i].p_vaddr, p64[i].p_offset,
+			      p64[i].p_filesz, p64[i].p_memsz))
 	    goto bad_elf;
       break;
 
@@ -315,9 +316,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 
     case ELFCLASS32:
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p32[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset,
-			      phdrs->p32[i].p_filesz))
+	if (p32[i].p_type == PT_LOAD)
+	  if (handle_segment (p32[i].p_vaddr, p32[i].p_offset,
+			      p32[i].p_filesz))
 	    goto read_error;
 
       /* If the segments visible in memory didn't include the section
@@ -342,9 +343,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 
     case ELFCLASS64:
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p64[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset,
-			      phdrs->p64[i].p_filesz))
+	if (p64[i].p_type == PT_LOAD)
+	  if (handle_segment (p64[i].p_vaddr, p64[i].p_offset,
+			      p64[i].p_filesz))
 	    goto read_error;
 
       /* If the segments visible in memory didn't include the section
@@ -373,7 +374,7 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
     }
 
   free (phdrsp);
-  phdrs = phdrsp = NULL;
+  phdrsp = NULL;
 
   /* Now we have the image.  Open libelf on it.  */
 
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index 030c600..c55c7f0 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -48,20 +48,16 @@ static bool
 auxv_format_probe (const void *auxv, size_t size,
 		   uint_fast8_t *elfclass, uint_fast8_t *elfdata)
 {
-  const union
-  {
-    char buf[size];
-    Elf32_auxv_t a32[size / sizeof (Elf32_auxv_t)];
-    Elf64_auxv_t a64[size / sizeof (Elf64_auxv_t)];
-  } *u = auxv;
+  const Elf32_auxv_t *a32 = auxv;
+  const Elf64_auxv_t *a64 = auxv;
 
   inline bool check64 (size_t i)
   {
     /* The AUXV pointer might not even be naturally aligned for 64-bit
        data, because note payloads in a core file are not aligned.  */
 
-    uint64_t type = read_8ubyte_unaligned_noncvt (&u->a64[i].a_type);
-    uint64_t val = read_8ubyte_unaligned_noncvt (&u->a64[i].a_un.a_val);
+    uint64_t type = read_8ubyte_unaligned_noncvt (&a64[i].a_type);
+    uint64_t val = read_8ubyte_unaligned_noncvt (&a64[i].a_un.a_val);
 
     if (type == BE64 (PROBE_TYPE)
 	&& val == BE64 (PROBE_VAL64))
@@ -85,8 +81,8 @@ auxv_format_probe (const void *auxv, size_t size,
     /* The AUXV pointer might not even be naturally aligned for 32-bit
        data, because note payloads in a core file are not aligned.  */
 
-    uint32_t type = read_4ubyte_unaligned_noncvt (&u->a32[i].a_type);
-    uint32_t val = read_4ubyte_unaligned_noncvt (&u->a32[i].a_un.a_val);
+    uint32_t type = read_4ubyte_unaligned_noncvt (&a32[i].a_type);
+    uint32_t val = read_4ubyte_unaligned_noncvt (&a32[i].a_un.a_val);
 
     if (type == BE32 (PROBE_TYPE)
 	&& val == BE32 (PROBE_VAL32))
@@ -280,29 +276,26 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
 	  return true;
       }
 
-    const union
-    {
-      Elf32_Addr a32[n];
-      Elf64_Addr a64[n];
-    } *in = vaddr - read_vaddr + buffer;
+    Elf32_Addr *a32 = vaddr - read_vaddr + buffer;
+    Elf64_Addr *a64 = (void *) a32;
 
     if (elfclass == ELFCLASS32)
       {
 	if (elfdata == ELFDATA2MSB)
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (&in->a32[i]));
+	    addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (&a32[i]));
 	else
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (&in->a32[i]));
+	    addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (&a32[i]));
       }
     else
       {
 	if (elfdata == ELFDATA2MSB)
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (&in->a64[i]));
+	    addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (&a64[i]));
 	else
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (&in->a64[i]));
+	    addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (&a64[i]));
       }
 
     return false;
@@ -861,13 +854,15 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	    }
 	  if (in_ok)
 	    {
-	      typedef union
-	      {
-		Elf32_Phdr p32;
-		Elf64_Phdr p64;
-		char data[phnum * phent];
-	      } data_buf;
-	      data_buf *buf = malloc (sizeof (data_buf));
+	      size_t nbytes = phnum * phent;
+	      if (unlikely (phnum != nbytes / phent))
+		{
+		  __libdwfl_seterrno (DWFL_E_NOMEM);
+		  return false;
+		}
+	      void *buf = malloc (nbytes);
+	      Elf32_Phdr *p32 = buf;
+	      Elf64_Phdr *p64 = buf;
 	      if (unlikely (buf == NULL))
 		{
 		  __libdwfl_seterrno (DWFL_E_NOMEM);
@@ -886,25 +881,20 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 			  (&out, &in, elfdata) != NULL))
 		{
 		  /* We are looking for PT_DYNAMIC.  */
-		  const union
-		  {
-		    Elf32_Phdr p32[phnum];
-		    Elf64_Phdr p64[phnum];
-		  } *u = (void *) buf;
 		  if (elfclass == ELFCLASS32)
 		    {
 		      for (size_t i = 0; i < phnum; ++i)
-			if (consider_phdr (u->p32[i].p_type,
-					   u->p32[i].p_vaddr,
-					   u->p32[i].p_filesz))
+			if (consider_phdr (p32[i].p_type,
+					   p32[i].p_vaddr,
+					   p32[i].p_filesz))
 			  break;
 		    }
 		  else
 		    {
 		      for (size_t i = 0; i < phnum; ++i)
-			if (consider_phdr (u->p64[i].p_type,
-					   u->p64[i].p_vaddr,
-					   u->p64[i].p_filesz))
+			if (consider_phdr (p64[i].p_type,
+					   p64[i].p_vaddr,
+					   p64[i].p_filesz))
 			  break;
 		    }
 		}
@@ -955,13 +945,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	  if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size,
 				  dyn_vaddr, dyn_filesz, memory_callback_arg))
 	    {
-	      typedef union
-	      {
-		Elf32_Dyn d32;
-		Elf64_Dyn d64;
-		char data[dyn_filesz];
-	      } data_buf;
-	      data_buf *buf = malloc (sizeof (data_buf));
+	      void *buf = malloc (dyn_filesz);
+	      Elf32_Dyn *d32 = buf;
+	      Elf64_Dyn *d64 = buf;
 	      if (unlikely (buf == NULL))
 		{
 		  __libdwfl_seterrno (DWFL_E_NOMEM);
@@ -980,18 +966,13 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 			  (&out, &in, elfdata) != NULL))
 		{
 		  /* We are looking for DT_DEBUG.  */
-		  const union
-		  {
-		    Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
-		    Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
-		  } *u = (void *) buf;
 		  if (elfclass == ELFCLASS32)
 		    {
 		      size_t n = dyn_filesz / sizeof (Elf32_Dyn);
 		      for (size_t i = 0; i < n; ++i)
-			if (u->d32[i].d_tag == DT_DEBUG)
+			if (d32[i].d_tag == DT_DEBUG)
 			  {
-			    r_debug_vaddr = u->d32[i].d_un.d_val;
+			    r_debug_vaddr = d32[i].d_un.d_val;
 			    break;
 			  }
 		    }
@@ -999,9 +980,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 		    {
 		      size_t n = dyn_filesz / sizeof (Elf64_Dyn);
 		      for (size_t i = 0; i < n; ++i)
-			if (u->d64[i].d_tag == DT_DEBUG)
+			if (d64[i].d_tag == DT_DEBUG)
 			  {
-			    r_debug_vaddr = u->d64[i].d_un.d_val;
+			    r_debug_vaddr = d64[i].d_un.d_val;
 			    break;
 			  }
 		    }
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 1916877..33efda0 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,8 @@
+2015-10-01  Chih-Hung Hsieh <chh@google.com>
+
+	* elf_getarsym.c (elf_getarsym): Do not use
+	union of variable length arrays.
+
 2015-09-23  Mark Wielaard  <mjw@redhat.com>
 
 	* elf32_getehdr.c (getehdr_wrlock): Mark as internal_function.
diff --git a/libelf/elf_getarsym.c b/libelf/elf_getarsym.c
index 1ab94ca..f5ee3cb 100644
--- a/libelf/elf_getarsym.c
+++ b/libelf/elf_getarsym.c
@@ -201,11 +201,7 @@ elf_getarsym (Elf *elf, size_t *ptr)
       elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len);
       if (elf->state.ar.ar_sym != NULL)
 	{
-	  union
-	  {
-	    uint32_t u32[n];
-	    uint64_t u64[n];
-	  } *file_data;
+	  void *file_data; /* unit32_t[n] or uint64_t[n] */
 	  char *str_data;
 	  size_t sz = n * w;
 
@@ -272,7 +268,7 @@ elf_getarsym (Elf *elf, size_t *ptr)
 	      arsym[cnt].as_name = str_data;
 	      if (index64_p)
 		{
-		  uint64_t tmp = file_data->u64[cnt];
+		  uint64_t tmp = ((uint64_t *) file_data)[cnt];
 		  if (__BYTE_ORDER == __LITTLE_ENDIAN)
 		    tmp = bswap_64 (tmp);
 
@@ -294,9 +290,9 @@ elf_getarsym (Elf *elf, size_t *ptr)
 		    }
 		}
 	      else if (__BYTE_ORDER == __LITTLE_ENDIAN)
-		arsym[cnt].as_off = bswap_32 (file_data->u32[cnt]);
+		arsym[cnt].as_off = bswap_32 (((uint32_t *) file_data)[cnt]);
 	      else
-		arsym[cnt].as_off = file_data->u32[cnt];
+		arsym[cnt].as_off = ((uint32_t *) file_data)[cnt];
 
 	      arsym[cnt].as_hash = _dl_elf_hash (str_data);
 	      str_data = rawmemchr (str_data, '\0') + 1;
diff --git a/src/ChangeLog b/src/ChangeLog
index 49aa3f7..8b13705 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,11 @@
+2015-10-01  Chih-Hung Hsieh <chh@google.com>
+
+	* unstrip.c (find_alloc_sections_prelink): Do not allocate
+	on stack union types with variable length arrays; use xmalloc
+	for such dynamic sized objects.
+	* readelf.c (handle_core_item): Likewise, but use alloca
+	for small variable size data object and add assert(count < 128).
+
 2015-09-22  Mark Wielaard  <mjw@redhat.com>
 
 	* strip.c (cleanup_debug): Remove old-style function definitions.
diff --git a/src/readelf.c b/src/readelf.c
index 33274f3..fe7bc39 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -8370,6 +8370,9 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 		  unsigned int colno, size_t *repeated_size)
 {
   uint_fast16_t count = item->count ?: 1;
+  /* Ebl_Core_Item count is always a small number.
+     Make sure the backend didn't put in some large bogus value.  */
+  assert (count < 128);
 
 #define TYPES								      \
   DO_TYPE (BYTE, Byte, "0x%.2" PRIx8, "%" PRId8);			      \
@@ -8379,11 +8382,16 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
   DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64);			      \
   DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64)
 
-#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name[count]
-  union { TYPES; } value;
+#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name
+  typedef union { TYPES; } value_t;
+  void *data = alloca (count * sizeof (value_t));
+#undef DO_TYPE
+
+#define DO_TYPE(NAME, Name, hex, dec) \
+    GElf_##Name *value_##Name __attribute__((unused)) = data
+  TYPES;
 #undef DO_TYPE
 
-  void *data = &value;
   size_t size = gelf_fsize (core, item->type, count, EV_CURRENT);
   size_t convsize = size;
   if (repeated_size != NULL)
@@ -8414,7 +8422,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
 	    colno = print_core_item (colno, ',', WRAP_COLUMN,		      \
-				     0, item->name, dec, value.Name[0]); \
+				     0, item->name, dec, value_##Name[0]); \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8430,7 +8438,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
 	    colno = print_core_item (colno, ',', WRAP_COLUMN,		      \
-				     0, item->name, hex, value.Name[0]);      \
+				     0, item->name, hex, value_##Name[0]);      \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8520,8 +8528,8 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 	{
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
-	    sec = value.Name[0];					      \
-	    usec = value.Name[1];					      \
+	    sec = value_##Name[0];					      \
+	    usec = value_##Name[1];					      \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8551,12 +8559,12 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
     case 'c':
       assert (count == 1);
       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
-			       "%c", value.Byte[0]);
+			       "%c", value_Byte[0]);
       break;
 
     case 's':
       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
-			       "%.*s", (int) count, value.Byte);
+			       "%.*s", (int) count, value_Byte);
       break;
 
     case '\n':
diff --git a/src/unstrip.c b/src/unstrip.c
index 82bcdd8..2f380b3 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -54,6 +54,10 @@
 # define _(str) gettext (str)
 #endif
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 /* Name and version of program.  */
 static void print_version (FILE *stream, struct argp_state *state);
 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
@@ -1013,13 +1017,17 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	error (EXIT_FAILURE, 0, _("invalid contents in '%s' section"),
 	       ".gnu.prelink_undo");
 
-      union
-      {
-	Elf32_Shdr s32[shnum - 1];
-	Elf64_Shdr s64[shnum - 1];
-      } shdr;
-      dst.d_buf = &shdr;
-      dst.d_size = sizeof shdr;
+      const size_t shdr_bytes =
+          (shnum - 1) * MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr));
+      if (unlikely (shdr_bytes / (shnum - 1 ) !=
+                    MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr))))
+	error (EXIT_FAILURE, 0, _("overflow with shnum = %zu in '%s' section"),
+	       (size_t) shnum, ".gnu.prelink_undo");
+      void *shdr = xmalloc (shdr_bytes);
+      Elf32_Shdr *s32 = shdr;
+      Elf64_Shdr *s64 = shdr;
+      dst.d_buf = shdr;
+      dst.d_size = shdr_bytes;
       ELF_CHECK (gelf_xlatetom (main, &dst, &src,
 				main_ehdr->e_ident[EI_DATA]) != NULL,
 		 _("cannot read '.gnu.prelink_undo' section: %s"));
@@ -1030,7 +1038,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	  struct section *sec = &undo_sections[undo_nalloc];
 	  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
 	    {
-#define COPY(field) sec->shdr.field = shdr.s32[i].field
+#define COPY(field) sec->shdr.field = s32[i].field
 	      COPY (sh_name);
 	      COPY (sh_type);
 	      COPY (sh_flags);
@@ -1044,7 +1052,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 #undef	COPY
 	    }
 	  else
-	    sec->shdr = shdr.s64[i];
+	    sec->shdr = s64[i];
 	  if (sec->shdr.sh_flags & SHF_ALLOC)
 	    {
 	      sec->shdr.sh_addr += bias;
@@ -1057,6 +1065,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	}
       qsort (undo_sections, undo_nalloc,
 	     sizeof undo_sections[0], compare_sections_nonrel);
+      free (shdr);
     }
 
   bool fail = false;
-- 
2.6.0.rc2.230.g3dd15c0


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-01 17:22 Roland McGrath
  0 siblings, 0 replies; 34+ messages in thread
From: Roland McGrath @ 2015-10-01 17:22 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 290 bytes --]

In ChangeLog entries, "Likewise" should be followed by a period.

You have some readelf changes that are not directly part of avoiding
unions.  They are also not described in the src/ChangeLog entry.
Please post those separately and describe their justifications.


Thanks,
Roland

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-10-01  0:14 Chih-Hung Hsieh
  0 siblings, 0 replies; 34+ messages in thread
From: Chih-Hung Hsieh @ 2015-10-01  0:14 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 4640 bytes --]

Please review the new attached 0004*patch file.

Compared with previous 0003-Do-without-union-of-variable-length-arrays.patch
the new 0004-* patch has:

* Synced in latest elfutils.
* Updated changes to ChangeLog files.
* Checked overflow before malloc or xmalloc:
     xmalloc(shdr_bytes) in src/unstrip.c
     malloc(phnum * phent) in libdwfl/link_map.c
     malloc(phdrs_bytes) in libdwfl/dwfl_module_getdwarf.c
     malloc(phdrsp_bytes) in libdwfl/dwfl_segment_report_module.c
* Used new suggested comment about assert (count < 128) in src/readelf.c.
* Reverted back to alloca for the data pointer to value_t in src/readelf.c

Thanks.


On Thu, Sep 17, 2015 at 2:40 AM, Mark Wielaard <mjw@redhat.com> wrote:

> Hi,
>
> On Wed, 2015-09-16 at 16:16 -0700, Chih-hung Hsieh wrote:
> > * I used alloca to keep the same functionality,
> >   but now they are replaced with malloc or xmalloc.
>
> Thanks, that looks good. But not all needed to change to malloc, when we
> know the size is bounded it is simpler to use alloca I think. See below.
>
> > * Now const size_t is used instead of const int for malloc argument type.
>
> Thanks. I am still interested in the overflow issue. I believe since we
> are using unsigned arithmetic and we know the size is always > 0, it
> should be as simple as doing:
>
>   const size_t elem_size = ... sizeof (...);
>   const size_t bytes = num * elem_size;
>   if (unlikely (bytes / elem_size != num))
>     return E_NOMEM;
>   ... malloc (bytes);
>
> > * I added assert(count<128) with simple comment,
> >   but I am not familiar with all the size assumptions to add extra
> checks.
> >   Could someone more familiar with these modules do it?
>
> Yes, sorry. I think the assert you added is all that is needed. I'll
> suggest better wording for the comment. It was mainly to help review the
> changes. I wanted to make sure we weren't accidentally doing unbounded
> (stack) allocations.
>
> > It's unfortunate that we will lose some compile time bound checking
> > from gnu-compatible tools. I think all clang based tools cannot
> > handle such VLA in union or struct anyway. I hope this is a reasonable
> > trade off to get wider use of elfutils on Android, which is moving fast
> > to use clang as the default compiler.
>
> I appreciate your end goal, but lets take it one patch at a time. Your
> patches and the reviews have improved the code which is a good thing.
> Thanks for taking the time to address the issues. It has been a great
> help. And you pointing out some missing compiler warnings tricked me
> into adding them to GCC, so that is another nice thing (really, gcc is
> pretty good and easy to hack on, I am not sure using clang has any real
> benefit, at least for elfutils).
>
> elfutils is best used with the GNU toolchain though. It would be good to
> support any ELF/DWARF based system if at all possible. On android you
> will also have to cope with not having glibc around. elfutils has been
> made to work on kfreebsd and with uClibc, so it should hopefully also
> work on android with some additional work.
>
> > @@ -8370,6 +8370,8 @@ handle_core_item (Elf *core, const Ebl_Core_Item
> *item, const void *desc,
> >                 unsigned int colno, size_t *repeated_size)
> >  {
> >    uint_fast16_t count = item->count ?: 1;
> > +  /* count is variable but should be bound. */
> > +  assert (count < 128);
>
> Assert is good. I would make the comment:
> /* Ebl_Core_Item count is always a small number.
>    Make sure the backend didn't put in some large bogus value.  */
>
> >  #define TYPES
>             \
> >    DO_TYPE (BYTE, Byte, "0x%.2" PRIx8, "%" PRId8);
>     \
> > @@ -8379,11 +8381,16 @@ handle_core_item (Elf *core, const Ebl_Core_Item
> *item, const void *desc,
> >    DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64);
>            \
> >    DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64)
> >
> > -#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name[count]
> > -  union { TYPES; } value;
> > +#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name
> > +  typedef union { TYPES; } value_t;
> > +  void *data = malloc (count * sizeof (value_t));
> > +#undef DO_TYPE
> > +
> > +#define DO_TYPE(NAME, Name, hex, dec) \
> > +    GElf_##Name *value_##Name __attribute__((unused)) = data
> > +  TYPES;
> >  #undef DO_TYPE
> >
> > -  void *data = &value;
>
> I think this can just stay as an alloca since we know it is a small
> bounded number. But if you want to keep it as malloc you'll need to
> check malloc didn't fail.
>
> Thanks,
>
> Mark
>

[-- Attachment #2: attachment.html --]
[-- Type: text/html, Size: 5647 bytes --]

[-- Attachment #3: 0004-Do-without-union-of-variable-length-arrays.patch --]
[-- Type: application/octet-stream, Size: 27162 bytes --]

From 22234fc7ac745ba18ee137ec28c223843fe3d73d Mon Sep 17 00:00:00 2001
From: Chih-Hung Hsieh <chh@google.com>
Date: Wed, 30 Sep 2015 16:50:42 -0700
Subject: [PATCH] Do without union of variable length arrays.

Prepare to compile with clang.

A union like
  { T32 a32[n]; T64 a64[n]; } u;
is expanded to
  void *data = malloc (...);
  T32 *a32 = data;
  T64 *a64 = data;

Signed-off-by: Chih-Hung Hsieh <chh@google.com>
---
 libdwfl/ChangeLog                    | 10 +++++
 libdwfl/dwfl_module_getdwarf.c       | 53 ++++++++++++----------
 libdwfl/dwfl_segment_report_module.c | 69 ++++++++++++++--------------
 libdwfl/elf-from-memory.c            | 47 +++++++++----------
 libdwfl/link_map.c                   | 87 ++++++++++++++----------------------
 libelf/ChangeLog                     |  5 +++
 libelf/elf_getarsym.c                | 12 ++---
 src/ChangeLog                        |  9 ++++
 src/readelf.c                        | 26 +++++++----
 src/unstrip.c                        | 27 +++++++----
 10 files changed, 184 insertions(+), 161 deletions(-)

diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index f34087c..5524a2a 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,13 @@
+2015-09-30  Chih-Hung Hsieh <chh@google.com>
+
+	* dwfl_module_getdwarf.c (find_prelink_address_sync): Do not use
+	union of variable length arrays.
+	* dwfl_segment_report_module.c (dwfl_segment_report_module): Likewise
+	* elf-from-memory.c (elf_from_remote_memory): Likewise
+	* link_map.c (auxv_format_probe): Likewise
+	* link_map.c (report_r_debug): Likewise
+	* link_map.c (dwfl_link_map_report): Likewise
+
 2015-09-22  Mark Wielaard  <mjw@redhat.com>
 
 	* core-file.c: Remove old-style function definitions.
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index dba9d66..74cb19f 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -34,6 +34,10 @@
 #include "../libdw/libdwP.h"	/* DWARF_E_* values are here.  */
 #include "../libelf/libelfP.h"
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 static inline Dwfl_Error
 open_elf_file (Elf **elf, int *fd, char **name)
 {
@@ -368,16 +372,18 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
 
   GElf_Addr undo_interp = 0;
   {
-    typedef union
-    {
-      Elf32_Phdr p32[phnum];
-      Elf64_Phdr p64[phnum];
-    } phdr;
-    phdr *phdrs = malloc (sizeof (phdr));
+    const size_t phdrs_bytes =
+        phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+    if (unlikely (phdrs_bytes / phnum != 
+                  MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr))))
+      return DWFL_E_NOMEM;
+    void *phdrs = malloc (phdrs_bytes);
+    Elf32_Phdr *p32 = phdrs;
+    Elf64_Phdr *p64 = phdrs;
     if (unlikely (phdrs == NULL))
       return DWFL_E_NOMEM;
     dst.d_buf = phdrs;
-    dst.d_size = sizeof (phdr);
+    dst.d_size = phdrs_bytes;
     if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
 				 ehdr.e32.e_ident[EI_DATA]) == NULL))
       {
@@ -387,18 +393,18 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
     if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
       {
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  if (phdrs->p32[i].p_type == PT_INTERP)
+	  if (p32[i].p_type == PT_INTERP)
 	    {
-	      undo_interp = phdrs->p32[i].p_vaddr;
+	      undo_interp = p32[i].p_vaddr;
 	      break;
 	    }
       }
     else
       {
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  if (phdrs->p64[i].p_type == PT_INTERP)
+	  if (p64[i].p_type == PT_INTERP)
 	    {
-	      undo_interp = phdrs->p64[i].p_vaddr;
+	      undo_interp = p64[i].p_vaddr;
 	      break;
 	    }
       }
@@ -412,16 +418,15 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
   src.d_type = ELF_T_SHDR;
   src.d_size = gelf_fsize (mod->main.elf, ELF_T_SHDR, shnum - 1, EV_CURRENT);
 
-  typedef union
-  {
-    Elf32_Shdr s32[shnum - 1];
-    Elf64_Shdr s64[shnum - 1];
-  } shdr;
-  shdr *shdrs = malloc (sizeof (shdr));
+  const size_t shdrs_bytes =
+      (shnum - 1) * MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr));
+  void *shdrs = malloc (shdrs_bytes);
+  Elf32_Shdr *s32 = shdrs;
+  Elf64_Shdr *s64 = shdrs;
   if (unlikely (shdrs == NULL))
     return DWFL_E_NOMEM;
   dst.d_buf = shdrs;
-  dst.d_size = sizeof (shdr);
+  dst.d_size = shdrs_bytes;
   if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
 			       ehdr.e32.e_ident[EI_DATA]) == NULL))
     {
@@ -484,14 +489,14 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
       highest = 0;
       if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
 	for (size_t i = 0; i < shnum - 1; ++i)
-	  consider_shdr (undo_interp, shdrs->s32[i].sh_type,
-			 shdrs->s32[i].sh_flags, shdrs->s32[i].sh_addr,
-			 shdrs->s32[i].sh_size);
+	  consider_shdr (undo_interp, s32[i].sh_type,
+			 s32[i].sh_flags, s32[i].sh_addr,
+			 s32[i].sh_size);
       else
 	for (size_t i = 0; i < shnum - 1; ++i)
-	  consider_shdr (undo_interp, shdrs->s64[i].sh_type,
-			 shdrs->s64[i].sh_flags, shdrs->s64[i].sh_addr,
-			 shdrs->s64[i].sh_size);
+	  consider_shdr (undo_interp, s64[i].sh_type,
+			 s64[i].sh_flags, s64[i].sh_addr,
+			 s64[i].sh_size);
 
       if (highest > file->vaddr)
 	file->address_sync = highest;
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index a0f07ad..613f779 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -53,6 +53,10 @@
 # define MY_ELFDATA	ELFDATA2MSB
 #endif
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 
 /* Return user segment index closest to ADDR but not above it.
    If NEXT, return the closest to ADDR but not below it.  */
@@ -404,19 +408,19 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
   xlatefrom.d_buf = ph_buffer;
 
-  typedef union
-  {
-    Elf32_Phdr p32[phnum];
-    Elf64_Phdr p64[phnum];
-  } phdrsn;
-
-  phdrsp = malloc (sizeof (phdrsn));
+  const size_t phdrsp_bytes =
+      phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+  if (unlikely (phdrsp_bytes / phnum !=
+                MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr))))
+    return finish ();
+  phdrsp = malloc (phdrsp_bytes);
+  Elf32_Phdr *p32 = phdrsp;
+  Elf64_Phdr *p64 = phdrsp;
   if (unlikely (phdrsp == NULL))
     return finish ();
-  phdrsn *phdrs = (phdrsn *) phdrsp;
 
-  xlateto.d_buf = phdrs;
-  xlateto.d_size = sizeof (phdrsn);
+  xlateto.d_buf = phdrsp;
+  xlateto.d_size = phdrsp_bytes;
 
   /* Track the bounds of the file visible in memory.  */
   GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end.  */
@@ -579,10 +583,10 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	found_bias = false;	/* Trigger error check.  */
       else
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  consider_phdr (phdrs->p32[i].p_type,
-			 phdrs->p32[i].p_vaddr, phdrs->p32[i].p_memsz,
-			 phdrs->p32[i].p_offset, phdrs->p32[i].p_filesz,
-			 phdrs->p32[i].p_align);
+	  consider_phdr (p32[i].p_type,
+			 p32[i].p_vaddr, p32[i].p_memsz,
+			 p32[i].p_offset, p32[i].p_filesz,
+			 p32[i].p_align);
     }
   else
     {
@@ -590,10 +594,10 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	found_bias = false;	/* Trigger error check.  */
       else
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  consider_phdr (phdrs->p64[i].p_type,
-			 phdrs->p64[i].p_vaddr, phdrs->p64[i].p_memsz,
-			 phdrs->p64[i].p_offset, phdrs->p64[i].p_filesz,
-			 phdrs->p64[i].p_align);
+	  consider_phdr (p64[i].p_type,
+			 p64[i].p_vaddr, p64[i].p_memsz,
+			 p64[i].p_offset, p64[i].p_filesz,
+			 p64[i].p_align);
     }
 
   finish_portion (&ph_buffer, &ph_buffer_size);
@@ -749,44 +753,39 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
   const size_t dyn_entsize = (ei_class == ELFCLASS32
 			      ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
-  void *dyns = NULL;
   void *dyn_data = NULL;
   size_t dyn_data_size = 0;
   if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
       && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz))
     {
-      typedef union
-      {
-	Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
-	Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
-      } dynn;
-      dyns = malloc (sizeof (dynn));
+      void *dyns = malloc (dyn_filesz);
+      Elf32_Dyn *d32 = dyns;
+      Elf64_Dyn *d64 = dyns;
       if (unlikely (dyns == NULL))
 	return finish ();
-      dynn *dyn = (dynn *) dyns;
 
       xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
       xlatefrom.d_buf = (void *) dyn_data;
       xlatefrom.d_size = dyn_filesz;
-      xlateto.d_buf = dyn;
-      xlateto.d_size = sizeof (dynn);
+      xlateto.d_buf = dyns;
+      xlateto.d_size = dyn_filesz;
 
       if (ei_class == ELFCLASS32)
 	{
 	  if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
 	    for (size_t i = 0; i < dyn_filesz / sizeof (Elf32_Dyn); ++i)
-	      if (consider_dyn (dyn->d32[i].d_tag, dyn->d32[i].d_un.d_val))
+	      if (consider_dyn (d32[i].d_tag, d32[i].d_un.d_val))
 		break;
 	}
       else
 	{
 	  if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
 	    for (size_t i = 0; i < dyn_filesz / sizeof (Elf64_Dyn); ++i)
-	      if (consider_dyn (dyn->d64[i].d_tag, dyn->d64[i].d_un.d_val))
+	      if (consider_dyn (d64[i].d_tag, d64[i].d_un.d_val))
 		break;
 	}
+      free (dyns);
     }
-  free (dyns);
   finish_portion (&dyn_data, &dyn_data_size);
 
   /* We'll use the name passed in or a stupid default if not DT_SONAME.  */
@@ -901,12 +900,12 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
 	  if (ei_class == ELFCLASS32)
 	    for (uint_fast16_t i = 0; i < phnum; ++i)
-	      read_phdr (phdrs->p32[i].p_type, phdrs->p32[i].p_vaddr,
-			 phdrs->p32[i].p_offset, phdrs->p32[i].p_filesz);
+	      read_phdr (p32[i].p_type, p32[i].p_vaddr,
+			 p32[i].p_offset, p32[i].p_filesz);
 	  else
 	    for (uint_fast16_t i = 0; i < phnum; ++i)
-	      read_phdr (phdrs->p64[i].p_type, phdrs->p64[i].p_vaddr,
-			 phdrs->p64[i].p_offset, phdrs->p64[i].p_filesz);
+	      read_phdr (p64[i].p_type, p64[i].p_vaddr,
+			 p64[i].p_offset, p64[i].p_filesz);
 	}
       else
 	{
diff --git a/libdwfl/elf-from-memory.c b/libdwfl/elf-from-memory.c
index ed8f6e9..52d8395 100644
--- a/libdwfl/elf-from-memory.c
+++ b/libdwfl/elf-from-memory.c
@@ -38,6 +38,10 @@
 #include <stdlib.h>
 #include <string.h>
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 /* Reconstruct an ELF file by reading the segments out of remote memory
    based on the ELF file header at EHDR_VMA and the ELF program headers it
    points to.  If not null, *LOADBASEP is filled in with the difference
@@ -191,22 +195,19 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
       xlatefrom.d_buf = buffer;
     }
 
-  typedef union
-  {
-    Elf32_Phdr p32[phnum];
-    Elf64_Phdr p64[phnum];
-  } phdrsn;
-
-  phdrsp = malloc (sizeof (phdrsn));
+  const size_t phdrsp_bytes =
+      phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+  phdrsp = malloc (phdrsp_bytes);
+  Elf32_Phdr *p32 = phdrsp;
+  Elf64_Phdr *p64 = phdrsp;
   if (unlikely (phdrsp == NULL))
     {
       free (buffer);
       goto no_memory;
     }
-  phdrsn *phdrs = (phdrsn *) phdrsp;
 
-  xlateto.d_buf = phdrs;
-  xlateto.d_size = sizeof (phdrsn);
+  xlateto.d_buf = phdrsp;
+  xlateto.d_size = phdrsp_bytes;
 
   /* Scan for PT_LOAD segments to find the total size of the file image.  */
   size_t contents_size = 0;
@@ -249,9 +250,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 			  ehdr.e32.e_ident[EI_DATA]) == NULL)
 	goto libelf_error;
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p32[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset,
-			      phdrs->p32[i].p_filesz, phdrs->p32[i].p_memsz))
+	if (p32[i].p_type == PT_LOAD)
+	  if (handle_segment (p32[i].p_vaddr, p32[i].p_offset,
+			      p32[i].p_filesz, p32[i].p_memsz))
 	    goto bad_elf;
       break;
 
@@ -260,9 +261,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 			  ehdr.e64.e_ident[EI_DATA]) == NULL)
 	goto libelf_error;
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p64[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset,
-			      phdrs->p64[i].p_filesz, phdrs->p64[i].p_memsz))
+	if (p64[i].p_type == PT_LOAD)
+	  if (handle_segment (p64[i].p_vaddr, p64[i].p_offset,
+			      p64[i].p_filesz, p64[i].p_memsz))
 	    goto bad_elf;
       break;
 
@@ -315,9 +316,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 
     case ELFCLASS32:
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p32[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset,
-			      phdrs->p32[i].p_filesz))
+	if (p32[i].p_type == PT_LOAD)
+	  if (handle_segment (p32[i].p_vaddr, p32[i].p_offset,
+			      p32[i].p_filesz))
 	    goto read_error;
 
       /* If the segments visible in memory didn't include the section
@@ -342,9 +343,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 
     case ELFCLASS64:
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p64[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset,
-			      phdrs->p64[i].p_filesz))
+	if (p64[i].p_type == PT_LOAD)
+	  if (handle_segment (p64[i].p_vaddr, p64[i].p_offset,
+			      p64[i].p_filesz))
 	    goto read_error;
 
       /* If the segments visible in memory didn't include the section
@@ -373,7 +374,7 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
     }
 
   free (phdrsp);
-  phdrs = phdrsp = NULL;
+  phdrsp = NULL;
 
   /* Now we have the image.  Open libelf on it.  */
 
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index 030c600..c55c7f0 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -48,20 +48,16 @@ static bool
 auxv_format_probe (const void *auxv, size_t size,
 		   uint_fast8_t *elfclass, uint_fast8_t *elfdata)
 {
-  const union
-  {
-    char buf[size];
-    Elf32_auxv_t a32[size / sizeof (Elf32_auxv_t)];
-    Elf64_auxv_t a64[size / sizeof (Elf64_auxv_t)];
-  } *u = auxv;
+  const Elf32_auxv_t *a32 = auxv;
+  const Elf64_auxv_t *a64 = auxv;
 
   inline bool check64 (size_t i)
   {
     /* The AUXV pointer might not even be naturally aligned for 64-bit
        data, because note payloads in a core file are not aligned.  */
 
-    uint64_t type = read_8ubyte_unaligned_noncvt (&u->a64[i].a_type);
-    uint64_t val = read_8ubyte_unaligned_noncvt (&u->a64[i].a_un.a_val);
+    uint64_t type = read_8ubyte_unaligned_noncvt (&a64[i].a_type);
+    uint64_t val = read_8ubyte_unaligned_noncvt (&a64[i].a_un.a_val);
 
     if (type == BE64 (PROBE_TYPE)
 	&& val == BE64 (PROBE_VAL64))
@@ -85,8 +81,8 @@ auxv_format_probe (const void *auxv, size_t size,
     /* The AUXV pointer might not even be naturally aligned for 32-bit
        data, because note payloads in a core file are not aligned.  */
 
-    uint32_t type = read_4ubyte_unaligned_noncvt (&u->a32[i].a_type);
-    uint32_t val = read_4ubyte_unaligned_noncvt (&u->a32[i].a_un.a_val);
+    uint32_t type = read_4ubyte_unaligned_noncvt (&a32[i].a_type);
+    uint32_t val = read_4ubyte_unaligned_noncvt (&a32[i].a_un.a_val);
 
     if (type == BE32 (PROBE_TYPE)
 	&& val == BE32 (PROBE_VAL32))
@@ -280,29 +276,26 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
 	  return true;
       }
 
-    const union
-    {
-      Elf32_Addr a32[n];
-      Elf64_Addr a64[n];
-    } *in = vaddr - read_vaddr + buffer;
+    Elf32_Addr *a32 = vaddr - read_vaddr + buffer;
+    Elf64_Addr *a64 = (void *) a32;
 
     if (elfclass == ELFCLASS32)
       {
 	if (elfdata == ELFDATA2MSB)
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (&in->a32[i]));
+	    addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (&a32[i]));
 	else
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (&in->a32[i]));
+	    addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (&a32[i]));
       }
     else
       {
 	if (elfdata == ELFDATA2MSB)
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (&in->a64[i]));
+	    addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (&a64[i]));
 	else
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (&in->a64[i]));
+	    addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (&a64[i]));
       }
 
     return false;
@@ -861,13 +854,15 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	    }
 	  if (in_ok)
 	    {
-	      typedef union
-	      {
-		Elf32_Phdr p32;
-		Elf64_Phdr p64;
-		char data[phnum * phent];
-	      } data_buf;
-	      data_buf *buf = malloc (sizeof (data_buf));
+	      size_t nbytes = phnum * phent;
+	      if (unlikely (phnum != nbytes / phent))
+		{
+		  __libdwfl_seterrno (DWFL_E_NOMEM);
+		  return false;
+		}
+	      void *buf = malloc (nbytes);
+	      Elf32_Phdr *p32 = buf;
+	      Elf64_Phdr *p64 = buf;
 	      if (unlikely (buf == NULL))
 		{
 		  __libdwfl_seterrno (DWFL_E_NOMEM);
@@ -886,25 +881,20 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 			  (&out, &in, elfdata) != NULL))
 		{
 		  /* We are looking for PT_DYNAMIC.  */
-		  const union
-		  {
-		    Elf32_Phdr p32[phnum];
-		    Elf64_Phdr p64[phnum];
-		  } *u = (void *) buf;
 		  if (elfclass == ELFCLASS32)
 		    {
 		      for (size_t i = 0; i < phnum; ++i)
-			if (consider_phdr (u->p32[i].p_type,
-					   u->p32[i].p_vaddr,
-					   u->p32[i].p_filesz))
+			if (consider_phdr (p32[i].p_type,
+					   p32[i].p_vaddr,
+					   p32[i].p_filesz))
 			  break;
 		    }
 		  else
 		    {
 		      for (size_t i = 0; i < phnum; ++i)
-			if (consider_phdr (u->p64[i].p_type,
-					   u->p64[i].p_vaddr,
-					   u->p64[i].p_filesz))
+			if (consider_phdr (p64[i].p_type,
+					   p64[i].p_vaddr,
+					   p64[i].p_filesz))
 			  break;
 		    }
 		}
@@ -955,13 +945,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	  if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size,
 				  dyn_vaddr, dyn_filesz, memory_callback_arg))
 	    {
-	      typedef union
-	      {
-		Elf32_Dyn d32;
-		Elf64_Dyn d64;
-		char data[dyn_filesz];
-	      } data_buf;
-	      data_buf *buf = malloc (sizeof (data_buf));
+	      void *buf = malloc (dyn_filesz);
+	      Elf32_Dyn *d32 = buf;
+	      Elf64_Dyn *d64 = buf;
 	      if (unlikely (buf == NULL))
 		{
 		  __libdwfl_seterrno (DWFL_E_NOMEM);
@@ -980,18 +966,13 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 			  (&out, &in, elfdata) != NULL))
 		{
 		  /* We are looking for DT_DEBUG.  */
-		  const union
-		  {
-		    Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
-		    Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
-		  } *u = (void *) buf;
 		  if (elfclass == ELFCLASS32)
 		    {
 		      size_t n = dyn_filesz / sizeof (Elf32_Dyn);
 		      for (size_t i = 0; i < n; ++i)
-			if (u->d32[i].d_tag == DT_DEBUG)
+			if (d32[i].d_tag == DT_DEBUG)
 			  {
-			    r_debug_vaddr = u->d32[i].d_un.d_val;
+			    r_debug_vaddr = d32[i].d_un.d_val;
 			    break;
 			  }
 		    }
@@ -999,9 +980,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 		    {
 		      size_t n = dyn_filesz / sizeof (Elf64_Dyn);
 		      for (size_t i = 0; i < n; ++i)
-			if (u->d64[i].d_tag == DT_DEBUG)
+			if (d64[i].d_tag == DT_DEBUG)
 			  {
-			    r_debug_vaddr = u->d64[i].d_un.d_val;
+			    r_debug_vaddr = d64[i].d_un.d_val;
 			    break;
 			  }
 		    }
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 1916877..757adc1 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,8 @@
+2015-09-30  Chih-Hung Hsieh <chh@google.com>
+
+	* elf_getarsym.c (elf_getarsym): Do not use
+	union of variable length arrays.
+
 2015-09-23  Mark Wielaard  <mjw@redhat.com>
 
 	* elf32_getehdr.c (getehdr_wrlock): Mark as internal_function.
diff --git a/libelf/elf_getarsym.c b/libelf/elf_getarsym.c
index 1ab94ca..f5ee3cb 100644
--- a/libelf/elf_getarsym.c
+++ b/libelf/elf_getarsym.c
@@ -201,11 +201,7 @@ elf_getarsym (Elf *elf, size_t *ptr)
       elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len);
       if (elf->state.ar.ar_sym != NULL)
 	{
-	  union
-	  {
-	    uint32_t u32[n];
-	    uint64_t u64[n];
-	  } *file_data;
+	  void *file_data; /* unit32_t[n] or uint64_t[n] */
 	  char *str_data;
 	  size_t sz = n * w;
 
@@ -272,7 +268,7 @@ elf_getarsym (Elf *elf, size_t *ptr)
 	      arsym[cnt].as_name = str_data;
 	      if (index64_p)
 		{
-		  uint64_t tmp = file_data->u64[cnt];
+		  uint64_t tmp = ((uint64_t *) file_data)[cnt];
 		  if (__BYTE_ORDER == __LITTLE_ENDIAN)
 		    tmp = bswap_64 (tmp);
 
@@ -294,9 +290,9 @@ elf_getarsym (Elf *elf, size_t *ptr)
 		    }
 		}
 	      else if (__BYTE_ORDER == __LITTLE_ENDIAN)
-		arsym[cnt].as_off = bswap_32 (file_data->u32[cnt]);
+		arsym[cnt].as_off = bswap_32 (((uint32_t *) file_data)[cnt]);
 	      else
-		arsym[cnt].as_off = file_data->u32[cnt];
+		arsym[cnt].as_off = ((uint32_t *) file_data)[cnt];
 
 	      arsym[cnt].as_hash = _dl_elf_hash (str_data);
 	      str_data = rawmemchr (str_data, '\0') + 1;
diff --git a/src/ChangeLog b/src/ChangeLog
index 49aa3f7..03600d5 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,12 @@
+2015-09-30  Chih-Hung Hsieh <chh@google.com>
+
+	* readelf.c (print_cfa_program): Do not use
+	variable length arrays on stack or in union.
+	* readelf.c (handle_core_item): Likewise
+	* readelf.c (handle_core_registers): Likewise
+	* unstrip.c (find_alloc_sections_prelink): Likewise
+	* unstrip.c (copy_elided_sections): Likewise
+
 2015-09-22  Mark Wielaard  <mjw@redhat.com>
 
 	* strip.c (cleanup_debug): Remove old-style function definitions.
diff --git a/src/readelf.c b/src/readelf.c
index 33274f3..fe7bc39 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -8370,6 +8370,9 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 		  unsigned int colno, size_t *repeated_size)
 {
   uint_fast16_t count = item->count ?: 1;
+  /* Ebl_Core_Item count is always a small number.
+     Make sure the backend didn't put in some large bogus value.  */
+  assert (count < 128);
 
 #define TYPES								      \
   DO_TYPE (BYTE, Byte, "0x%.2" PRIx8, "%" PRId8);			      \
@@ -8379,11 +8382,16 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
   DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64);			      \
   DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64)
 
-#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name[count]
-  union { TYPES; } value;
+#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name
+  typedef union { TYPES; } value_t;
+  void *data = alloca (count * sizeof (value_t));
+#undef DO_TYPE
+
+#define DO_TYPE(NAME, Name, hex, dec) \
+    GElf_##Name *value_##Name __attribute__((unused)) = data
+  TYPES;
 #undef DO_TYPE
 
-  void *data = &value;
   size_t size = gelf_fsize (core, item->type, count, EV_CURRENT);
   size_t convsize = size;
   if (repeated_size != NULL)
@@ -8414,7 +8422,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
 	    colno = print_core_item (colno, ',', WRAP_COLUMN,		      \
-				     0, item->name, dec, value.Name[0]); \
+				     0, item->name, dec, value_##Name[0]); \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8430,7 +8438,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
 	    colno = print_core_item (colno, ',', WRAP_COLUMN,		      \
-				     0, item->name, hex, value.Name[0]);      \
+				     0, item->name, hex, value_##Name[0]);      \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8520,8 +8528,8 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 	{
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
-	    sec = value.Name[0];					      \
-	    usec = value.Name[1];					      \
+	    sec = value_##Name[0];					      \
+	    usec = value_##Name[1];					      \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8551,12 +8559,12 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
     case 'c':
       assert (count == 1);
       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
-			       "%c", value.Byte[0]);
+			       "%c", value_Byte[0]);
       break;
 
     case 's':
       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
-			       "%.*s", (int) count, value.Byte);
+			       "%.*s", (int) count, value_Byte);
       break;
 
     case '\n':
diff --git a/src/unstrip.c b/src/unstrip.c
index 82bcdd8..2f380b3 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -54,6 +54,10 @@
 # define _(str) gettext (str)
 #endif
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 /* Name and version of program.  */
 static void print_version (FILE *stream, struct argp_state *state);
 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
@@ -1013,13 +1017,17 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	error (EXIT_FAILURE, 0, _("invalid contents in '%s' section"),
 	       ".gnu.prelink_undo");
 
-      union
-      {
-	Elf32_Shdr s32[shnum - 1];
-	Elf64_Shdr s64[shnum - 1];
-      } shdr;
-      dst.d_buf = &shdr;
-      dst.d_size = sizeof shdr;
+      const size_t shdr_bytes =
+          (shnum - 1) * MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr));
+      if (unlikely (shdr_bytes / (shnum - 1 ) !=
+                    MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr))))
+	error (EXIT_FAILURE, 0, _("overflow with shnum = %zu in '%s' section"),
+	       (size_t) shnum, ".gnu.prelink_undo");
+      void *shdr = xmalloc (shdr_bytes);
+      Elf32_Shdr *s32 = shdr;
+      Elf64_Shdr *s64 = shdr;
+      dst.d_buf = shdr;
+      dst.d_size = shdr_bytes;
       ELF_CHECK (gelf_xlatetom (main, &dst, &src,
 				main_ehdr->e_ident[EI_DATA]) != NULL,
 		 _("cannot read '.gnu.prelink_undo' section: %s"));
@@ -1030,7 +1038,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	  struct section *sec = &undo_sections[undo_nalloc];
 	  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
 	    {
-#define COPY(field) sec->shdr.field = shdr.s32[i].field
+#define COPY(field) sec->shdr.field = s32[i].field
 	      COPY (sh_name);
 	      COPY (sh_type);
 	      COPY (sh_flags);
@@ -1044,7 +1052,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 #undef	COPY
 	    }
 	  else
-	    sec->shdr = shdr.s64[i];
+	    sec->shdr = s64[i];
 	  if (sec->shdr.sh_flags & SHF_ALLOC)
 	    {
 	      sec->shdr.sh_addr += bias;
@@ -1057,6 +1065,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	}
       qsort (undo_sections, undo_nalloc,
 	     sizeof undo_sections[0], compare_sections_nonrel);
+      free (shdr);
     }
 
   bool fail = false;
-- 
2.6.0.rc2.230.g3dd15c0


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-09-17  9:40 Mark Wielaard
  0 siblings, 0 replies; 34+ messages in thread
From: Mark Wielaard @ 2015-09-17  9:40 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 3721 bytes --]

Hi,

On Wed, 2015-09-16 at 16:16 -0700, Chih-hung Hsieh wrote:
> * I used alloca to keep the same functionality,
>   but now they are replaced with malloc or xmalloc.

Thanks, that looks good. But not all needed to change to malloc, when we
know the size is bounded it is simpler to use alloca I think. See below.

> * Now const size_t is used instead of const int for malloc argument type.

Thanks. I am still interested in the overflow issue. I believe since we
are using unsigned arithmetic and we know the size is always > 0, it
should be as simple as doing:

  const size_t elem_size = ... sizeof (...);
  const size_t bytes = num * elem_size;
  if (unlikely (bytes / elem_size != num))
    return E_NOMEM;
  ... malloc (bytes);

> * I added assert(count<128) with simple comment,
>   but I am not familiar with all the size assumptions to add extra checks.
>   Could someone more familiar with these modules do it?

Yes, sorry. I think the assert you added is all that is needed. I'll
suggest better wording for the comment. It was mainly to help review the
changes. I wanted to make sure we weren't accidentally doing unbounded
(stack) allocations.

> It's unfortunate that we will lose some compile time bound checking
> from gnu-compatible tools. I think all clang based tools cannot
> handle such VLA in union or struct anyway. I hope this is a reasonable
> trade off to get wider use of elfutils on Android, which is moving fast
> to use clang as the default compiler.

I appreciate your end goal, but lets take it one patch at a time. Your
patches and the reviews have improved the code which is a good thing.
Thanks for taking the time to address the issues. It has been a great
help. And you pointing out some missing compiler warnings tricked me
into adding them to GCC, so that is another nice thing (really, gcc is
pretty good and easy to hack on, I am not sure using clang has any real
benefit, at least for elfutils).

elfutils is best used with the GNU toolchain though. It would be good to
support any ELF/DWARF based system if at all possible. On android you
will also have to cope with not having glibc around. elfutils has been
made to work on kfreebsd and with uClibc, so it should hopefully also
work on android with some additional work.

> @@ -8370,6 +8370,8 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
>  		  unsigned int colno, size_t *repeated_size)
>  {
>    uint_fast16_t count = item->count ?: 1;
> +  /* count is variable but should be bound. */
> +  assert (count < 128);

Assert is good. I would make the comment:
/* Ebl_Core_Item count is always a small number.
   Make sure the backend didn't put in some large bogus value.  */

>  #define TYPES								      \
>    DO_TYPE (BYTE, Byte, "0x%.2" PRIx8, "%" PRId8);			      \
> @@ -8379,11 +8381,16 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
>    DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64);			      \
>    DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64)
>  
> -#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name[count]
> -  union { TYPES; } value;
> +#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name
> +  typedef union { TYPES; } value_t;
> +  void *data = malloc (count * sizeof (value_t));
> +#undef DO_TYPE
> +
> +#define DO_TYPE(NAME, Name, hex, dec) \
> +    GElf_##Name *value_##Name __attribute__((unused)) = data
> +  TYPES;
>  #undef DO_TYPE
>  
> -  void *data = &value;

I think this can just stay as an alloca since we know it is a small
bounded number. But if you want to keep it as malloc you'll need to
check malloc didn't fail.

Thanks,

Mark

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-09-16 23:16 Chih-Hung Hsieh
  0 siblings, 0 replies; 34+ messages in thread
From: Chih-Hung Hsieh @ 2015-09-16 23:16 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 7101 bytes --]

Mark,

I have made the changes you suggested.
Please take a look of attached 0003*.patch again.

* The comment is changed.  I don't plan to change -std=gnu99 mode yet.
  These changes only avoid some gnu extensions that clang does not like.

* I used alloca to keep the same functionality,
  but now they are replaced with malloc or xmalloc.

* Now const size_t is used instead of const int for malloc argument type.

* I added assert(count<128) with simple comment,
  but I am not familiar with all the size assumptions to add extra checks.
  Could someone more familiar with these modules do it?

* I reverted the changes of on-stack variable length arrays.
  They can be accepted by clang, but not captured into clang Blocks closure.
  Assuming that you prefer replacing nested functions with macros
  or file scope functions, those on-stack VLA can be kept as is:

    char regnamebuf[REGNAMESZ];

    struct register_info regs[maxnreg];
    memset (regs, 0, sizeof regs);

    struct section sections[stripped_shnum - 1];


It's unfortunate that we will lose some compile time bound checking
from gnu-compatible tools. I think all clang based tools cannot
handle such VLA in union or struct anyway. I hope this is a reasonable
trade off to get wider use of elfutils on Android, which is moving fast
to use clang as the default compiler.

Thanks.


On Wed, Sep 16, 2015 at 8:25 AM, Mark Wielaard <mjw@redhat.com> wrote:

> On Fri, 2015-09-11 at 12:22 -0700, Roland McGrath wrote:
> > It looks fine to me from a quick skim, but Mark should review and test
> it too.
>
> I am not super enthusiastic about this change, it seems to just take
> away type/size information that the compiler/bounds checking tools can
> use.
>
> That said I tested the patch under valgrind and with gcc
> -fsanitize-undefined which didn't find any issues.
>
> Some questions that might show how/why it could still be an improvement:
>
> >     Do without union of variable length arrays.
> >
> >     Prepare to compile without gnu99 extension.
>
> I think we still want to compile with several gnu99 extensions. Or is
> your aim to build with -std=c99?
>
> >     A union like
> >       { T32 a32[n]; T64 a64[n]; } u;
> >     is expanded to
> >       void *data = malloc (...);
> >       T32 *a32 = data;
> >       T64 *a64 = data;
>
> That might be useful since that prevents some possibly unbounded stack
> usage. But most of the patch doesn't seem to be about that. Because such
> unions are not allocated on the stack in the first place. There are a
> couple of cases like the above, but there you replace them with an
> alloca, which isn't much better.
>
> > @@ -368,16 +372,15 @@ find_prelink_address_sync (Dwfl_Module *mod,
> struct dwfl_file *file)
> >
> >    GElf_Addr undo_interp = 0;
> >    {
> > -    typedef union
> > -    {
> > -      Elf32_Phdr p32[phnum];
> > -      Elf64_Phdr p64[phnum];
> > -    } phdr;
> > -    phdr *phdrs = malloc (sizeof (phdr));
> > +    const int phdrs_bytes =
> > +        phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
> +    void *phdrs = malloc (phdrs_bytes);
> > +    Elf32_Phdr *p32 = phdrs;
> > +    Elf64_Phdr *p64 = phdrs;
> >      if (unlikely (phdrs == NULL))
> >        return DWFL_E_NOMEM;
>
> phdrs_bytes should be a size_t. And it needs a check that it didn't
> overflow. I am assuming such an overflow check was done by the compiler
> for the previous construct. But if not, then a change like this plus an
> explicit overflow check would be an improvement.
>
> The same pattern using an const int is used a couple of times.
>
> > --- a/src/readelf.c
> > +++ b/src/readelf.c
> > @@ -4943,7 +4943,7 @@ print_cfa_program (const unsigned char *readp,
> const unsigned char *const endp,
> >                    unsigned int version, unsigned int ptr_size,
> >                    Dwfl_Module *dwflmod, Ebl *ebl, Dwarf *dbg)
> >  {
> > -  char regnamebuf[REGNAMESZ];
> > +  char *regnamebuf = alloca (REGNAMESZ);
>
> REGNAMESZ is a constant (defined as 16), why replace with with an alloca?
>
> > @@ -8379,11 +8379,16 @@ handle_core_item (Elf *core, const Ebl_Core_Item
> *item, const void *desc,
> >    DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64);
>      \
> >    DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64)
> >
> > -#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name[count]
> > -  union { TYPES; } value;
> > +#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name
> > +  typedef union { TYPES; } value_t;
> > +  void *data = alloca (count * sizeof (value_t));
> > +#undef DO_TYPE
> > +
> > +#define DO_TYPE(NAME, Name, hex, dec) \
> > +    GElf_##Name *value_##Name __attribute__((unused)) = data
> > +  TYPES;
> >  #undef DO_TYPE
>
> count is actually bounded, but that might not be easy to see.
> We trust the backends to only provide sane Ebl_Core_Item's. The maximum
> number of items I see is in the tilegx backends (which has an item with
> count = 56). So this is fine, but maybe a we should add a comment
> explaining it (or maybe add an assert (count < 128) or something to make
> sure if this every accidentally gets violated we get an warning/error
> early (and not silent stack corruption).
>
> > @@ -8900,8 +8905,9 @@ handle_core_registers (Ebl *ebl, Elf *core, const
> void *desc,
> >        assert (maxnreg > 0);
> >      }
> >
> > -  struct register_info regs[maxnreg];
> > -  memset (regs, 0, sizeof regs);
> > +  const int sizeof_regs = sizeof (struct register_info) * maxnreg;
> > +  struct register_info *regs = alloca (sizeof_regs);
> > +  memset (regs, 0, sizeof_regs);
> >
> >    /* Sort to collect the sets together.  */
> >    int maxreg = 0;
>
> Same here. We count on ebl_register_info to return a (small) bounded
> number.
>
> > @@ -1013,13 +1017,13 @@ find_alloc_sections_prelink (Elf *debug,
> Elf_Data *debug_shstrtab,
> >         error (EXIT_FAILURE, 0, _("invalid contents in '%s' section"),
> >                ".gnu.prelink_undo");
> >
> > -      union
> > -      {
> > -       Elf32_Shdr s32[shnum - 1];
> > -       Elf64_Shdr s64[shnum - 1];
> > -      } shdr;
> > -      dst.d_buf = &shdr;
> > -      dst.d_size = sizeof shdr;
> > +      const int shdr_bytes =
> > +          (shnum - 1) * MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr));
> > +      void *shdr = alloca (shdr_bytes);
> > +      Elf32_Shdr *s32 = shdr;
> > +      Elf64_Shdr *s64 = shdr;
> > +      dst.d_buf = shdr;
> > +      dst.d_size = shdr_bytes;
>
> Here, and in copy_elided_sections there are real stack allocated
> (possibly unbounded) variable length arrays. I think it makes sense to
> actually use malloc/free instead of alloca. Otherwise you just keep the
> problem. The reason this wasn't caught before is because this file isn't
> build with -Wstack-usage. You don't have to make them -Wstack-usage
> clean, but if you are replacing real VLAs anyway, then please don't
> replace them with alloca if at all possible.
>
> Thanks,
>
> Mark
>

[-- Attachment #2: attachment.html --]
[-- Type: text/html, Size: 8735 bytes --]

[-- Attachment #3: 0003-Do-without-union-of-variable-length-arrays.patch --]
[-- Type: application/octet-stream, Size: 26538 bytes --]

From 4982d51949d3a4e2bfb4b5bcd1adc032710987e6 Mon Sep 17 00:00:00 2001
From: Chih-Hung Hsieh <chh@google.com>
Date: Wed, 16 Sep 2015 15:38:46 -0700
Subject: [PATCH] Do without union of variable length arrays.

Prepare to compile with clang.

A union like
  { T32 a32[n]; T64 a64[n]; } u;
is expanded to
  void *data = malloc (...);
  T32 *a32 = data;
  T64 *a64 = data;

Signed-off-by: Chih-Hung Hsieh <chh@google.com>
---
 libdwfl/ChangeLog                    | 10 +++++
 libdwfl/dwfl_module_getdwarf.c       | 50 +++++++++++-----------
 libdwfl/dwfl_segment_report_module.c | 66 ++++++++++++++---------------
 libdwfl/elf-from-memory.c            | 47 +++++++++++----------
 libdwfl/link_map.c                   | 81 +++++++++++++-----------------------
 libelf/ChangeLog                     |  5 +++
 libelf/elf_getarsym.c                | 12 ++----
 src/ChangeLog                        |  9 ++++
 src/readelf.c                        | 26 ++++++++----
 src/unstrip.c                        | 23 ++++++----
 10 files changed, 168 insertions(+), 161 deletions(-)

diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 0ab386f..e839580 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,13 @@
+2015-09-16  Chih-Hung Hsieh <chh@google.com>
+
+	* dwfl_module_getdwarf.c (find_prelink_address_sync): Do not use
+	union of variable length arrays.
+	* dwfl_segment_report_module.c (dwfl_segment_report_module): Likewise
+	* elf-from-memory.c (elf_from_remote_memory): Likewise
+	* link_map.c (auxv_format_probe): Likewise
+	* link_map.c (report_r_debug): Likewise
+	* link_map.c (dwfl_link_map_report): Likewise
+
 2015-09-09  Chih-Hung Hsieh  <chh@google.com>
 	    Mark Wielaard  <mjw@redhat.com>
 
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index dba9d66..45549e9 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -34,6 +34,10 @@
 #include "../libdw/libdwP.h"	/* DWARF_E_* values are here.  */
 #include "../libelf/libelfP.h"
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 static inline Dwfl_Error
 open_elf_file (Elf **elf, int *fd, char **name)
 {
@@ -368,16 +372,15 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
 
   GElf_Addr undo_interp = 0;
   {
-    typedef union
-    {
-      Elf32_Phdr p32[phnum];
-      Elf64_Phdr p64[phnum];
-    } phdr;
-    phdr *phdrs = malloc (sizeof (phdr));
+    const size_t phdrs_bytes =
+        phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+    void *phdrs = malloc (phdrs_bytes);
+    Elf32_Phdr *p32 = phdrs;
+    Elf64_Phdr *p64 = phdrs;
     if (unlikely (phdrs == NULL))
       return DWFL_E_NOMEM;
     dst.d_buf = phdrs;
-    dst.d_size = sizeof (phdr);
+    dst.d_size = phdrs_bytes;
     if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
 				 ehdr.e32.e_ident[EI_DATA]) == NULL))
       {
@@ -387,18 +390,18 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
     if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
       {
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  if (phdrs->p32[i].p_type == PT_INTERP)
+	  if (p32[i].p_type == PT_INTERP)
 	    {
-	      undo_interp = phdrs->p32[i].p_vaddr;
+	      undo_interp = p32[i].p_vaddr;
 	      break;
 	    }
       }
     else
       {
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  if (phdrs->p64[i].p_type == PT_INTERP)
+	  if (p64[i].p_type == PT_INTERP)
 	    {
-	      undo_interp = phdrs->p64[i].p_vaddr;
+	      undo_interp = p64[i].p_vaddr;
 	      break;
 	    }
       }
@@ -412,16 +415,15 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
   src.d_type = ELF_T_SHDR;
   src.d_size = gelf_fsize (mod->main.elf, ELF_T_SHDR, shnum - 1, EV_CURRENT);
 
-  typedef union
-  {
-    Elf32_Shdr s32[shnum - 1];
-    Elf64_Shdr s64[shnum - 1];
-  } shdr;
-  shdr *shdrs = malloc (sizeof (shdr));
+  const size_t shdrs_bytes =
+      (shnum - 1) * MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr));
+  void *shdrs = malloc (shdrs_bytes);
+  Elf32_Shdr *s32 = shdrs;
+  Elf64_Shdr *s64 = shdrs;
   if (unlikely (shdrs == NULL))
     return DWFL_E_NOMEM;
   dst.d_buf = shdrs;
-  dst.d_size = sizeof (shdr);
+  dst.d_size = shdrs_bytes;
   if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
 			       ehdr.e32.e_ident[EI_DATA]) == NULL))
     {
@@ -484,14 +486,14 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
       highest = 0;
       if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
 	for (size_t i = 0; i < shnum - 1; ++i)
-	  consider_shdr (undo_interp, shdrs->s32[i].sh_type,
-			 shdrs->s32[i].sh_flags, shdrs->s32[i].sh_addr,
-			 shdrs->s32[i].sh_size);
+	  consider_shdr (undo_interp, s32[i].sh_type,
+			 s32[i].sh_flags, s32[i].sh_addr,
+			 s32[i].sh_size);
       else
 	for (size_t i = 0; i < shnum - 1; ++i)
-	  consider_shdr (undo_interp, shdrs->s64[i].sh_type,
-			 shdrs->s64[i].sh_flags, shdrs->s64[i].sh_addr,
-			 shdrs->s64[i].sh_size);
+	  consider_shdr (undo_interp, s64[i].sh_type,
+			 s64[i].sh_flags, s64[i].sh_addr,
+			 s64[i].sh_size);
 
       if (highest > file->vaddr)
 	file->address_sync = highest;
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index a0f07ad..24cc758 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -53,6 +53,10 @@
 # define MY_ELFDATA	ELFDATA2MSB
 #endif
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 
 /* Return user segment index closest to ADDR but not above it.
    If NEXT, return the closest to ADDR but not below it.  */
@@ -404,19 +408,16 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
   xlatefrom.d_buf = ph_buffer;
 
-  typedef union
-  {
-    Elf32_Phdr p32[phnum];
-    Elf64_Phdr p64[phnum];
-  } phdrsn;
-
-  phdrsp = malloc (sizeof (phdrsn));
+  const size_t phdrsp_bytes =
+      phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+  phdrsp = malloc (phdrsp_bytes);
+  Elf32_Phdr *p32 = phdrsp;
+  Elf64_Phdr *p64 = phdrsp;
   if (unlikely (phdrsp == NULL))
     return finish ();
-  phdrsn *phdrs = (phdrsn *) phdrsp;
 
-  xlateto.d_buf = phdrs;
-  xlateto.d_size = sizeof (phdrsn);
+  xlateto.d_buf = phdrsp;
+  xlateto.d_size = phdrsp_bytes;
 
   /* Track the bounds of the file visible in memory.  */
   GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end.  */
@@ -579,10 +580,10 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	found_bias = false;	/* Trigger error check.  */
       else
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  consider_phdr (phdrs->p32[i].p_type,
-			 phdrs->p32[i].p_vaddr, phdrs->p32[i].p_memsz,
-			 phdrs->p32[i].p_offset, phdrs->p32[i].p_filesz,
-			 phdrs->p32[i].p_align);
+	  consider_phdr (p32[i].p_type,
+			 p32[i].p_vaddr, p32[i].p_memsz,
+			 p32[i].p_offset, p32[i].p_filesz,
+			 p32[i].p_align);
     }
   else
     {
@@ -590,10 +591,10 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	found_bias = false;	/* Trigger error check.  */
       else
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  consider_phdr (phdrs->p64[i].p_type,
-			 phdrs->p64[i].p_vaddr, phdrs->p64[i].p_memsz,
-			 phdrs->p64[i].p_offset, phdrs->p64[i].p_filesz,
-			 phdrs->p64[i].p_align);
+	  consider_phdr (p64[i].p_type,
+			 p64[i].p_vaddr, p64[i].p_memsz,
+			 p64[i].p_offset, p64[i].p_filesz,
+			 p64[i].p_align);
     }
 
   finish_portion (&ph_buffer, &ph_buffer_size);
@@ -749,44 +750,39 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
   const size_t dyn_entsize = (ei_class == ELFCLASS32
 			      ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
-  void *dyns = NULL;
   void *dyn_data = NULL;
   size_t dyn_data_size = 0;
   if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
       && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz))
     {
-      typedef union
-      {
-	Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
-	Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
-      } dynn;
-      dyns = malloc (sizeof (dynn));
+      void *dyns = malloc (dyn_filesz);
+      Elf32_Dyn *d32 = dyns;
+      Elf64_Dyn *d64 = dyns;
       if (unlikely (dyns == NULL))
 	return finish ();
-      dynn *dyn = (dynn *) dyns;
 
       xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
       xlatefrom.d_buf = (void *) dyn_data;
       xlatefrom.d_size = dyn_filesz;
-      xlateto.d_buf = dyn;
-      xlateto.d_size = sizeof (dynn);
+      xlateto.d_buf = dyns;
+      xlateto.d_size = dyn_filesz;
 
       if (ei_class == ELFCLASS32)
 	{
 	  if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
 	    for (size_t i = 0; i < dyn_filesz / sizeof (Elf32_Dyn); ++i)
-	      if (consider_dyn (dyn->d32[i].d_tag, dyn->d32[i].d_un.d_val))
+	      if (consider_dyn (d32[i].d_tag, d32[i].d_un.d_val))
 		break;
 	}
       else
 	{
 	  if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
 	    for (size_t i = 0; i < dyn_filesz / sizeof (Elf64_Dyn); ++i)
-	      if (consider_dyn (dyn->d64[i].d_tag, dyn->d64[i].d_un.d_val))
+	      if (consider_dyn (d64[i].d_tag, d64[i].d_un.d_val))
 		break;
 	}
+      free (dyns);
     }
-  free (dyns);
   finish_portion (&dyn_data, &dyn_data_size);
 
   /* We'll use the name passed in or a stupid default if not DT_SONAME.  */
@@ -901,12 +897,12 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
 	  if (ei_class == ELFCLASS32)
 	    for (uint_fast16_t i = 0; i < phnum; ++i)
-	      read_phdr (phdrs->p32[i].p_type, phdrs->p32[i].p_vaddr,
-			 phdrs->p32[i].p_offset, phdrs->p32[i].p_filesz);
+	      read_phdr (p32[i].p_type, p32[i].p_vaddr,
+			 p32[i].p_offset, p32[i].p_filesz);
 	  else
 	    for (uint_fast16_t i = 0; i < phnum; ++i)
-	      read_phdr (phdrs->p64[i].p_type, phdrs->p64[i].p_vaddr,
-			 phdrs->p64[i].p_offset, phdrs->p64[i].p_filesz);
+	      read_phdr (p64[i].p_type, p64[i].p_vaddr,
+			 p64[i].p_offset, p64[i].p_filesz);
 	}
       else
 	{
diff --git a/libdwfl/elf-from-memory.c b/libdwfl/elf-from-memory.c
index ed8f6e9..52d8395 100644
--- a/libdwfl/elf-from-memory.c
+++ b/libdwfl/elf-from-memory.c
@@ -38,6 +38,10 @@
 #include <stdlib.h>
 #include <string.h>
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 /* Reconstruct an ELF file by reading the segments out of remote memory
    based on the ELF file header at EHDR_VMA and the ELF program headers it
    points to.  If not null, *LOADBASEP is filled in with the difference
@@ -191,22 +195,19 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
       xlatefrom.d_buf = buffer;
     }
 
-  typedef union
-  {
-    Elf32_Phdr p32[phnum];
-    Elf64_Phdr p64[phnum];
-  } phdrsn;
-
-  phdrsp = malloc (sizeof (phdrsn));
+  const size_t phdrsp_bytes =
+      phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+  phdrsp = malloc (phdrsp_bytes);
+  Elf32_Phdr *p32 = phdrsp;
+  Elf64_Phdr *p64 = phdrsp;
   if (unlikely (phdrsp == NULL))
     {
       free (buffer);
       goto no_memory;
     }
-  phdrsn *phdrs = (phdrsn *) phdrsp;
 
-  xlateto.d_buf = phdrs;
-  xlateto.d_size = sizeof (phdrsn);
+  xlateto.d_buf = phdrsp;
+  xlateto.d_size = phdrsp_bytes;
 
   /* Scan for PT_LOAD segments to find the total size of the file image.  */
   size_t contents_size = 0;
@@ -249,9 +250,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 			  ehdr.e32.e_ident[EI_DATA]) == NULL)
 	goto libelf_error;
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p32[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset,
-			      phdrs->p32[i].p_filesz, phdrs->p32[i].p_memsz))
+	if (p32[i].p_type == PT_LOAD)
+	  if (handle_segment (p32[i].p_vaddr, p32[i].p_offset,
+			      p32[i].p_filesz, p32[i].p_memsz))
 	    goto bad_elf;
       break;
 
@@ -260,9 +261,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 			  ehdr.e64.e_ident[EI_DATA]) == NULL)
 	goto libelf_error;
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p64[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset,
-			      phdrs->p64[i].p_filesz, phdrs->p64[i].p_memsz))
+	if (p64[i].p_type == PT_LOAD)
+	  if (handle_segment (p64[i].p_vaddr, p64[i].p_offset,
+			      p64[i].p_filesz, p64[i].p_memsz))
 	    goto bad_elf;
       break;
 
@@ -315,9 +316,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 
     case ELFCLASS32:
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p32[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset,
-			      phdrs->p32[i].p_filesz))
+	if (p32[i].p_type == PT_LOAD)
+	  if (handle_segment (p32[i].p_vaddr, p32[i].p_offset,
+			      p32[i].p_filesz))
 	    goto read_error;
 
       /* If the segments visible in memory didn't include the section
@@ -342,9 +343,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 
     case ELFCLASS64:
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p64[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset,
-			      phdrs->p64[i].p_filesz))
+	if (p64[i].p_type == PT_LOAD)
+	  if (handle_segment (p64[i].p_vaddr, p64[i].p_offset,
+			      p64[i].p_filesz))
 	    goto read_error;
 
       /* If the segments visible in memory didn't include the section
@@ -373,7 +374,7 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
     }
 
   free (phdrsp);
-  phdrs = phdrsp = NULL;
+  phdrsp = NULL;
 
   /* Now we have the image.  Open libelf on it.  */
 
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index 030c600..a756e43 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -48,20 +48,16 @@ static bool
 auxv_format_probe (const void *auxv, size_t size,
 		   uint_fast8_t *elfclass, uint_fast8_t *elfdata)
 {
-  const union
-  {
-    char buf[size];
-    Elf32_auxv_t a32[size / sizeof (Elf32_auxv_t)];
-    Elf64_auxv_t a64[size / sizeof (Elf64_auxv_t)];
-  } *u = auxv;
+  const Elf32_auxv_t *a32 = auxv;
+  const Elf64_auxv_t *a64 = auxv;
 
   inline bool check64 (size_t i)
   {
     /* The AUXV pointer might not even be naturally aligned for 64-bit
        data, because note payloads in a core file are not aligned.  */
 
-    uint64_t type = read_8ubyte_unaligned_noncvt (&u->a64[i].a_type);
-    uint64_t val = read_8ubyte_unaligned_noncvt (&u->a64[i].a_un.a_val);
+    uint64_t type = read_8ubyte_unaligned_noncvt (&a64[i].a_type);
+    uint64_t val = read_8ubyte_unaligned_noncvt (&a64[i].a_un.a_val);
 
     if (type == BE64 (PROBE_TYPE)
 	&& val == BE64 (PROBE_VAL64))
@@ -85,8 +81,8 @@ auxv_format_probe (const void *auxv, size_t size,
     /* The AUXV pointer might not even be naturally aligned for 32-bit
        data, because note payloads in a core file are not aligned.  */
 
-    uint32_t type = read_4ubyte_unaligned_noncvt (&u->a32[i].a_type);
-    uint32_t val = read_4ubyte_unaligned_noncvt (&u->a32[i].a_un.a_val);
+    uint32_t type = read_4ubyte_unaligned_noncvt (&a32[i].a_type);
+    uint32_t val = read_4ubyte_unaligned_noncvt (&a32[i].a_un.a_val);
 
     if (type == BE32 (PROBE_TYPE)
 	&& val == BE32 (PROBE_VAL32))
@@ -280,29 +276,26 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
 	  return true;
       }
 
-    const union
-    {
-      Elf32_Addr a32[n];
-      Elf64_Addr a64[n];
-    } *in = vaddr - read_vaddr + buffer;
+    Elf32_Addr *a32 = vaddr - read_vaddr + buffer;
+    Elf64_Addr *a64 = (void *) a32;
 
     if (elfclass == ELFCLASS32)
       {
 	if (elfdata == ELFDATA2MSB)
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (&in->a32[i]));
+	    addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (&a32[i]));
 	else
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (&in->a32[i]));
+	    addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (&a32[i]));
       }
     else
       {
 	if (elfdata == ELFDATA2MSB)
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (&in->a64[i]));
+	    addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (&a64[i]));
 	else
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (&in->a64[i]));
+	    addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (&a64[i]));
       }
 
     return false;
@@ -861,13 +854,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	    }
 	  if (in_ok)
 	    {
-	      typedef union
-	      {
-		Elf32_Phdr p32;
-		Elf64_Phdr p64;
-		char data[phnum * phent];
-	      } data_buf;
-	      data_buf *buf = malloc (sizeof (data_buf));
+	      void *buf = malloc (phnum * phent);
+	      Elf32_Phdr *p32 = buf;
+	      Elf64_Phdr *p64 = buf;
 	      if (unlikely (buf == NULL))
 		{
 		  __libdwfl_seterrno (DWFL_E_NOMEM);
@@ -886,25 +875,20 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 			  (&out, &in, elfdata) != NULL))
 		{
 		  /* We are looking for PT_DYNAMIC.  */
-		  const union
-		  {
-		    Elf32_Phdr p32[phnum];
-		    Elf64_Phdr p64[phnum];
-		  } *u = (void *) buf;
 		  if (elfclass == ELFCLASS32)
 		    {
 		      for (size_t i = 0; i < phnum; ++i)
-			if (consider_phdr (u->p32[i].p_type,
-					   u->p32[i].p_vaddr,
-					   u->p32[i].p_filesz))
+			if (consider_phdr (p32[i].p_type,
+					   p32[i].p_vaddr,
+					   p32[i].p_filesz))
 			  break;
 		    }
 		  else
 		    {
 		      for (size_t i = 0; i < phnum; ++i)
-			if (consider_phdr (u->p64[i].p_type,
-					   u->p64[i].p_vaddr,
-					   u->p64[i].p_filesz))
+			if (consider_phdr (p64[i].p_type,
+					   p64[i].p_vaddr,
+					   p64[i].p_filesz))
 			  break;
 		    }
 		}
@@ -955,13 +939,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	  if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size,
 				  dyn_vaddr, dyn_filesz, memory_callback_arg))
 	    {
-	      typedef union
-	      {
-		Elf32_Dyn d32;
-		Elf64_Dyn d64;
-		char data[dyn_filesz];
-	      } data_buf;
-	      data_buf *buf = malloc (sizeof (data_buf));
+	      void *buf = malloc (dyn_filesz);
+	      Elf32_Dyn *d32 = buf;
+	      Elf64_Dyn *d64 = buf;
 	      if (unlikely (buf == NULL))
 		{
 		  __libdwfl_seterrno (DWFL_E_NOMEM);
@@ -980,18 +960,13 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 			  (&out, &in, elfdata) != NULL))
 		{
 		  /* We are looking for DT_DEBUG.  */
-		  const union
-		  {
-		    Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
-		    Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
-		  } *u = (void *) buf;
 		  if (elfclass == ELFCLASS32)
 		    {
 		      size_t n = dyn_filesz / sizeof (Elf32_Dyn);
 		      for (size_t i = 0; i < n; ++i)
-			if (u->d32[i].d_tag == DT_DEBUG)
+			if (d32[i].d_tag == DT_DEBUG)
 			  {
-			    r_debug_vaddr = u->d32[i].d_un.d_val;
+			    r_debug_vaddr = d32[i].d_un.d_val;
 			    break;
 			  }
 		    }
@@ -999,9 +974,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 		    {
 		      size_t n = dyn_filesz / sizeof (Elf64_Dyn);
 		      for (size_t i = 0; i < n; ++i)
-			if (u->d64[i].d_tag == DT_DEBUG)
+			if (d64[i].d_tag == DT_DEBUG)
 			  {
-			    r_debug_vaddr = u->d64[i].d_un.d_val;
+			    r_debug_vaddr = d64[i].d_un.d_val;
 			    break;
 			  }
 		    }
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index bb56e5b..a9685ba 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,8 @@
+2015-09-08  Chih-Hung Hsieh <chh@google.com>
+
+	* elf_getarsym.c (elf_getarsym): Do not use
+	union of variable length arrays.
+
 2015-06-18  Mark Wielaard  <mjw@redhat.com>
 
 	* elf32_updatefile.c (updatefile): Always free shdr_data and scns
diff --git a/libelf/elf_getarsym.c b/libelf/elf_getarsym.c
index 8324244..6f7bfab 100644
--- a/libelf/elf_getarsym.c
+++ b/libelf/elf_getarsym.c
@@ -203,11 +203,7 @@ elf_getarsym (elf, ptr)
       elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len);
       if (elf->state.ar.ar_sym != NULL)
 	{
-	  union
-	  {
-	    uint32_t u32[n];
-	    uint64_t u64[n];
-	  } *file_data;
+	  void *file_data; /* unit32_t[n] or uint64_t[n] */
 	  char *str_data;
 	  size_t sz = n * w;
 
@@ -274,7 +270,7 @@ elf_getarsym (elf, ptr)
 	      arsym[cnt].as_name = str_data;
 	      if (index64_p)
 		{
-		  uint64_t tmp = file_data->u64[cnt];
+		  uint64_t tmp = ((uint64_t *) file_data)[cnt];
 		  if (__BYTE_ORDER == __LITTLE_ENDIAN)
 		    tmp = bswap_64 (tmp);
 
@@ -296,9 +292,9 @@ elf_getarsym (elf, ptr)
 		    }
 		}
 	      else if (__BYTE_ORDER == __LITTLE_ENDIAN)
-		arsym[cnt].as_off = bswap_32 (file_data->u32[cnt]);
+		arsym[cnt].as_off = bswap_32 (((uint32_t *) file_data)[cnt]);
 	      else
-		arsym[cnt].as_off = file_data->u32[cnt];
+		arsym[cnt].as_off = ((uint32_t *) file_data)[cnt];
 
 	      arsym[cnt].as_hash = _dl_elf_hash (str_data);
 	      str_data = rawmemchr (str_data, '\0') + 1;
diff --git a/src/ChangeLog b/src/ChangeLog
index 238c416..d6c1093 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,12 @@
+2015-09-16  Chih-Hung Hsieh <chh@google.com>
+
+	* readelf.c (print_cfa_program): Do not use
+	variable length arrays on stack or in union.
+	* readelf.c (handle_core_item): Likewise
+	* readelf.c (handle_core_registers): Likewise
+	* unstrip.c (find_alloc_sections_prelink): Likewise
+	* unstrip.c (copy_elided_sections): Likewise
+
 2015-09-09  Chih-Hung Hsieh  <chh@google.com>
 
 	* readelf.c (print_debug_exception_table): Initialize variable before
diff --git a/src/readelf.c b/src/readelf.c
index 33274f3..cc6c6d3 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -8370,6 +8370,8 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 		  unsigned int colno, size_t *repeated_size)
 {
   uint_fast16_t count = item->count ?: 1;
+  /* count is variable but should be bound. */
+  assert (count < 128);
 
 #define TYPES								      \
   DO_TYPE (BYTE, Byte, "0x%.2" PRIx8, "%" PRId8);			      \
@@ -8379,11 +8381,16 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
   DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64);			      \
   DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64)
 
-#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name[count]
-  union { TYPES; } value;
+#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name
+  typedef union { TYPES; } value_t;
+  void *data = malloc (count * sizeof (value_t));
+#undef DO_TYPE
+
+#define DO_TYPE(NAME, Name, hex, dec) \
+    GElf_##Name *value_##Name __attribute__((unused)) = data
+  TYPES;
 #undef DO_TYPE
 
-  void *data = &value;
   size_t size = gelf_fsize (core, item->type, count, EV_CURRENT);
   size_t convsize = size;
   if (repeated_size != NULL)
@@ -8414,7 +8421,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
 	    colno = print_core_item (colno, ',', WRAP_COLUMN,		      \
-				     0, item->name, dec, value.Name[0]); \
+				     0, item->name, dec, value_##Name[0]); \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8430,7 +8437,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
 	    colno = print_core_item (colno, ',', WRAP_COLUMN,		      \
-				     0, item->name, hex, value.Name[0]);      \
+				     0, item->name, hex, value_##Name[0]);      \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8520,8 +8527,8 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 	{
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
-	    sec = value.Name[0];					      \
-	    usec = value.Name[1];					      \
+	    sec = value_##Name[0];					      \
+	    usec = value_##Name[1];					      \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8551,12 +8558,12 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
     case 'c':
       assert (count == 1);
       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
-			       "%c", value.Byte[0]);
+			       "%c", value_Byte[0]);
       break;
 
     case 's':
       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
-			       "%.*s", (int) count, value.Byte);
+			       "%.*s", (int) count, value_Byte);
       break;
 
     case '\n':
@@ -8597,6 +8604,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 
 #undef TYPES
 
+  free (data);
   return colno;
 }
 
diff --git a/src/unstrip.c b/src/unstrip.c
index 82bcdd8..97e002c 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -54,6 +54,10 @@
 # define _(str) gettext (str)
 #endif
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 /* Name and version of program.  */
 static void print_version (FILE *stream, struct argp_state *state);
 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
@@ -1013,13 +1017,13 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	error (EXIT_FAILURE, 0, _("invalid contents in '%s' section"),
 	       ".gnu.prelink_undo");
 
-      union
-      {
-	Elf32_Shdr s32[shnum - 1];
-	Elf64_Shdr s64[shnum - 1];
-      } shdr;
-      dst.d_buf = &shdr;
-      dst.d_size = sizeof shdr;
+      const size_t shdr_bytes =
+          (shnum - 1) * MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr));
+      void *shdr = xmalloc (shdr_bytes);
+      Elf32_Shdr *s32 = shdr;
+      Elf64_Shdr *s64 = shdr;
+      dst.d_buf = shdr;
+      dst.d_size = shdr_bytes;
       ELF_CHECK (gelf_xlatetom (main, &dst, &src,
 				main_ehdr->e_ident[EI_DATA]) != NULL,
 		 _("cannot read '.gnu.prelink_undo' section: %s"));
@@ -1030,7 +1034,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	  struct section *sec = &undo_sections[undo_nalloc];
 	  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
 	    {
-#define COPY(field) sec->shdr.field = shdr.s32[i].field
+#define COPY(field) sec->shdr.field = s32[i].field
 	      COPY (sh_name);
 	      COPY (sh_type);
 	      COPY (sh_flags);
@@ -1044,7 +1048,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 #undef	COPY
 	    }
 	  else
-	    sec->shdr = shdr.s64[i];
+	    sec->shdr = s64[i];
 	  if (sec->shdr.sh_flags & SHF_ALLOC)
 	    {
 	      sec->shdr.sh_addr += bias;
@@ -1057,6 +1061,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	}
       qsort (undo_sections, undo_nalloc,
 	     sizeof undo_sections[0], compare_sections_nonrel);
+      free (shdr);
     }
 
   bool fail = false;
-- 
2.6.0.rc0.131.gf624c3d


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-09-16 15:25 Mark Wielaard
  0 siblings, 0 replies; 34+ messages in thread
From: Mark Wielaard @ 2015-09-16 15:25 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 5381 bytes --]

On Fri, 2015-09-11 at 12:22 -0700, Roland McGrath wrote:
> It looks fine to me from a quick skim, but Mark should review and test it too.

I am not super enthusiastic about this change, it seems to just take
away type/size information that the compiler/bounds checking tools can
use.

That said I tested the patch under valgrind and with gcc
-fsanitize-undefined which didn't find any issues.

Some questions that might show how/why it could still be an improvement:

>     Do without union of variable length arrays.
>
>     Prepare to compile without gnu99 extension.

I think we still want to compile with several gnu99 extensions. Or is
your aim to build with -std=c99?

>     A union like
>       { T32 a32[n]; T64 a64[n]; } u;
>     is expanded to
>       void *data = malloc (...);
>       T32 *a32 = data;
>       T64 *a64 = data;

That might be useful since that prevents some possibly unbounded stack
usage. But most of the patch doesn't seem to be about that. Because such
unions are not allocated on the stack in the first place. There are a
couple of cases like the above, but there you replace them with an
alloca, which isn't much better.

> @@ -368,16 +372,15 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
>  
>    GElf_Addr undo_interp = 0;
>    {
> -    typedef union
> -    {
> -      Elf32_Phdr p32[phnum];
> -      Elf64_Phdr p64[phnum];
> -    } phdr;
> -    phdr *phdrs = malloc (sizeof (phdr));
> +    const int phdrs_bytes =
> +        phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+    void *phdrs = malloc (phdrs_bytes);
> +    Elf32_Phdr *p32 = phdrs;
> +    Elf64_Phdr *p64 = phdrs;
>      if (unlikely (phdrs == NULL))
>        return DWFL_E_NOMEM;

phdrs_bytes should be a size_t. And it needs a check that it didn't
overflow. I am assuming such an overflow check was done by the compiler
for the previous construct. But if not, then a change like this plus an
explicit overflow check would be an improvement.

The same pattern using an const int is used a couple of times.

> --- a/src/readelf.c
> +++ b/src/readelf.c
> @@ -4943,7 +4943,7 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp,
>                    unsigned int version, unsigned int ptr_size,
>                    Dwfl_Module *dwflmod, Ebl *ebl, Dwarf *dbg)
>  {
> -  char regnamebuf[REGNAMESZ];
> +  char *regnamebuf = alloca (REGNAMESZ);

REGNAMESZ is a constant (defined as 16), why replace with with an alloca?

> @@ -8379,11 +8379,16 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
>    DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64);                       \
>    DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64)
>  
> -#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name[count]
> -  union { TYPES; } value;
> +#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name
> +  typedef union { TYPES; } value_t;
> +  void *data = alloca (count * sizeof (value_t));
> +#undef DO_TYPE
> +
> +#define DO_TYPE(NAME, Name, hex, dec) \
> +    GElf_##Name *value_##Name __attribute__((unused)) = data
> +  TYPES;
>  #undef DO_TYPE

count is actually bounded, but that might not be easy to see.
We trust the backends to only provide sane Ebl_Core_Item's. The maximum
number of items I see is in the tilegx backends (which has an item with
count = 56). So this is fine, but maybe a we should add a comment
explaining it (or maybe add an assert (count < 128) or something to make
sure if this every accidentally gets violated we get an warning/error
early (and not silent stack corruption).

> @@ -8900,8 +8905,9 @@ handle_core_registers (Ebl *ebl, Elf *core, const void *desc,
>        assert (maxnreg > 0);
>      }
>  
> -  struct register_info regs[maxnreg];
> -  memset (regs, 0, sizeof regs);
> +  const int sizeof_regs = sizeof (struct register_info) * maxnreg;
> +  struct register_info *regs = alloca (sizeof_regs);
> +  memset (regs, 0, sizeof_regs);
>  
>    /* Sort to collect the sets together.  */
>    int maxreg = 0;

Same here. We count on ebl_register_info to return a (small) bounded number.

> @@ -1013,13 +1017,13 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
>         error (EXIT_FAILURE, 0, _("invalid contents in '%s' section"),
>                ".gnu.prelink_undo");
>  
> -      union
> -      {
> -       Elf32_Shdr s32[shnum - 1];
> -       Elf64_Shdr s64[shnum - 1];
> -      } shdr;
> -      dst.d_buf = &shdr;
> -      dst.d_size = sizeof shdr;
> +      const int shdr_bytes =
> +          (shnum - 1) * MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr));
> +      void *shdr = alloca (shdr_bytes);
> +      Elf32_Shdr *s32 = shdr;
> +      Elf64_Shdr *s64 = shdr;
> +      dst.d_buf = shdr;
> +      dst.d_size = shdr_bytes;

Here, and in copy_elided_sections there are real stack allocated
(possibly unbounded) variable length arrays. I think it makes sense to
actually use malloc/free instead of alloca. Otherwise you just keep the
problem. The reason this wasn't caught before is because this file isn't
build with -Wstack-usage. You don't have to make them -Wstack-usage
clean, but if you are replacing real VLAs anyway, then please don't
replace them with alloca if at all possible.

Thanks,

Mark

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-09-11 19:22 Roland McGrath
  0 siblings, 0 replies; 34+ messages in thread
From: Roland McGrath @ 2015-09-11 19:22 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 80 bytes --]

It looks fine to me from a quick skim, but Mark should review and test it too.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-09-08 23:15 Chih-Hung Hsieh
  0 siblings, 0 replies; 34+ messages in thread
From: Chih-Hung Hsieh @ 2015-09-08 23:15 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 532 bytes --]

The attached new 0002*patch file has ChangeLog files and uses MAX to
replace union types. Please take a look again.
Thanks.


On Tue, Sep 8, 2015 at 2:15 PM, Roland McGrath <roland@hack.frob.com> wrote:

> That looks generally OK, though it lacks ChangeLog entries.
> But I think it's a bit weird to declare those union types for
> the sole purpose of using sizeof on them.  I think it would
> be cleaner to replace e.g. sizeof (phdr_u) with:
>
> #define PHDR_MAX_SIZE MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr))
>

[-- Attachment #2: attachment.html --]
[-- Type: text/html, Size: 863 bytes --]

[-- Attachment #3: 0002-Do-without-union-of-variable-length-arrays.patch --]
[-- Type: application/octet-stream, Size: 27049 bytes --]

From a49ad4fb5eb87a7f0cce99654755fb62a9b67c8a Mon Sep 17 00:00:00 2001
From: Chih-Hung Hsieh <chh@google.com>
Date: Tue, 8 Sep 2015 11:53:16 -0700
Subject: [PATCH] Do without union of variable length arrays.

Prepare to compile without gnu99 extension.

A union like
  { T32 a32[n]; T64 a64[n]; } u;
is expanded to
  void *data = malloc (...);
  T32 *a32 = data;
  T64 *a64 = data;

Signed-off-by: Chih-Hung Hsieh <chh@google.com>
---
 libdwfl/ChangeLog                    | 10 +++++
 libdwfl/dwfl_module_getdwarf.c       | 50 +++++++++++-----------
 libdwfl/dwfl_segment_report_module.c | 66 ++++++++++++++---------------
 libdwfl/elf-from-memory.c            | 47 +++++++++++----------
 libdwfl/link_map.c                   | 81 +++++++++++++-----------------------
 libelf/ChangeLog                     |  5 +++
 libelf/elf_getarsym.c                | 12 ++----
 src/ChangeLog                        |  9 ++++
 src/readelf.c                        | 30 +++++++------
 src/unstrip.c                        | 25 ++++++-----
 10 files changed, 170 insertions(+), 165 deletions(-)

diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 3e36aa7..0b3af9f 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,13 @@
+2015-09-08  Chih-Hung Hsieh <chh@google.com>
+
+	* dwfl_module_getdwarf.c (find_prelink_address_sync): Do not use
+	union of variable length arrays.
+	* dwfl_segment_report_module.c (dwfl_segment_report_module): Likewise
+	* elf-from-memory.c (elf_from_remote_memory): Likewise
+	* link_map.c (auxv_format_probe): Likewise
+	* link_map.c (report_r_debug): Likewise
+	* link_map.c (dwfl_link_map_report): Likewise
+
 2015-08-14  Dodji Seketeli  <dodji@seketeli.org>
 
 	* find-debuginfo.c (find_debuginfo_in_path): Try to locate the
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index dba9d66..93afb76 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -34,6 +34,10 @@
 #include "../libdw/libdwP.h"	/* DWARF_E_* values are here.  */
 #include "../libelf/libelfP.h"
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 static inline Dwfl_Error
 open_elf_file (Elf **elf, int *fd, char **name)
 {
@@ -368,16 +372,15 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
 
   GElf_Addr undo_interp = 0;
   {
-    typedef union
-    {
-      Elf32_Phdr p32[phnum];
-      Elf64_Phdr p64[phnum];
-    } phdr;
-    phdr *phdrs = malloc (sizeof (phdr));
+    const int phdrs_bytes =
+        phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+    void *phdrs = malloc (phdrs_bytes);
+    Elf32_Phdr *p32 = phdrs;
+    Elf64_Phdr *p64 = phdrs;
     if (unlikely (phdrs == NULL))
       return DWFL_E_NOMEM;
     dst.d_buf = phdrs;
-    dst.d_size = sizeof (phdr);
+    dst.d_size = phdrs_bytes;
     if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
 				 ehdr.e32.e_ident[EI_DATA]) == NULL))
       {
@@ -387,18 +390,18 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
     if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
       {
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  if (phdrs->p32[i].p_type == PT_INTERP)
+	  if (p32[i].p_type == PT_INTERP)
 	    {
-	      undo_interp = phdrs->p32[i].p_vaddr;
+	      undo_interp = p32[i].p_vaddr;
 	      break;
 	    }
       }
     else
       {
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  if (phdrs->p64[i].p_type == PT_INTERP)
+	  if (p64[i].p_type == PT_INTERP)
 	    {
-	      undo_interp = phdrs->p64[i].p_vaddr;
+	      undo_interp = p64[i].p_vaddr;
 	      break;
 	    }
       }
@@ -412,16 +415,15 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
   src.d_type = ELF_T_SHDR;
   src.d_size = gelf_fsize (mod->main.elf, ELF_T_SHDR, shnum - 1, EV_CURRENT);
 
-  typedef union
-  {
-    Elf32_Shdr s32[shnum - 1];
-    Elf64_Shdr s64[shnum - 1];
-  } shdr;
-  shdr *shdrs = malloc (sizeof (shdr));
+  const int shdrs_bytes =
+      (shnum - 1) * MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr));
+  void *shdrs = malloc (shdrs_bytes);
+  Elf32_Shdr *s32 = shdrs;
+  Elf64_Shdr *s64 = shdrs;
   if (unlikely (shdrs == NULL))
     return DWFL_E_NOMEM;
   dst.d_buf = shdrs;
-  dst.d_size = sizeof (shdr);
+  dst.d_size = shdrs_bytes;
   if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
 			       ehdr.e32.e_ident[EI_DATA]) == NULL))
     {
@@ -484,14 +486,14 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
       highest = 0;
       if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
 	for (size_t i = 0; i < shnum - 1; ++i)
-	  consider_shdr (undo_interp, shdrs->s32[i].sh_type,
-			 shdrs->s32[i].sh_flags, shdrs->s32[i].sh_addr,
-			 shdrs->s32[i].sh_size);
+	  consider_shdr (undo_interp, s32[i].sh_type,
+			 s32[i].sh_flags, s32[i].sh_addr,
+			 s32[i].sh_size);
       else
 	for (size_t i = 0; i < shnum - 1; ++i)
-	  consider_shdr (undo_interp, shdrs->s64[i].sh_type,
-			 shdrs->s64[i].sh_flags, shdrs->s64[i].sh_addr,
-			 shdrs->s64[i].sh_size);
+	  consider_shdr (undo_interp, s64[i].sh_type,
+			 s64[i].sh_flags, s64[i].sh_addr,
+			 s64[i].sh_size);
 
       if (highest > file->vaddr)
 	file->address_sync = highest;
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index a0f07ad..43742ef 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -53,6 +53,10 @@
 # define MY_ELFDATA	ELFDATA2MSB
 #endif
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 
 /* Return user segment index closest to ADDR but not above it.
    If NEXT, return the closest to ADDR but not below it.  */
@@ -404,19 +408,16 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
   xlatefrom.d_buf = ph_buffer;
 
-  typedef union
-  {
-    Elf32_Phdr p32[phnum];
-    Elf64_Phdr p64[phnum];
-  } phdrsn;
-
-  phdrsp = malloc (sizeof (phdrsn));
+  const int phdrsp_bytes =
+      phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+  phdrsp = malloc (phdrsp_bytes);
+  Elf32_Phdr *p32 = phdrsp;
+  Elf64_Phdr *p64 = phdrsp;
   if (unlikely (phdrsp == NULL))
     return finish ();
-  phdrsn *phdrs = (phdrsn *) phdrsp;
 
-  xlateto.d_buf = phdrs;
-  xlateto.d_size = sizeof (phdrsn);
+  xlateto.d_buf = phdrsp;
+  xlateto.d_size = phdrsp_bytes;
 
   /* Track the bounds of the file visible in memory.  */
   GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end.  */
@@ -579,10 +580,10 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	found_bias = false;	/* Trigger error check.  */
       else
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  consider_phdr (phdrs->p32[i].p_type,
-			 phdrs->p32[i].p_vaddr, phdrs->p32[i].p_memsz,
-			 phdrs->p32[i].p_offset, phdrs->p32[i].p_filesz,
-			 phdrs->p32[i].p_align);
+	  consider_phdr (p32[i].p_type,
+			 p32[i].p_vaddr, p32[i].p_memsz,
+			 p32[i].p_offset, p32[i].p_filesz,
+			 p32[i].p_align);
     }
   else
     {
@@ -590,10 +591,10 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	found_bias = false;	/* Trigger error check.  */
       else
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  consider_phdr (phdrs->p64[i].p_type,
-			 phdrs->p64[i].p_vaddr, phdrs->p64[i].p_memsz,
-			 phdrs->p64[i].p_offset, phdrs->p64[i].p_filesz,
-			 phdrs->p64[i].p_align);
+	  consider_phdr (p64[i].p_type,
+			 p64[i].p_vaddr, p64[i].p_memsz,
+			 p64[i].p_offset, p64[i].p_filesz,
+			 p64[i].p_align);
     }
 
   finish_portion (&ph_buffer, &ph_buffer_size);
@@ -749,44 +750,39 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
   const size_t dyn_entsize = (ei_class == ELFCLASS32
 			      ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
-  void *dyns = NULL;
   void *dyn_data = NULL;
   size_t dyn_data_size = 0;
   if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
       && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz))
     {
-      typedef union
-      {
-	Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
-	Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
-      } dynn;
-      dyns = malloc (sizeof (dynn));
+      void *dyns = malloc (dyn_filesz);
+      Elf32_Dyn *d32 = dyns;
+      Elf64_Dyn *d64 = dyns;
       if (unlikely (dyns == NULL))
 	return finish ();
-      dynn *dyn = (dynn *) dyns;
 
       xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
       xlatefrom.d_buf = (void *) dyn_data;
       xlatefrom.d_size = dyn_filesz;
-      xlateto.d_buf = dyn;
-      xlateto.d_size = sizeof (dynn);
+      xlateto.d_buf = dyns;
+      xlateto.d_size = dyn_filesz;
 
       if (ei_class == ELFCLASS32)
 	{
 	  if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
 	    for (size_t i = 0; i < dyn_filesz / sizeof (Elf32_Dyn); ++i)
-	      if (consider_dyn (dyn->d32[i].d_tag, dyn->d32[i].d_un.d_val))
+	      if (consider_dyn (d32[i].d_tag, d32[i].d_un.d_val))
 		break;
 	}
       else
 	{
 	  if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
 	    for (size_t i = 0; i < dyn_filesz / sizeof (Elf64_Dyn); ++i)
-	      if (consider_dyn (dyn->d64[i].d_tag, dyn->d64[i].d_un.d_val))
+	      if (consider_dyn (d64[i].d_tag, d64[i].d_un.d_val))
 		break;
 	}
+      free (dyns);
     }
-  free (dyns);
   finish_portion (&dyn_data, &dyn_data_size);
 
   /* We'll use the name passed in or a stupid default if not DT_SONAME.  */
@@ -901,12 +897,12 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
 	  if (ei_class == ELFCLASS32)
 	    for (uint_fast16_t i = 0; i < phnum; ++i)
-	      read_phdr (phdrs->p32[i].p_type, phdrs->p32[i].p_vaddr,
-			 phdrs->p32[i].p_offset, phdrs->p32[i].p_filesz);
+	      read_phdr (p32[i].p_type, p32[i].p_vaddr,
+			 p32[i].p_offset, p32[i].p_filesz);
 	  else
 	    for (uint_fast16_t i = 0; i < phnum; ++i)
-	      read_phdr (phdrs->p64[i].p_type, phdrs->p64[i].p_vaddr,
-			 phdrs->p64[i].p_offset, phdrs->p64[i].p_filesz);
+	      read_phdr (p64[i].p_type, p64[i].p_vaddr,
+			 p64[i].p_offset, p64[i].p_filesz);
 	}
       else
 	{
diff --git a/libdwfl/elf-from-memory.c b/libdwfl/elf-from-memory.c
index ed8f6e9..47e743d 100644
--- a/libdwfl/elf-from-memory.c
+++ b/libdwfl/elf-from-memory.c
@@ -38,6 +38,10 @@
 #include <stdlib.h>
 #include <string.h>
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 /* Reconstruct an ELF file by reading the segments out of remote memory
    based on the ELF file header at EHDR_VMA and the ELF program headers it
    points to.  If not null, *LOADBASEP is filled in with the difference
@@ -191,22 +195,19 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
       xlatefrom.d_buf = buffer;
     }
 
-  typedef union
-  {
-    Elf32_Phdr p32[phnum];
-    Elf64_Phdr p64[phnum];
-  } phdrsn;
-
-  phdrsp = malloc (sizeof (phdrsn));
+  const int phdrsp_bytes =
+      phnum * MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr));
+  phdrsp = malloc (phdrsp_bytes);
+  Elf32_Phdr *p32 = phdrsp;
+  Elf64_Phdr *p64 = phdrsp;
   if (unlikely (phdrsp == NULL))
     {
       free (buffer);
       goto no_memory;
     }
-  phdrsn *phdrs = (phdrsn *) phdrsp;
 
-  xlateto.d_buf = phdrs;
-  xlateto.d_size = sizeof (phdrsn);
+  xlateto.d_buf = phdrsp;
+  xlateto.d_size = phdrsp_bytes;
 
   /* Scan for PT_LOAD segments to find the total size of the file image.  */
   size_t contents_size = 0;
@@ -249,9 +250,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 			  ehdr.e32.e_ident[EI_DATA]) == NULL)
 	goto libelf_error;
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p32[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset,
-			      phdrs->p32[i].p_filesz, phdrs->p32[i].p_memsz))
+	if (p32[i].p_type == PT_LOAD)
+	  if (handle_segment (p32[i].p_vaddr, p32[i].p_offset,
+			      p32[i].p_filesz, p32[i].p_memsz))
 	    goto bad_elf;
       break;
 
@@ -260,9 +261,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 			  ehdr.e64.e_ident[EI_DATA]) == NULL)
 	goto libelf_error;
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p64[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset,
-			      phdrs->p64[i].p_filesz, phdrs->p64[i].p_memsz))
+	if (p64[i].p_type == PT_LOAD)
+	  if (handle_segment (p64[i].p_vaddr, p64[i].p_offset,
+			      p64[i].p_filesz, p64[i].p_memsz))
 	    goto bad_elf;
       break;
 
@@ -315,9 +316,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 
     case ELFCLASS32:
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p32[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset,
-			      phdrs->p32[i].p_filesz))
+	if (p32[i].p_type == PT_LOAD)
+	  if (handle_segment (p32[i].p_vaddr, p32[i].p_offset,
+			      p32[i].p_filesz))
 	    goto read_error;
 
       /* If the segments visible in memory didn't include the section
@@ -342,9 +343,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 
     case ELFCLASS64:
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p64[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset,
-			      phdrs->p64[i].p_filesz))
+	if (p64[i].p_type == PT_LOAD)
+	  if (handle_segment (p64[i].p_vaddr, p64[i].p_offset,
+			      p64[i].p_filesz))
 	    goto read_error;
 
       /* If the segments visible in memory didn't include the section
@@ -373,7 +374,7 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
     }
 
   free (phdrsp);
-  phdrs = phdrsp = NULL;
+  phdrsp = NULL;
 
   /* Now we have the image.  Open libelf on it.  */
 
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index 030c600..a756e43 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -48,20 +48,16 @@ static bool
 auxv_format_probe (const void *auxv, size_t size,
 		   uint_fast8_t *elfclass, uint_fast8_t *elfdata)
 {
-  const union
-  {
-    char buf[size];
-    Elf32_auxv_t a32[size / sizeof (Elf32_auxv_t)];
-    Elf64_auxv_t a64[size / sizeof (Elf64_auxv_t)];
-  } *u = auxv;
+  const Elf32_auxv_t *a32 = auxv;
+  const Elf64_auxv_t *a64 = auxv;
 
   inline bool check64 (size_t i)
   {
     /* The AUXV pointer might not even be naturally aligned for 64-bit
        data, because note payloads in a core file are not aligned.  */
 
-    uint64_t type = read_8ubyte_unaligned_noncvt (&u->a64[i].a_type);
-    uint64_t val = read_8ubyte_unaligned_noncvt (&u->a64[i].a_un.a_val);
+    uint64_t type = read_8ubyte_unaligned_noncvt (&a64[i].a_type);
+    uint64_t val = read_8ubyte_unaligned_noncvt (&a64[i].a_un.a_val);
 
     if (type == BE64 (PROBE_TYPE)
 	&& val == BE64 (PROBE_VAL64))
@@ -85,8 +81,8 @@ auxv_format_probe (const void *auxv, size_t size,
     /* The AUXV pointer might not even be naturally aligned for 32-bit
        data, because note payloads in a core file are not aligned.  */
 
-    uint32_t type = read_4ubyte_unaligned_noncvt (&u->a32[i].a_type);
-    uint32_t val = read_4ubyte_unaligned_noncvt (&u->a32[i].a_un.a_val);
+    uint32_t type = read_4ubyte_unaligned_noncvt (&a32[i].a_type);
+    uint32_t val = read_4ubyte_unaligned_noncvt (&a32[i].a_un.a_val);
 
     if (type == BE32 (PROBE_TYPE)
 	&& val == BE32 (PROBE_VAL32))
@@ -280,29 +276,26 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
 	  return true;
       }
 
-    const union
-    {
-      Elf32_Addr a32[n];
-      Elf64_Addr a64[n];
-    } *in = vaddr - read_vaddr + buffer;
+    Elf32_Addr *a32 = vaddr - read_vaddr + buffer;
+    Elf64_Addr *a64 = (void *) a32;
 
     if (elfclass == ELFCLASS32)
       {
 	if (elfdata == ELFDATA2MSB)
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (&in->a32[i]));
+	    addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (&a32[i]));
 	else
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (&in->a32[i]));
+	    addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (&a32[i]));
       }
     else
       {
 	if (elfdata == ELFDATA2MSB)
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (&in->a64[i]));
+	    addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (&a64[i]));
 	else
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (&in->a64[i]));
+	    addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (&a64[i]));
       }
 
     return false;
@@ -861,13 +854,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	    }
 	  if (in_ok)
 	    {
-	      typedef union
-	      {
-		Elf32_Phdr p32;
-		Elf64_Phdr p64;
-		char data[phnum * phent];
-	      } data_buf;
-	      data_buf *buf = malloc (sizeof (data_buf));
+	      void *buf = malloc (phnum * phent);
+	      Elf32_Phdr *p32 = buf;
+	      Elf64_Phdr *p64 = buf;
 	      if (unlikely (buf == NULL))
 		{
 		  __libdwfl_seterrno (DWFL_E_NOMEM);
@@ -886,25 +875,20 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 			  (&out, &in, elfdata) != NULL))
 		{
 		  /* We are looking for PT_DYNAMIC.  */
-		  const union
-		  {
-		    Elf32_Phdr p32[phnum];
-		    Elf64_Phdr p64[phnum];
-		  } *u = (void *) buf;
 		  if (elfclass == ELFCLASS32)
 		    {
 		      for (size_t i = 0; i < phnum; ++i)
-			if (consider_phdr (u->p32[i].p_type,
-					   u->p32[i].p_vaddr,
-					   u->p32[i].p_filesz))
+			if (consider_phdr (p32[i].p_type,
+					   p32[i].p_vaddr,
+					   p32[i].p_filesz))
 			  break;
 		    }
 		  else
 		    {
 		      for (size_t i = 0; i < phnum; ++i)
-			if (consider_phdr (u->p64[i].p_type,
-					   u->p64[i].p_vaddr,
-					   u->p64[i].p_filesz))
+			if (consider_phdr (p64[i].p_type,
+					   p64[i].p_vaddr,
+					   p64[i].p_filesz))
 			  break;
 		    }
 		}
@@ -955,13 +939,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	  if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size,
 				  dyn_vaddr, dyn_filesz, memory_callback_arg))
 	    {
-	      typedef union
-	      {
-		Elf32_Dyn d32;
-		Elf64_Dyn d64;
-		char data[dyn_filesz];
-	      } data_buf;
-	      data_buf *buf = malloc (sizeof (data_buf));
+	      void *buf = malloc (dyn_filesz);
+	      Elf32_Dyn *d32 = buf;
+	      Elf64_Dyn *d64 = buf;
 	      if (unlikely (buf == NULL))
 		{
 		  __libdwfl_seterrno (DWFL_E_NOMEM);
@@ -980,18 +960,13 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 			  (&out, &in, elfdata) != NULL))
 		{
 		  /* We are looking for DT_DEBUG.  */
-		  const union
-		  {
-		    Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
-		    Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
-		  } *u = (void *) buf;
 		  if (elfclass == ELFCLASS32)
 		    {
 		      size_t n = dyn_filesz / sizeof (Elf32_Dyn);
 		      for (size_t i = 0; i < n; ++i)
-			if (u->d32[i].d_tag == DT_DEBUG)
+			if (d32[i].d_tag == DT_DEBUG)
 			  {
-			    r_debug_vaddr = u->d32[i].d_un.d_val;
+			    r_debug_vaddr = d32[i].d_un.d_val;
 			    break;
 			  }
 		    }
@@ -999,9 +974,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 		    {
 		      size_t n = dyn_filesz / sizeof (Elf64_Dyn);
 		      for (size_t i = 0; i < n; ++i)
-			if (u->d64[i].d_tag == DT_DEBUG)
+			if (d64[i].d_tag == DT_DEBUG)
 			  {
-			    r_debug_vaddr = u->d64[i].d_un.d_val;
+			    r_debug_vaddr = d64[i].d_un.d_val;
 			    break;
 			  }
 		    }
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index bb56e5b..a9685ba 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,8 @@
+2015-09-08  Chih-Hung Hsieh <chh@google.com>
+
+	* elf_getarsym.c (elf_getarsym): Do not use
+	union of variable length arrays.
+
 2015-06-18  Mark Wielaard  <mjw@redhat.com>
 
 	* elf32_updatefile.c (updatefile): Always free shdr_data and scns
diff --git a/libelf/elf_getarsym.c b/libelf/elf_getarsym.c
index 8324244..6f7bfab 100644
--- a/libelf/elf_getarsym.c
+++ b/libelf/elf_getarsym.c
@@ -203,11 +203,7 @@ elf_getarsym (elf, ptr)
       elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len);
       if (elf->state.ar.ar_sym != NULL)
 	{
-	  union
-	  {
-	    uint32_t u32[n];
-	    uint64_t u64[n];
-	  } *file_data;
+	  void *file_data; /* unit32_t[n] or uint64_t[n] */
 	  char *str_data;
 	  size_t sz = n * w;
 
@@ -274,7 +270,7 @@ elf_getarsym (elf, ptr)
 	      arsym[cnt].as_name = str_data;
 	      if (index64_p)
 		{
-		  uint64_t tmp = file_data->u64[cnt];
+		  uint64_t tmp = ((uint64_t *) file_data)[cnt];
 		  if (__BYTE_ORDER == __LITTLE_ENDIAN)
 		    tmp = bswap_64 (tmp);
 
@@ -296,9 +292,9 @@ elf_getarsym (elf, ptr)
 		    }
 		}
 	      else if (__BYTE_ORDER == __LITTLE_ENDIAN)
-		arsym[cnt].as_off = bswap_32 (file_data->u32[cnt]);
+		arsym[cnt].as_off = bswap_32 (((uint32_t *) file_data)[cnt]);
 	      else
-		arsym[cnt].as_off = file_data->u32[cnt];
+		arsym[cnt].as_off = ((uint32_t *) file_data)[cnt];
 
 	      arsym[cnt].as_hash = _dl_elf_hash (str_data);
 	      str_data = rawmemchr (str_data, '\0') + 1;
diff --git a/src/ChangeLog b/src/ChangeLog
index fb92807..1eb3b93 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,12 @@
+2015-09-08  Chih-Hung Hsieh <chh@google.com>
+
+	* readelf.c (print_cfa_program): Do not use
+	variable length arrays on stack or in union.
+	* readelf.c (handle_core_item): Likewise
+	* readelf.c (handle_core_registers): Likewise
+	* unstrip.c (find_alloc_sections_prelink): Likewise
+	* unstrip.c (copy_elided_sections): Likewise
+
 2015-09-04  Chih-Hung Hsieh  <chh@google.com>
 
 	* elflint.c (check_group): Replace %Z length modifier with %z.
diff --git a/src/readelf.c b/src/readelf.c
index 8e64400..6011ad7 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -4943,7 +4943,7 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp,
 		   unsigned int version, unsigned int ptr_size,
 		   Dwfl_Module *dwflmod, Ebl *ebl, Dwarf *dbg)
 {
-  char regnamebuf[REGNAMESZ];
+  char *regnamebuf = alloca (REGNAMESZ);
   const char *regname (unsigned int regno)
   {
     register_info (ebl, regno, NULL, regnamebuf, NULL, NULL);
@@ -8378,11 +8378,16 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
   DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64);			      \
   DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64)
 
-#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name[count]
-  union { TYPES; } value;
+#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name
+  typedef union { TYPES; } value_t;
+  void *data = alloca (count * sizeof (value_t));
+#undef DO_TYPE
+
+#define DO_TYPE(NAME, Name, hex, dec) \
+    GElf_##Name *value_##Name __attribute__((unused)) = data
+  TYPES;
 #undef DO_TYPE
 
-  void *data = &value;
   size_t size = gelf_fsize (core, item->type, count, EV_CURRENT);
   size_t convsize = size;
   if (repeated_size != NULL)
@@ -8413,7 +8418,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
 	    colno = print_core_item (colno, ',', WRAP_COLUMN,		      \
-				     0, item->name, dec, value.Name[0]); \
+				     0, item->name, dec, value_##Name[0]); \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8429,7 +8434,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
 	    colno = print_core_item (colno, ',', WRAP_COLUMN,		      \
-				     0, item->name, hex, value.Name[0]);      \
+				     0, item->name, hex, value_##Name[0]);      \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8519,8 +8524,8 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 	{
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
-	    sec = value.Name[0];					      \
-	    usec = value.Name[1];					      \
+	    sec = value_##Name[0];					      \
+	    usec = value_##Name[1];					      \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8550,12 +8555,12 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
     case 'c':
       assert (count == 1);
       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
-			       "%c", value.Byte[0]);
+			       "%c", value_Byte[0]);
       break;
 
     case 's':
       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
-			       "%.*s", (int) count, value.Byte);
+			       "%.*s", (int) count, value_Byte);
       break;
 
     case '\n':
@@ -8899,8 +8904,9 @@ handle_core_registers (Ebl *ebl, Elf *core, const void *desc,
       assert (maxnreg > 0);
     }
 
-  struct register_info regs[maxnreg];
-  memset (regs, 0, sizeof regs);
+  const int sizeof_regs = sizeof (struct register_info) * maxnreg;
+  struct register_info *regs = alloca (sizeof_regs);
+  memset (regs, 0, sizeof_regs);
 
   /* Sort to collect the sets together.  */
   int maxreg = 0;
diff --git a/src/unstrip.c b/src/unstrip.c
index 82bcdd8..a42aad6 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -54,6 +54,10 @@
 # define _(str) gettext (str)
 #endif
 
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
 /* Name and version of program.  */
 static void print_version (FILE *stream, struct argp_state *state);
 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
@@ -1013,13 +1017,13 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	error (EXIT_FAILURE, 0, _("invalid contents in '%s' section"),
 	       ".gnu.prelink_undo");
 
-      union
-      {
-	Elf32_Shdr s32[shnum - 1];
-	Elf64_Shdr s64[shnum - 1];
-      } shdr;
-      dst.d_buf = &shdr;
-      dst.d_size = sizeof shdr;
+      const int shdr_bytes =
+          (shnum - 1) * MAX (sizeof (Elf32_Shdr), sizeof (Elf64_Shdr));
+      void *shdr = alloca (shdr_bytes);
+      Elf32_Shdr *s32 = shdr;
+      Elf64_Shdr *s64 = shdr;
+      dst.d_buf = shdr;
+      dst.d_size = shdr_bytes;
       ELF_CHECK (gelf_xlatetom (main, &dst, &src,
 				main_ehdr->e_ident[EI_DATA]) != NULL,
 		 _("cannot read '.gnu.prelink_undo' section: %s"));
@@ -1030,7 +1034,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	  struct section *sec = &undo_sections[undo_nalloc];
 	  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
 	    {
-#define COPY(field) sec->shdr.field = shdr.s32[i].field
+#define COPY(field) sec->shdr.field = s32[i].field
 	      COPY (sh_name);
 	      COPY (sh_type);
 	      COPY (sh_flags);
@@ -1044,7 +1048,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 #undef	COPY
 	    }
 	  else
-	    sec->shdr = shdr.s64[i];
+	    sec->shdr = s64[i];
 	  if (sec->shdr.sh_flags & SHF_ALLOC)
 	    {
 	      sec->shdr.sh_addr += bias;
@@ -1260,7 +1264,8 @@ copy_elided_sections (Elf *unstripped, Elf *stripped,
 more sections in stripped file than debug file -- arguments reversed?"));
 
   /* Cache the stripped file's section details.  */
-  struct section sections[stripped_shnum - 1];
+  struct section *sections =
+      alloca (sizeof (struct section) * (stripped_shnum - 1));
   Elf_Scn *scn = NULL;
   while ((scn = elf_nextscn (stripped, scn)) != NULL)
     {
-- 
2.6.0.rc0.131.gf624c3d


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] Do without union of variable length arrays.
@ 2015-09-08 21:15 Roland McGrath
  0 siblings, 0 replies; 34+ messages in thread
From: Roland McGrath @ 2015-09-08 21:15 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 307 bytes --]

That looks generally OK, though it lacks ChangeLog entries.
But I think it's a bit weird to declare those union types for
the sole purpose of using sizeof on them.  I think it would
be cleaner to replace e.g. sizeof (phdr_u) with:

#define PHDR_MAX_SIZE MAX (sizeof (Elf32_Phdr), sizeof (Elf64_Phdr))

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH] Do without union of variable length arrays.
@ 2015-09-08 21:08 Chih-Hung Hsieh
  0 siblings, 0 replies; 34+ messages in thread
From: Chih-Hung Hsieh @ 2015-09-08 21:08 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 24413 bytes --]

Prepare to compile without gnu99 extension.

A union like
  { T32 a32[n]; T64 a64[n]; } u;
is expanded to
  void *data = malloc (...);
  T32 *a32 = data;
  T64 *a64 = data;

Signed-off-by: Chih-Hung Hsieh <chh@google.com>
---
 libdwfl/dwfl_module_getdwarf.c       | 46 +++++++++++---------
 libdwfl/dwfl_segment_report_module.c | 60 +++++++++++++-------------
 libdwfl/elf-from-memory.c            | 41 +++++++++---------
 libdwfl/link_map.c                   | 81 +++++++++++++-----------------------
 libelf/elf_getarsym.c                | 12 ++----
 src/readelf.c                        | 30 +++++++------
 src/unstrip.c                        | 22 ++++++----
 7 files changed, 138 insertions(+), 154 deletions(-)

diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index dba9d66..5f1b9b1 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -370,14 +370,17 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
   {
     typedef union
     {
-      Elf32_Phdr p32[phnum];
-      Elf64_Phdr p64[phnum];
-    } phdr;
-    phdr *phdrs = malloc (sizeof (phdr));
+      Elf32_Phdr p32;
+      Elf64_Phdr p64;
+    } phdr_u;
+    /* phnum elements of phdr_u */
+    void *phdrs = malloc (phnum * sizeof (phdr_u));
+    Elf32_Phdr *p32 = phdrs;
+    Elf64_Phdr *p64 = phdrs;
     if (unlikely (phdrs == NULL))
       return DWFL_E_NOMEM;
     dst.d_buf = phdrs;
-    dst.d_size = sizeof (phdr);
+    dst.d_size = phnum * sizeof (phdr_u);
     if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
 				 ehdr.e32.e_ident[EI_DATA]) == NULL))
       {
@@ -387,18 +390,18 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
     if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
       {
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  if (phdrs->p32[i].p_type == PT_INTERP)
+	  if (p32[i].p_type == PT_INTERP)
 	    {
-	      undo_interp = phdrs->p32[i].p_vaddr;
+	      undo_interp = p32[i].p_vaddr;
 	      break;
 	    }
       }
     else
       {
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  if (phdrs->p64[i].p_type == PT_INTERP)
+	  if (p64[i].p_type == PT_INTERP)
 	    {
-	      undo_interp = phdrs->p64[i].p_vaddr;
+	      undo_interp = p64[i].p_vaddr;
 	      break;
 	    }
       }
@@ -414,14 +417,17 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
 
   typedef union
   {
-    Elf32_Shdr s32[shnum - 1];
-    Elf64_Shdr s64[shnum - 1];
-  } shdr;
-  shdr *shdrs = malloc (sizeof (shdr));
+    Elf32_Shdr s32;
+    Elf64_Shdr s64;
+  } shdr_u;
+  /* (shnum - 1) elements of shdr_u */
+  void *shdrs = malloc ((shnum - 1) * sizeof (shdr_u));
+  Elf32_Shdr *s32 = shdrs;
+  Elf64_Shdr *s64 = shdrs;
   if (unlikely (shdrs == NULL))
     return DWFL_E_NOMEM;
   dst.d_buf = shdrs;
-  dst.d_size = sizeof (shdr);
+  dst.d_size = (shnum - 1) * sizeof (shdr_u);
   if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
 			       ehdr.e32.e_ident[EI_DATA]) == NULL))
     {
@@ -484,14 +490,14 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
       highest = 0;
       if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
 	for (size_t i = 0; i < shnum - 1; ++i)
-	  consider_shdr (undo_interp, shdrs->s32[i].sh_type,
-			 shdrs->s32[i].sh_flags, shdrs->s32[i].sh_addr,
-			 shdrs->s32[i].sh_size);
+	  consider_shdr (undo_interp, s32[i].sh_type,
+			 s32[i].sh_flags, s32[i].sh_addr,
+			 s32[i].sh_size);
       else
 	for (size_t i = 0; i < shnum - 1; ++i)
-	  consider_shdr (undo_interp, shdrs->s64[i].sh_type,
-			 shdrs->s64[i].sh_flags, shdrs->s64[i].sh_addr,
-			 shdrs->s64[i].sh_size);
+	  consider_shdr (undo_interp, s64[i].sh_type,
+			 s64[i].sh_flags, s64[i].sh_addr,
+			 s64[i].sh_size);
 
       if (highest > file->vaddr)
 	file->address_sync = highest;
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index a0f07ad..b5c45f3 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -406,17 +406,18 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
   typedef union
   {
-    Elf32_Phdr p32[phnum];
-    Elf64_Phdr p64[phnum];
-  } phdrsn;
+    Elf32_Phdr p32;
+    Elf64_Phdr p64;
+  } phdr_u;
 
-  phdrsp = malloc (sizeof (phdrsn));
+  phdrsp = malloc (phnum * sizeof (phdr_u));
+  Elf32_Phdr *p32 = phdrsp;
+  Elf64_Phdr *p64 = phdrsp;
   if (unlikely (phdrsp == NULL))
     return finish ();
-  phdrsn *phdrs = (phdrsn *) phdrsp;
 
-  xlateto.d_buf = phdrs;
-  xlateto.d_size = sizeof (phdrsn);
+  xlateto.d_buf = phdrsp;
+  xlateto.d_size = phnum * sizeof (phdr_u);
 
   /* Track the bounds of the file visible in memory.  */
   GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end.  */
@@ -579,10 +580,10 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	found_bias = false;	/* Trigger error check.  */
       else
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  consider_phdr (phdrs->p32[i].p_type,
-			 phdrs->p32[i].p_vaddr, phdrs->p32[i].p_memsz,
-			 phdrs->p32[i].p_offset, phdrs->p32[i].p_filesz,
-			 phdrs->p32[i].p_align);
+	  consider_phdr (p32[i].p_type,
+			 p32[i].p_vaddr, p32[i].p_memsz,
+			 p32[i].p_offset, p32[i].p_filesz,
+			 p32[i].p_align);
     }
   else
     {
@@ -590,10 +591,10 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	found_bias = false;	/* Trigger error check.  */
       else
 	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  consider_phdr (phdrs->p64[i].p_type,
-			 phdrs->p64[i].p_vaddr, phdrs->p64[i].p_memsz,
-			 phdrs->p64[i].p_offset, phdrs->p64[i].p_filesz,
-			 phdrs->p64[i].p_align);
+	  consider_phdr (p64[i].p_type,
+			 p64[i].p_vaddr, p64[i].p_memsz,
+			 p64[i].p_offset, p64[i].p_filesz,
+			 p64[i].p_align);
     }
 
   finish_portion (&ph_buffer, &ph_buffer_size);
@@ -749,44 +750,39 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
   const size_t dyn_entsize = (ei_class == ELFCLASS32
 			      ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
-  void *dyns = NULL;
   void *dyn_data = NULL;
   size_t dyn_data_size = 0;
   if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
       && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz))
     {
-      typedef union
-      {
-	Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
-	Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
-      } dynn;
-      dyns = malloc (sizeof (dynn));
+      void *dyns = malloc (dyn_filesz);
+      Elf32_Dyn *d32 = dyns;
+      Elf64_Dyn *d64 = dyns;
       if (unlikely (dyns == NULL))
 	return finish ();
-      dynn *dyn = (dynn *) dyns;
 
       xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
       xlatefrom.d_buf = (void *) dyn_data;
       xlatefrom.d_size = dyn_filesz;
-      xlateto.d_buf = dyn;
-      xlateto.d_size = sizeof (dynn);
+      xlateto.d_buf = dyns;
+      xlateto.d_size = dyn_filesz;
 
       if (ei_class == ELFCLASS32)
 	{
 	  if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
 	    for (size_t i = 0; i < dyn_filesz / sizeof (Elf32_Dyn); ++i)
-	      if (consider_dyn (dyn->d32[i].d_tag, dyn->d32[i].d_un.d_val))
+	      if (consider_dyn (d32[i].d_tag, d32[i].d_un.d_val))
 		break;
 	}
       else
 	{
 	  if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
 	    for (size_t i = 0; i < dyn_filesz / sizeof (Elf64_Dyn); ++i)
-	      if (consider_dyn (dyn->d64[i].d_tag, dyn->d64[i].d_un.d_val))
+	      if (consider_dyn (d64[i].d_tag, d64[i].d_un.d_val))
 		break;
 	}
+      free (dyns);
     }
-  free (dyns);
   finish_portion (&dyn_data, &dyn_data_size);
 
   /* We'll use the name passed in or a stupid default if not DT_SONAME.  */
@@ -901,12 +897,12 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 
 	  if (ei_class == ELFCLASS32)
 	    for (uint_fast16_t i = 0; i < phnum; ++i)
-	      read_phdr (phdrs->p32[i].p_type, phdrs->p32[i].p_vaddr,
-			 phdrs->p32[i].p_offset, phdrs->p32[i].p_filesz);
+	      read_phdr (p32[i].p_type, p32[i].p_vaddr,
+			 p32[i].p_offset, p32[i].p_filesz);
 	  else
 	    for (uint_fast16_t i = 0; i < phnum; ++i)
-	      read_phdr (phdrs->p64[i].p_type, phdrs->p64[i].p_vaddr,
-			 phdrs->p64[i].p_offset, phdrs->p64[i].p_filesz);
+	      read_phdr (p64[i].p_type, p64[i].p_vaddr,
+			 p64[i].p_offset, p64[i].p_filesz);
 	}
       else
 	{
diff --git a/libdwfl/elf-from-memory.c b/libdwfl/elf-from-memory.c
index ed8f6e9..ee37cfd 100644
--- a/libdwfl/elf-from-memory.c
+++ b/libdwfl/elf-from-memory.c
@@ -193,20 +193,21 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 
   typedef union
   {
-    Elf32_Phdr p32[phnum];
-    Elf64_Phdr p64[phnum];
-  } phdrsn;
+    Elf32_Phdr p32;
+    Elf64_Phdr p64;
+  } phdr_u;
 
-  phdrsp = malloc (sizeof (phdrsn));
+  phdrsp = malloc (phnum * sizeof (phdr_u));
+  Elf32_Phdr *p32 = phdrsp;
+  Elf64_Phdr *p64 = phdrsp;
   if (unlikely (phdrsp == NULL))
     {
       free (buffer);
       goto no_memory;
     }
-  phdrsn *phdrs = (phdrsn *) phdrsp;
 
-  xlateto.d_buf = phdrs;
-  xlateto.d_size = sizeof (phdrsn);
+  xlateto.d_buf = phdrsp;
+  xlateto.d_size = phnum * sizeof (phdr_u);
 
   /* Scan for PT_LOAD segments to find the total size of the file image.  */
   size_t contents_size = 0;
@@ -249,9 +250,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 			  ehdr.e32.e_ident[EI_DATA]) == NULL)
 	goto libelf_error;
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p32[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset,
-			      phdrs->p32[i].p_filesz, phdrs->p32[i].p_memsz))
+	if (p32[i].p_type == PT_LOAD)
+	  if (handle_segment (p32[i].p_vaddr, p32[i].p_offset,
+			      p32[i].p_filesz, p32[i].p_memsz))
 	    goto bad_elf;
       break;
 
@@ -260,9 +261,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 			  ehdr.e64.e_ident[EI_DATA]) == NULL)
 	goto libelf_error;
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p64[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset,
-			      phdrs->p64[i].p_filesz, phdrs->p64[i].p_memsz))
+	if (p64[i].p_type == PT_LOAD)
+	  if (handle_segment (p64[i].p_vaddr, p64[i].p_offset,
+			      p64[i].p_filesz, p64[i].p_memsz))
 	    goto bad_elf;
       break;
 
@@ -315,9 +316,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 
     case ELFCLASS32:
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p32[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset,
-			      phdrs->p32[i].p_filesz))
+	if (p32[i].p_type == PT_LOAD)
+	  if (handle_segment (p32[i].p_vaddr, p32[i].p_offset,
+			      p32[i].p_filesz))
 	    goto read_error;
 
       /* If the segments visible in memory didn't include the section
@@ -342,9 +343,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 
     case ELFCLASS64:
       for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdrs->p64[i].p_type == PT_LOAD)
-	  if (handle_segment (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset,
-			      phdrs->p64[i].p_filesz))
+	if (p64[i].p_type == PT_LOAD)
+	  if (handle_segment (p64[i].p_vaddr, p64[i].p_offset,
+			      p64[i].p_filesz))
 	    goto read_error;
 
       /* If the segments visible in memory didn't include the section
@@ -373,7 +374,7 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
     }
 
   free (phdrsp);
-  phdrs = phdrsp = NULL;
+  phdrsp = NULL;
 
   /* Now we have the image.  Open libelf on it.  */
 
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index 030c600..a756e43 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -48,20 +48,16 @@ static bool
 auxv_format_probe (const void *auxv, size_t size,
 		   uint_fast8_t *elfclass, uint_fast8_t *elfdata)
 {
-  const union
-  {
-    char buf[size];
-    Elf32_auxv_t a32[size / sizeof (Elf32_auxv_t)];
-    Elf64_auxv_t a64[size / sizeof (Elf64_auxv_t)];
-  } *u = auxv;
+  const Elf32_auxv_t *a32 = auxv;
+  const Elf64_auxv_t *a64 = auxv;
 
   inline bool check64 (size_t i)
   {
     /* The AUXV pointer might not even be naturally aligned for 64-bit
        data, because note payloads in a core file are not aligned.  */
 
-    uint64_t type = read_8ubyte_unaligned_noncvt (&u->a64[i].a_type);
-    uint64_t val = read_8ubyte_unaligned_noncvt (&u->a64[i].a_un.a_val);
+    uint64_t type = read_8ubyte_unaligned_noncvt (&a64[i].a_type);
+    uint64_t val = read_8ubyte_unaligned_noncvt (&a64[i].a_un.a_val);
 
     if (type == BE64 (PROBE_TYPE)
 	&& val == BE64 (PROBE_VAL64))
@@ -85,8 +81,8 @@ auxv_format_probe (const void *auxv, size_t size,
     /* The AUXV pointer might not even be naturally aligned for 32-bit
        data, because note payloads in a core file are not aligned.  */
 
-    uint32_t type = read_4ubyte_unaligned_noncvt (&u->a32[i].a_type);
-    uint32_t val = read_4ubyte_unaligned_noncvt (&u->a32[i].a_un.a_val);
+    uint32_t type = read_4ubyte_unaligned_noncvt (&a32[i].a_type);
+    uint32_t val = read_4ubyte_unaligned_noncvt (&a32[i].a_un.a_val);
 
     if (type == BE32 (PROBE_TYPE)
 	&& val == BE32 (PROBE_VAL32))
@@ -280,29 +276,26 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
 	  return true;
       }
 
-    const union
-    {
-      Elf32_Addr a32[n];
-      Elf64_Addr a64[n];
-    } *in = vaddr - read_vaddr + buffer;
+    Elf32_Addr *a32 = vaddr - read_vaddr + buffer;
+    Elf64_Addr *a64 = (void *) a32;
 
     if (elfclass == ELFCLASS32)
       {
 	if (elfdata == ELFDATA2MSB)
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (&in->a32[i]));
+	    addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (&a32[i]));
 	else
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (&in->a32[i]));
+	    addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (&a32[i]));
       }
     else
       {
 	if (elfdata == ELFDATA2MSB)
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (&in->a64[i]));
+	    addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (&a64[i]));
 	else
 	  for (size_t i = 0; i < n; ++i)
-	    addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (&in->a64[i]));
+	    addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (&a64[i]));
       }
 
     return false;
@@ -861,13 +854,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	    }
 	  if (in_ok)
 	    {
-	      typedef union
-	      {
-		Elf32_Phdr p32;
-		Elf64_Phdr p64;
-		char data[phnum * phent];
-	      } data_buf;
-	      data_buf *buf = malloc (sizeof (data_buf));
+	      void *buf = malloc (phnum * phent);
+	      Elf32_Phdr *p32 = buf;
+	      Elf64_Phdr *p64 = buf;
 	      if (unlikely (buf == NULL))
 		{
 		  __libdwfl_seterrno (DWFL_E_NOMEM);
@@ -886,25 +875,20 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 			  (&out, &in, elfdata) != NULL))
 		{
 		  /* We are looking for PT_DYNAMIC.  */
-		  const union
-		  {
-		    Elf32_Phdr p32[phnum];
-		    Elf64_Phdr p64[phnum];
-		  } *u = (void *) buf;
 		  if (elfclass == ELFCLASS32)
 		    {
 		      for (size_t i = 0; i < phnum; ++i)
-			if (consider_phdr (u->p32[i].p_type,
-					   u->p32[i].p_vaddr,
-					   u->p32[i].p_filesz))
+			if (consider_phdr (p32[i].p_type,
+					   p32[i].p_vaddr,
+					   p32[i].p_filesz))
 			  break;
 		    }
 		  else
 		    {
 		      for (size_t i = 0; i < phnum; ++i)
-			if (consider_phdr (u->p64[i].p_type,
-					   u->p64[i].p_vaddr,
-					   u->p64[i].p_filesz))
+			if (consider_phdr (p64[i].p_type,
+					   p64[i].p_vaddr,
+					   p64[i].p_filesz))
 			  break;
 		    }
 		}
@@ -955,13 +939,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	  if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size,
 				  dyn_vaddr, dyn_filesz, memory_callback_arg))
 	    {
-	      typedef union
-	      {
-		Elf32_Dyn d32;
-		Elf64_Dyn d64;
-		char data[dyn_filesz];
-	      } data_buf;
-	      data_buf *buf = malloc (sizeof (data_buf));
+	      void *buf = malloc (dyn_filesz);
+	      Elf32_Dyn *d32 = buf;
+	      Elf64_Dyn *d64 = buf;
 	      if (unlikely (buf == NULL))
 		{
 		  __libdwfl_seterrno (DWFL_E_NOMEM);
@@ -980,18 +960,13 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 			  (&out, &in, elfdata) != NULL))
 		{
 		  /* We are looking for DT_DEBUG.  */
-		  const union
-		  {
-		    Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
-		    Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
-		  } *u = (void *) buf;
 		  if (elfclass == ELFCLASS32)
 		    {
 		      size_t n = dyn_filesz / sizeof (Elf32_Dyn);
 		      for (size_t i = 0; i < n; ++i)
-			if (u->d32[i].d_tag == DT_DEBUG)
+			if (d32[i].d_tag == DT_DEBUG)
 			  {
-			    r_debug_vaddr = u->d32[i].d_un.d_val;
+			    r_debug_vaddr = d32[i].d_un.d_val;
 			    break;
 			  }
 		    }
@@ -999,9 +974,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 		    {
 		      size_t n = dyn_filesz / sizeof (Elf64_Dyn);
 		      for (size_t i = 0; i < n; ++i)
-			if (u->d64[i].d_tag == DT_DEBUG)
+			if (d64[i].d_tag == DT_DEBUG)
 			  {
-			    r_debug_vaddr = u->d64[i].d_un.d_val;
+			    r_debug_vaddr = d64[i].d_un.d_val;
 			    break;
 			  }
 		    }
diff --git a/libelf/elf_getarsym.c b/libelf/elf_getarsym.c
index 8324244..6f7bfab 100644
--- a/libelf/elf_getarsym.c
+++ b/libelf/elf_getarsym.c
@@ -203,11 +203,7 @@ elf_getarsym (elf, ptr)
       elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len);
       if (elf->state.ar.ar_sym != NULL)
 	{
-	  union
-	  {
-	    uint32_t u32[n];
-	    uint64_t u64[n];
-	  } *file_data;
+	  void *file_data; /* unit32_t[n] or uint64_t[n] */
 	  char *str_data;
 	  size_t sz = n * w;
 
@@ -274,7 +270,7 @@ elf_getarsym (elf, ptr)
 	      arsym[cnt].as_name = str_data;
 	      if (index64_p)
 		{
-		  uint64_t tmp = file_data->u64[cnt];
+		  uint64_t tmp = ((uint64_t *) file_data)[cnt];
 		  if (__BYTE_ORDER == __LITTLE_ENDIAN)
 		    tmp = bswap_64 (tmp);
 
@@ -296,9 +292,9 @@ elf_getarsym (elf, ptr)
 		    }
 		}
 	      else if (__BYTE_ORDER == __LITTLE_ENDIAN)
-		arsym[cnt].as_off = bswap_32 (file_data->u32[cnt]);
+		arsym[cnt].as_off = bswap_32 (((uint32_t *) file_data)[cnt]);
 	      else
-		arsym[cnt].as_off = file_data->u32[cnt];
+		arsym[cnt].as_off = ((uint32_t *) file_data)[cnt];
 
 	      arsym[cnt].as_hash = _dl_elf_hash (str_data);
 	      str_data = rawmemchr (str_data, '\0') + 1;
diff --git a/src/readelf.c b/src/readelf.c
index 8e64400..6011ad7 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -4943,7 +4943,7 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp,
 		   unsigned int version, unsigned int ptr_size,
 		   Dwfl_Module *dwflmod, Ebl *ebl, Dwarf *dbg)
 {
-  char regnamebuf[REGNAMESZ];
+  char *regnamebuf = alloca (REGNAMESZ);
   const char *regname (unsigned int regno)
   {
     register_info (ebl, regno, NULL, regnamebuf, NULL, NULL);
@@ -8378,11 +8378,16 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
   DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64);			      \
   DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64)
 
-#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name[count]
-  union { TYPES; } value;
+#define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name
+  typedef union { TYPES; } value_t;
+  void *data = alloca (count * sizeof (value_t));
+#undef DO_TYPE
+
+#define DO_TYPE(NAME, Name, hex, dec) \
+    GElf_##Name *value_##Name __attribute__((unused)) = data
+  TYPES;
 #undef DO_TYPE
 
-  void *data = &value;
   size_t size = gelf_fsize (core, item->type, count, EV_CURRENT);
   size_t convsize = size;
   if (repeated_size != NULL)
@@ -8413,7 +8418,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
 	    colno = print_core_item (colno, ',', WRAP_COLUMN,		      \
-				     0, item->name, dec, value.Name[0]); \
+				     0, item->name, dec, value_##Name[0]); \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8429,7 +8434,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
 	    colno = print_core_item (colno, ',', WRAP_COLUMN,		      \
-				     0, item->name, hex, value.Name[0]);      \
+				     0, item->name, hex, value_##Name[0]);      \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8519,8 +8524,8 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
 	{
 #define DO_TYPE(NAME, Name, hex, dec)					      \
 	  case ELF_T_##NAME:						      \
-	    sec = value.Name[0];					      \
-	    usec = value.Name[1];					      \
+	    sec = value_##Name[0];					      \
+	    usec = value_##Name[1];					      \
 	    break
 	  TYPES;
 #undef DO_TYPE
@@ -8550,12 +8555,12 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
     case 'c':
       assert (count == 1);
       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
-			       "%c", value.Byte[0]);
+			       "%c", value_Byte[0]);
       break;
 
     case 's':
       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
-			       "%.*s", (int) count, value.Byte);
+			       "%.*s", (int) count, value_Byte);
       break;
 
     case '\n':
@@ -8899,8 +8904,9 @@ handle_core_registers (Ebl *ebl, Elf *core, const void *desc,
       assert (maxnreg > 0);
     }
 
-  struct register_info regs[maxnreg];
-  memset (regs, 0, sizeof regs);
+  const int sizeof_regs = sizeof (struct register_info) * maxnreg;
+  struct register_info *regs = alloca (sizeof_regs);
+  memset (regs, 0, sizeof_regs);
 
   /* Sort to collect the sets together.  */
   int maxreg = 0;
diff --git a/src/unstrip.c b/src/unstrip.c
index 82bcdd8..7507eef 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -1013,13 +1013,16 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	error (EXIT_FAILURE, 0, _("invalid contents in '%s' section"),
 	       ".gnu.prelink_undo");
 
-      union
+      typedef union
       {
-	Elf32_Shdr s32[shnum - 1];
-	Elf64_Shdr s64[shnum - 1];
-      } shdr;
-      dst.d_buf = &shdr;
-      dst.d_size = sizeof shdr;
+	Elf32_Shdr s32;
+	Elf64_Shdr s64;
+      } shdr_u;
+      void *shdr = alloca ((shnum - 1) * sizeof (shdr_u));
+      Elf32_Shdr *s32 = shdr;
+      Elf64_Shdr *s64 = shdr;
+      dst.d_buf = shdr;
+      dst.d_size = (shnum - 1) * sizeof (shdr_u);
       ELF_CHECK (gelf_xlatetom (main, &dst, &src,
 				main_ehdr->e_ident[EI_DATA]) != NULL,
 		 _("cannot read '.gnu.prelink_undo' section: %s"));
@@ -1030,7 +1033,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 	  struct section *sec = &undo_sections[undo_nalloc];
 	  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
 	    {
-#define COPY(field) sec->shdr.field = shdr.s32[i].field
+#define COPY(field) sec->shdr.field = s32[i].field
 	      COPY (sh_name);
 	      COPY (sh_type);
 	      COPY (sh_flags);
@@ -1044,7 +1047,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
 #undef	COPY
 	    }
 	  else
-	    sec->shdr = shdr.s64[i];
+	    sec->shdr = s64[i];
 	  if (sec->shdr.sh_flags & SHF_ALLOC)
 	    {
 	      sec->shdr.sh_addr += bias;
@@ -1260,7 +1263,8 @@ copy_elided_sections (Elf *unstripped, Elf *stripped,
 more sections in stripped file than debug file -- arguments reversed?"));
 
   /* Cache the stripped file's section details.  */
-  struct section sections[stripped_shnum - 1];
+  struct section *sections =
+      alloca (sizeof (struct section) * (stripped_shnum - 1));
   Elf_Scn *scn = NULL;
   while ((scn = elf_nextscn (stripped, scn)) != NULL)
     {
-- 
2.5.0.457.gab17608


^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2015-10-27  8:30 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-07 22:24 [PATCH] Do without union of variable length arrays Mark Wielaard
  -- strict thread matches above, loose matches on Subject: below --
2015-10-27  8:30 Mark Wielaard
2015-10-26 20:00 Alexander Cherepanov
2015-10-08  7:04 Mark Wielaard
2015-10-07 23:46 Chih-Hung Hsieh
2015-10-07 22:45 Mark Wielaard
2015-10-07 22:35 Roland McGrath
2015-10-07 22:29 Mark Wielaard
2015-10-07 16:15 Chih-Hung Hsieh
2015-10-07 15:23 Mark Wielaard
2015-10-06 23:38 Alexander Cherepanov
2015-10-06 23:24 Alexander Cherepanov
2015-10-06 23:17 Chih-Hung Hsieh
2015-10-06 21:25 Mark Wielaard
2015-10-05 21:15 Chih-Hung Hsieh
2015-10-05 19:04 Chih-Hung Hsieh
2015-10-05 18:53 Mark Wielaard
2015-10-05 18:45 Mark Wielaard
2015-10-05 18:32 Mark Wielaard
2015-10-02 16:32 Alexander Cherepanov
2015-10-02 14:17 Florian Weimer
2015-10-01 23:01 Chih-Hung Hsieh
2015-10-01 21:10 Alexander Cherepanov
2015-10-01 20:45 Alexander Cherepanov
2015-10-01 19:04 Chih-Hung Hsieh
2015-10-01 17:22 Roland McGrath
2015-10-01  0:14 Chih-Hung Hsieh
2015-09-17  9:40 Mark Wielaard
2015-09-16 23:16 Chih-Hung Hsieh
2015-09-16 15:25 Mark Wielaard
2015-09-11 19:22 Roland McGrath
2015-09-08 23:15 Chih-Hung Hsieh
2015-09-08 21:15 Roland McGrath
2015-09-08 21:08 Chih-Hung Hsieh

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).