+2020-02-19  Alan Modra  <amodra@gmail.com>
+
+       * aoutx.h (slurp_reloc_table): Allocate reloc_cache after
+       reading external relocs.
+       * ecoff.c (ecoff_slurp_reloc_table): Likewise.
+       * archive.c (_bfd_write_archive_contents): Don't twiddle bfd_error
+       after bfd_bread.
+       * archive64.c (_bfd_archive_64_bit_slurp_armap): Remove unnecessary
+       bfd_release.
+       * elf32-m32c.c (m32c_offset_for_reloc): Make shndx_buf a bfd_byte*.
+       (m32c_elf_relax_section): Likewise.
+       * elf32-rl78.c (rl78_offset_for_reloc): Likewise.
+       (rl78_elf_relax_section): Likewise.
+       * elf32-rx.c (rx_offset_for_reloc): Likewise.
+       (elf32_rx_relax_section): Likewise.
+       * mach-o.c (bfd_mach_o_alloc_and_read): Move earlier with better
+       parameter types and use..
+       (bfd_mach_o_read_dylinker, bfd_mach_o_read_dylib),
+       (bfd_mach_o_read_fvmlib, bfd_mach_o_read_str): ..in these functions.
+       * peicode.h (pe_bfd_object_p): Don't zero the part of opthdr
+       being read from file, just the extra.
+       * som.c (som_slurp_symbol_table): Allocate internal symbol buffer
+       after reading external syms.  Free on failure.
+
 2020-02-19  Alan Modra  <amodra@gmail.com>
 
        * coffcode.h (buy_and_read, coff_slurp_line_table),
 
       return FALSE;
     }
 
-  if (reloc_size == 0)
-    return TRUE;               /* Nothing to be done.  */
-
-  if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0)
-    return FALSE;
-
   each_size = obj_reloc_entry_size (abfd);
-
   count = reloc_size / each_size;
   if (count == 0)
     return TRUE;               /* Nothing to be done.  */
 
-  amt = count * sizeof (arelent);
-  reloc_cache = (arelent *) bfd_zmalloc (amt);
-  if (reloc_cache == NULL)
+  if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0)
     return FALSE;
 
   relocs = bfd_malloc (reloc_size);
   if (relocs == NULL)
+    return FALSE;
+
+  if (bfd_bread (relocs, reloc_size, abfd) != reloc_size)
     {
-      free (reloc_cache);
+      free (relocs);
       return FALSE;
     }
 
-  if (bfd_bread (relocs, reloc_size, abfd) != reloc_size)
+  amt = count * sizeof (arelent);
+  reloc_cache = (arelent *) bfd_zmalloc (amt);
+  if (reloc_cache == NULL)
     {
       free (relocs);
-      free (reloc_cache);
       return FALSE;
     }
 
 
            amt = remaining;
          errno = 0;
          if (bfd_bread (buffer, amt, current) != amt)
-           {
-             if (bfd_get_error () != bfd_error_system_call)
-               bfd_set_error (bfd_error_file_truncated);
-             goto input_err;
-           }
+           goto input_err;
          if (bfd_bwrite (buffer, amt, arch) != amt)
            return FALSE;
          remaining -= amt;
 
     {
       if (bfd_get_error () != bfd_error_system_call)
        bfd_set_error (bfd_error_malformed_archive);
-      goto release_raw_armap;
+      goto release_symdefs;
     }
 
   stringend = stringbase + stringsize;
 
   return TRUE;
 
-release_raw_armap:
-  bfd_release (abfd, raw_armap);
 release_symdefs:
   bfd_release (abfd, ardata->symdefs);
   return FALSE;
 
   if (! _bfd_ecoff_slurp_symbol_table (abfd))
     return FALSE;
 
-  amt = section->reloc_count;
-  amt *= sizeof (arelent);
-  internal_relocs = (arelent *) bfd_alloc (abfd, amt);
-
   external_reloc_size = backend->external_reloc_size;
   amt = external_reloc_size * section->reloc_count;
   external_relocs = (char *) bfd_alloc (abfd, amt);
