Fix excessive memory allocation attempts and possible integer overfloaws when attempt...
[deliverable/binutils-gdb.git] / bfd / coffgen.c
index 481e4a5c91f690c9b3b26a20b4c6467319cd1af1..81efd9b372435370a02043c0cfcbdc4c70d22366 100644 (file)
@@ -1,5 +1,5 @@
 /* Support for the generic parts of COFF, for BFD.
-   Copyright (C) 1990-2015 Free Software Foundation, Inc.
+   Copyright (C) 1990-2017 Free Software Foundation, Inc.
    Written by Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -173,7 +173,8 @@ make_a_section_from_file (bfd *abfd,
        case compress:
          if (!bfd_init_section_compress_status (abfd, return_section))
            {
-             (*_bfd_error_handler)
+             _bfd_error_handler
+               /* xgettext: c-format */
                (_("%B: unable to initialize compress status for section %s"),
                 abfd, name);
              return FALSE;
@@ -196,7 +197,8 @@ make_a_section_from_file (bfd *abfd,
        case decompress:
          if (!bfd_init_section_decompress_status (abfd, return_section))
            {
-             (*_bfd_error_handler)
+             _bfd_error_handler
+               /* xgettext: c-format */
                (_("%B: unable to initialize decompress status for section %s"),
                 abfd, name);
              return FALSE;
@@ -1066,6 +1068,7 @@ bfd_boolean
 coff_write_alien_symbol (bfd *abfd,
                         asymbol *symbol,
                         struct internal_syment *isym,
+                        union internal_auxent *iaux,
                         bfd_vma *written,
                         bfd_size_type *string_size_p,
                         asection **debug_string_section_p,
@@ -1151,6 +1154,8 @@ coff_write_alien_symbol (bfd *abfd,
                           debug_string_section_p, debug_string_size_p);
   if (isym != NULL)
     *isym = native->u.syment;
+  if (iaux != NULL && native->u.syment.n_numaux)
+    *iaux = native[1].u.auxent;
   return ret;
 }
 
@@ -1215,7 +1220,8 @@ coff_write_native_symbol (bfd *abfd,
 }
 
 static void
-null_error_handler (const char * fmt ATTRIBUTE_UNUSED, ...)
+null_error_handler (const char *fmt ATTRIBUTE_UNUSED,
+                   va_list ap ATTRIBUTE_UNUSED)
 {
 }
 
@@ -1268,7 +1274,7 @@ coff_write_symbols (bfd *abfd)
       if (c_symbol == (coff_symbol_type *) NULL
          || c_symbol->native == (combined_entry_type *) NULL)
        {
-         if (!coff_write_alien_symbol (abfd, symbol, NULL, &written,
+         if (!coff_write_alien_symbol (abfd, symbol, NULL, NULL, &written,
                                        &string_size, &debug_string_section,
                                        &debug_string_size))
            return FALSE;
@@ -1381,7 +1387,7 @@ coff_write_symbols (bfd *abfd)
 
          else if (! c_symbol->native->is_sym)
            maxlen = bfd_coff_force_symnames_in_strings (abfd) ? 0 : SYMNMLEN;
-           
+
          else if (bfd_coff_symname_in_debug (abfd,
                                              &c_symbol->native->u.syment))
            /* This symbol name is in the XCOFF .debug section.
@@ -1634,10 +1640,25 @@ _bfd_coff_get_external_symbols (bfd *abfd)
   size = obj_raw_syment_count (abfd) * symesz;
   if (size == 0)
     return TRUE;
+  /* Check for integer overflow and for unreasonable symbol counts.  */
+  if (size < obj_raw_syment_count (abfd)
+      || (bfd_get_file_size (abfd) > 0
+         && size > bfd_get_file_size (abfd)))
+    
+    {
+      _bfd_error_handler (_("%B: corrupt symbol count: %#Lx"),
+                         abfd, obj_raw_syment_count (abfd));
+      return FALSE;
+    }
 
   syms = bfd_malloc (size);
   if (syms == NULL)
-    return FALSE;
+    {
+      /* PR 21013: Provide an error message when the alloc fails.  */
+      _bfd_error_handler (_("%B: not enough memory to allocate space for %#Lx symbols of size %#Lx"),
+                         abfd, obj_raw_syment_count (abfd), symesz);
+      return FALSE;
+    }
 
   if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0
       || bfd_bread (syms, size, abfd) != size)
@@ -1648,7 +1669,6 @@ _bfd_coff_get_external_symbols (bfd *abfd)
     }
 
   obj_coff_external_syms (abfd) = syms;
-
   return TRUE;
 }
 
@@ -1700,8 +1720,9 @@ _bfd_coff_read_string_table (bfd *abfd)
 
   if (strsize < STRING_SIZE_SIZE)
     {
-      (*_bfd_error_handler)
-       (_("%B: bad string table size %lu"), abfd, (unsigned long) strsize);
+      _bfd_error_handler
+       /* xgettext: c-format */
+       (_("%B: bad string table size %Lu"), abfd, strsize);
       bfd_set_error (bfd_error_bad_value);
       return NULL;
     }
@@ -1735,12 +1756,16 @@ _bfd_coff_read_string_table (bfd *abfd)
 bfd_boolean
 _bfd_coff_free_symbols (bfd *abfd)
 {
+  if (! bfd_family_coff (abfd))
+    return FALSE;
+
   if (obj_coff_external_syms (abfd) != NULL
       && ! obj_coff_keep_syms (abfd))
     {
       free (obj_coff_external_syms (abfd));
       obj_coff_external_syms (abfd) = NULL;
     }
+
   if (obj_coff_strings (abfd) != NULL
       && ! obj_coff_keep_strings (abfd))
     {
@@ -1748,6 +1773,7 @@ _bfd_coff_free_symbols (bfd *abfd)
       obj_coff_strings (abfd) = NULL;
       obj_coff_strings_len (abfd) = 0;
     }
+
   return TRUE;
 }
 
@@ -1778,11 +1804,14 @@ coff_get_normalized_symtab (bfd *abfd)
     return NULL;
 
   size = obj_raw_syment_count (abfd) * sizeof (combined_entry_type);
+  /* Check for integer overflow.  */
+  if (size < obj_raw_syment_count (abfd))
+    return NULL;
   internal = (combined_entry_type *) bfd_zalloc (abfd, size);
   if (internal == NULL && size != 0)
     return NULL;
   internal_end = internal + obj_raw_syment_count (abfd);
-  
+
   raw_src = (char *) obj_coff_external_syms (abfd);
 
   /* Mark the end of the symbols.  */
@@ -2130,7 +2159,7 @@ coff_print_symbol (bfd *abfd,
                                 auxp->u.auxent.x_scn.x_comdat);
                      break;
                    }
-                   /* Otherwise fall through.  */
+                 /* Fall through.  */
                case C_EXT:
                case C_AIX_WEAKEXT:
                  if (ISFCN (combined->u.syment.n_type))
@@ -2150,7 +2179,7 @@ coff_print_symbol (bfd *abfd,
                               llnos, next);
                      break;
                    }
