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