-  if (internal_relocs == NULL || external_relocs == NULL)
+  if (external_relocs == NULL)
     return FALSE;
   if (bfd_seek (abfd, section->rel_filepos, SEEK_SET) != 0)
     return FALSE;
   if (bfd_bread (external_relocs, amt, abfd) != amt)
     return FALSE;
 
+  amt = section->reloc_count;
+  amt *= sizeof (arelent);
+  internal_relocs = (arelent *) bfd_alloc (abfd, amt);
+  if (internal_relocs == NULL)
+    {
+      bfd_release (abfd, external_relocs);
+      return FALSE;
+    }
+
   for (i = 0, rptr = internal_relocs; i < section->reloc_count; i++, rptr++)
     {
       struct internal_reloc intern;
 
 m32c_offset_for_reloc (bfd *abfd,
                       Elf_Internal_Rela *rel,
                       Elf_Internal_Shdr *symtab_hdr,
-                      Elf_External_Sym_Shndx *shndx_buf ATTRIBUTE_UNUSED,
+                      bfd_byte *shndx_buf ATTRIBUTE_UNUSED,
                       Elf_Internal_Sym *intsyms)
 {
   bfd_vma symval;
   bfd_byte * free_contents = NULL;
   Elf_Internal_Sym *intsyms = NULL;
   Elf_Internal_Sym *free_intsyms = NULL;
-  Elf_External_Sym_Shndx *shndx_buf = NULL;
+  bfd_byte *shndx_buf = NULL;
   int machine;
 
   if (abfd == elf_hash_table (link_info)->dynobj
          bfd_set_error (bfd_error_file_too_big);
          goto error_return;
        }
-      shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+      shndx_buf = bfd_malloc (amt);
       if (shndx_buf == NULL)
        goto error_return;
       if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
          || bfd_bread (shndx_buf, amt, abfd) != amt)
        goto error_return;
-      shndx_hdr->contents = (bfd_byte *) shndx_buf;
+      shndx_hdr->contents = shndx_buf;
     }
 
   /* Get a copy of the native relocations.  */
 
 rl78_offset_for_reloc (bfd *                   abfd,
                       Elf_Internal_Rela *      rel,
                       Elf_Internal_Shdr *      symtab_hdr,
-                      Elf_External_Sym_Shndx * shndx_buf ATTRIBUTE_UNUSED,
+                      bfd_byte *               shndx_buf ATTRIBUTE_UNUSED,
                       Elf_Internal_Sym *       intsyms,
                       Elf_Internal_Rela **     lrel,
                       bfd *                    input_bfd,
   bfd_byte *         free_contents = NULL;
   Elf_Internal_Sym *  intsyms = NULL;
   Elf_Internal_Sym *  free_intsyms = NULL;
-  Elf_External_Sym_Shndx * shndx_buf = NULL;
+  bfd_byte *         shndx_buf = NULL;
   bfd_vma pc;
   bfd_vma symval ATTRIBUTE_UNUSED = 0;
   int pcrel ATTRIBUTE_UNUSED = 0;
          bfd_set_error (bfd_error_no_memory);
          goto error_return;
        }
-      shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+      shndx_buf = bfd_malloc (amt);
       if (shndx_buf == NULL)
        goto error_return;
       if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
          || bfd_bread (shndx_buf, amt, abfd) != amt)
        goto error_return;