-                 /* Otherwise fall through.  */
+                 /* Fall through.  */
                default:
                  fprintf (file, "AUX lnno %d size 0x%x tagndx %ld",
                           auxp->u.auxent.x_sym.x_misc.x_lnsz.x_lnno,
@@ -2247,6 +2276,8 @@ coff_find_nearest_line_with_names (bfd *abfd,
                                     &coff_data(abfd)->dwarf2_find_line_info))
     return TRUE;
 
+  sec_data = coff_section_data (abfd, section);
+
   /* If the DWARF lookup failed, but there is DWARF information available
      then the problem might be that the file has been rebased.  This tool
      changes the VMAs of all the sections, but it does not update the DWARF
@@ -2255,9 +2286,27 @@ coff_find_nearest_line_with_names (bfd *abfd,
     {
       bfd_signed_vma bias;
 
-      bias = _bfd_dwarf2_find_symbol_bias (symbols,
-                                          & coff_data (abfd)->dwarf2_find_line_info);
-      
+      /* Create a cache of the result for the next call.  */
+      if (sec_data == NULL && section->owner == abfd)
+       {
+         amt = sizeof (struct coff_section_tdata);
+         section->used_by_bfd = bfd_zalloc (abfd, amt);
+         sec_data = (struct coff_section_tdata *) section->used_by_bfd;
+       }
+
+      if (sec_data != NULL && sec_data->saved_bias)
+       bias = sec_data->saved_bias;
+      else
+       {
+         bias = _bfd_dwarf2_find_symbol_bias (symbols,
+                                              & coff_data (abfd)->dwarf2_find_line_info);
+         if (sec_data)
+           {
+             sec_data->saved_bias = TRUE;
+             sec_data->bias = bias;
+           }
+       }
+
       if (bias
          && _bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section,
                                            offset + bias,
@@ -2351,10 +2400,16 @@ coff_find_nearest_line_with_names (bfd *abfd,
        }
     }
 