-      shndx_hdr->contents = (bfd_byte *) shndx_buf;
+      shndx_hdr->contents = shndx_buf;
     }
 
   /* Get a copy of the native relocations.  */
 
 rx_offset_for_reloc (bfd *                   abfd,
                     Elf_Internal_Rela *      rel,
                     Elf_Internal_Shdr *      symtab_hdr,
-                    Elf_External_Sym_Shndx * shndx_buf ATTRIBUTE_UNUSED,
+                    bfd_byte *               shndx_buf ATTRIBUTE_UNUSED,
                     Elf_Internal_Sym *       intsyms,
                     Elf_Internal_Rela **     lrel,
                     bfd *                    input_bfd,
   bfd_byte *         free_contents = NULL;
   Elf_Internal_Sym *  intsyms = NULL;
   Elf_Internal_Sym *  free_intsyms = NULL;
-  Elf_External_Sym_Shndx * shndx_buf = NULL;
+  bfd_byte *         shndx_buf = NULL;
   bfd_vma pc;
   bfd_vma sec_start;
   bfd_vma symval = 0;
          bfd_set_error (bfd_error_file_too_big);
          goto error_return;
        }
-      shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+      shndx_buf = bfd_malloc (amt);
       if (shndx_buf == NULL)
        goto error_return;
       if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
          || bfd_bread (shndx_buf, amt, abfd) != amt)
        goto error_return;
-      shndx_hdr->contents = (bfd_byte *) shndx_buf;
+      shndx_hdr->contents = shndx_buf;
     }
 
   /* Get a copy of the native relocations.  */
 
     }
 }
 
+static unsigned char *
+bfd_mach_o_alloc_and_read (bfd *abfd, file_ptr filepos, size_t size)
+{
+  unsigned char *buf;
+
+  buf = bfd_alloc (abfd, size);
+  if (buf == NULL)
+    return NULL;
+  if (bfd_seek (abfd, filepos, SEEK_SET) != 0
+      || bfd_bread (buf, size, abfd) != size)
+    return NULL;
+  return buf;
+}
+
 static bfd_boolean
 bfd_mach_o_read_dylinker (bfd *abfd, bfd_mach_o_load_command *command)
 {
   cmd->name_offset = nameoff;
   namelen = command->len - nameoff;
   nameoff += command->offset;
-  cmd->name_str = bfd_alloc (abfd, namelen);
-  if (cmd->name_str == NULL)
-    return FALSE;
-  if (bfd_seek (abfd, nameoff, SEEK_SET) != 0
-      || bfd_bread (cmd->name_str, namelen, abfd) != namelen)
-    return FALSE;
-  return TRUE;
+  cmd->name_str = (char *) bfd_mach_o_alloc_and_read (abfd, nameoff, namelen);
+  return cmd->name_str != NULL;
 }
 
 static bfd_boolean
   struct mach_o_dylib_command_external raw;
   unsigned int nameoff;
   unsigned int namelen;
+  file_ptr pos;
 
   if (command->len < sizeof (raw) + 8)
     return FALSE;
 
   cmd->name_offset = command->offset + nameoff;
   namelen = command->len - nameoff;
-  cmd->name_str = bfd_alloc (abfd, namelen);
-  if (cmd->name_str == NULL)
-    return FALSE;
-  if (bfd_seek (abfd, mdata->hdr_offset + cmd->name_offset, SEEK_SET) != 0
-      || bfd_bread (cmd->name_str, namelen, abfd) != namelen)
-    return FALSE;
-  return TRUE;
+  pos = mdata->hdr_offset + cmd->name_offset;
+  cmd->name_str = (char *) bfd_mach_o_alloc_and_read (abfd, pos, namelen);
+  return cmd->name_str != NULL;
 }
 
 static bfd_boolean
 
   fvm->name_offset = command->offset + nameoff;
   namelen = command->len - nameoff;
-  fvm->name_str = bfd_alloc (abfd, namelen);
-  if (fvm->name_str == NULL)
-    return FALSE;
-  if (bfd_seek (abfd, fvm->name_offset, SEEK_SET) != 0
-      || bfd_bread (fvm->name_str, namelen, abfd) != namelen)
-    return FALSE;
-  return TRUE;
+  fvm->name_str = (char *) bfd_mach_o_alloc_and_read (abfd, fvm->name_offset,
+                                                     namelen);
+  return fvm->name_str != NULL;
 }
 
 static bfd_boolean
 
   cmd->stroff = command->offset + off;
   cmd->str_len = command->len - off;
-  cmd->str = bfd_alloc (abfd, cmd->str_len);
-  if (cmd->str == NULL)
-    return FALSE;
-  if (bfd_seek (abfd, cmd->stroff, SEEK_SET) != 0
-      || bfd_bread ((void *) cmd->str, cmd->str_len, abfd) != cmd->str_len)
-    return FALSE;
-  return TRUE;
-}
-
-static unsigned char *
-bfd_mach_o_alloc_and_read (bfd *abfd, unsigned int off, unsigned int size)
-{
-  unsigned char *buf;
-
-  buf = bfd_alloc (abfd, size);
-  if (buf == NULL)
-    return NULL;
-  if (bfd_seek (abfd, off, SEEK_SET) != 0
-      || bfd_bread (buf, size, abfd) != size)
-    return NULL;
-  return buf;
+  cmd->str = (char *) bfd_mach_o_alloc_and_read (abfd, cmd->stroff,
+                                                cmd->str_len);
+  return cmd->str != NULL;
 }
 
 static bfd_boolean
 
   struct external_PEI_IMAGE_hdr image_hdr;
   struct internal_filehdr internal_f;
   struct internal_aouthdr internal_a;
-  file_ptr opt_hdr_size;
+  bfd_size_type opt_hdr_size;
   file_ptr offset;
   const bfd_target *result;
 
       if (amt < sizeof (PEAOUTHDR))
        amt = sizeof (PEAOUTHDR);
 
-      opthdr = bfd_zalloc (abfd, amt);
+      opthdr = bfd_alloc (abfd, amt);
       if (opthdr == NULL)
        return NULL;
       if (bfd_bread (opthdr, opt_hdr_size, abfd)
          != (bfd_size_type) opt_hdr_size)
        return NULL;
+      if (amt > opt_hdr_size)
+       memset (opthdr + opt_hdr_size, 0, amt - opt_hdr_size);
 
       bfd_set_error (bfd_error_no_error);
       bfd_coff_swap_aouthdr_in (abfd, opthdr, & internal_a);
 
   size_t symsize = sizeof (struct som_external_symbol_dictionary_record);
   char *stringtab;
   struct som_external_symbol_dictionary_record *buf = NULL, *bufp, *endbufp;
-  som_symbol_type *sym, *symbase;
+  som_symbol_type *sym, *symbase = NULL;
   size_t amt;
 
   /* Return saved value if it exists.  */
 
   stringtab = obj_som_stringtab (abfd);
 
-  if (_bfd_mul_overflow (symbol_count, sizeof (som_symbol_type), &amt))
-    {
-      bfd_set_error (bfd_error_file_too_big);
-      goto error_return;
-    }
-  symbase = bfd_zmalloc (amt);
-  if (symbase == NULL)
-    goto error_return;
-
   /* Read in the external SOM representation.  */
   if (_bfd_mul_overflow (symbol_count, symsize, &amt))
     {
   if (bfd_bread (buf, amt, abfd) != amt)
     goto error_return;
 
+  if (_bfd_mul_overflow (symbol_count, sizeof (som_symbol_type), &amt))
+    {
+      bfd_set_error (bfd_error_file_too_big);
+      goto error_return;
+    }
+  symbase = bfd_zmalloc (amt);
+  if (symbase == NULL)
+    goto error_return;
+
   /* Iterate over all the symbols and internalize them.  */
   endbufp = buf + symbol_count;
   for (bufp = buf, sym = symbase; bufp < endbufp; ++bufp)
   return (TRUE);
 
  error_return:
+  if (symbase != NULL)
+    free (symbase);
   if (buf != NULL)
     free (buf);
   return FALSE;