-  /* Now wander though the raw linenumbers of the section.  */
-  /* If we have been called on this section before, and the offset we
-     want is further down then we can prime the lookup loop.  */
-  sec_data = coff_section_data (abfd, section);
+  if (section->lineno_count == 0)
+    {
+      *functionname_ptr = NULL;
+      *line_ptr = 0;
+      return TRUE;
+    }
+
+  /* Now wander though the raw linenumbers of the section.
+     If we have been called on this section before, and the offset
+     we want is further down then we can prime the lookup loop.  */
   if (sec_data != NULL
       && sec_data->i > 0
       && offset >= sec_data->offset)
@@ -2383,6 +2438,7 @@ coff_find_nearest_line_with_names (bfd *abfd,
              coff_symbol_type *coff = (coff_symbol_type *) (l->u.sym);
              if (coff->symbol.value > offset)
                break;
+
              *functionname_ptr = coff->symbol.name;
              last_value = coff->symbol.value;
              if (coff->native)
@@ -2439,6 +2495,7 @@ coff_find_nearest_line_with_names (bfd *abfd,
       section->used_by_bfd = bfd_zalloc (abfd, amt);
       sec_data = (struct coff_section_tdata *) section->used_by_bfd;
     }
+
   if (sec_data != NULL)
     {
       sec_data->offset = offset;
@@ -2486,7 +2543,7 @@ coff_sizeof_headers (bfd *abfd, struct bfd_link_info *info)
 {
   size_t size;
 
-  if (!info->relocatable)
+  if (!bfd_link_relocatable (info))
     size = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd);
   else
     size = bfd_coff_filhsz (abfd);
@@ -2688,7 +2745,13 @@ static void
 fini_reloc_cookie_rels (struct coff_reloc_cookie *cookie,
                        asection *sec)
 {
-  if (cookie->rels && coff_section_data (NULL, sec)->relocs != cookie->rels)
+  if (cookie->rels
+      /* PR 20401.  The relocs may not have been cached, so check first.
+        If the relocs were loaded by init_reloc_cookie_rels() then this
+        will be the case.  FIXME: Would performance be improved if the
+        relocs *were* cached ?  */
+      && coff_section_data (NULL, sec)
+      && coff_section_data (NULL, sec)->relocs != cookie->rels)
     free (cookie->rels);
 }
 
@@ -2739,8 +2802,22 @@ _bfd_coff_gc_mark_hook (asection *sec,
         case bfd_link_hash_common:
           return h->root.u.c.p->section;
 
-       case bfd_link_hash_undefined:
        case bfd_link_hash_undefweak:
+         if (h->symbol_class == C_NT_WEAK && h->numaux == 1)
+           {
+             /* PE weak externals.  A weak symbol may include an auxiliary
+                record indicating that if the weak symbol is not resolved,
+                another external symbol is used instead.  */
+             struct coff_link_hash_entry *h2 =
+               h->auxbfd->tdata.coff_obj_data->sym_hashes[
+                   h->aux->x_sym.x_tagndx.l];
+
+             if (h2 && h2->root.type != bfd_link_hash_undefined)
+               return  h2->root.u.def.section;
+           }
+         break;
+
+       case bfd_link_hash_undefined:
         default:
           break;
         }
@@ -2851,7 +2928,7 @@ _bfd_coff_gc_mark_extra_sections (struct bfd_link_info *info,
       asection *isec;
       bfd_boolean some_kept;
 
-      if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+      if (bfd_get_flavour (ibfd) != bfd_target_coff_flavour)
        continue;
 
       /* Ensure all linker created sections are kept, and see whether
@@ -2943,7 +3020,9 @@ coff_gc_sweep (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
          o->flags |= SEC_EXCLUDE;
 
          if (info->print_gc_sections && o->size != 0)
-            _bfd_error_handler (_("Removing unused section '%s' in file '%B'"), sub, o->name);
+           /* xgettext: c-format */
+           _bfd_error_handler (_("Removing unused section '%A' in file '%B'"),
+                               o, sub);
 
 #if 0
          /* But we also have to update some of the relocation
@@ -3019,7 +3098,7 @@ bfd_coff_gc_sections (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
   if (!bed->can_gc_sections
       || !is_coff_hash_table (info->hash))
     {
-      (*_bfd_error_handler)(_("Warning: gc-sections option ignored"));
+      _bfd_error_handler(_("Warning: gc-sections option ignored"));
       return TRUE;
     }
 #endif
This page took 0.036299 seconds and 4 git commands to generate.