windres: don't exit so much on errors in read_coff_rsrc

Message ID Z_zeeykJ1tjFXbCB@squeak.grove.modra.org
State New
Headers
Series windres: don't exit so much on errors in read_coff_rsrc |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 fail Patch failed to apply
linaro-tcwg-bot/tcwg_binutils_build--master-arm fail Patch failed to apply

Commit Message

Alan Modra April 14, 2025, 10:07 a.m. UTC
  windres code has the habit of exiting on any error.  That's not so
bad, but it does make oss-fuzz ineffective when testing windres.  Fix
many places that print errors and exit to instead print the error and
pass status up the call chain.  In the process of doing this, I
noticed write_res_file was calling bfd_close without checking return
status.  Fixing that resulted in lots of testsuite failures..  The
problem was a lack of bfd_set_format in windres_open_as_binary, which
leaves the output file as bfd_unknown format.  As it happens this
doesn't make any difference in writing the output binary file, except
for the bfd_close return status.
  

Patch

diff --git a/binutils/resbin.c b/binutils/resbin.c
index a42a846d94b..1698e144d50 100644
--- a/binutils/resbin.c
+++ b/binutils/resbin.c
@@ -55,7 +55,7 @@  static rc_res_resource *bin_to_res_group_icon (windres_bfd *, const bfd_byte *,
 static rc_res_resource *bin_to_res_version (windres_bfd *, const bfd_byte *, rc_uint_type);
 static rc_res_resource *bin_to_res_userdata (windres_bfd *, const bfd_byte *, rc_uint_type);
 static rc_res_resource *bin_to_res_toolbar (windres_bfd *, const bfd_byte *, rc_uint_type);
-static void get_version_header (windres_bfd *, const bfd_byte *, rc_uint_type, const char *,
+static bool get_version_header (windres_bfd *, const bfd_byte *, rc_uint_type, const char *,
 				unichar **, rc_uint_type *, rc_uint_type *, rc_uint_type *,
 				rc_uint_type *);
 
@@ -116,7 +116,7 @@  bin_to_res (windres_bfd *wrbfd, rc_res_id type, const bfd_byte *data,
 static void
 toosmall (const char *msg)
 {
-  fatal (_("%s: not enough binary data"), msg);
+  non_fatal (_("%s: not enough binary data"), msg);
 }
 
 /* Swap in a NULL terminated unicode string.  */
@@ -132,7 +132,10 @@  get_unicode (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
   while (1)
     {
       if (length < c * 2 + 2)
-	toosmall (_("null terminated unicode string"));
+	{
+	  toosmall (_("null terminated unicode string"));
+	  return NULL;
+	}
       if (windres_get_16 (wrbfd, data + c * 2, 2) == 0)
 	break;
       ++c;
@@ -159,13 +162,19 @@  get_resid (windres_bfd *wrbfd, rc_res_id *id, const bfd_byte *data,
   rc_uint_type first;
 
   if (length < 2)
-    toosmall (_("resource ID"));
+    {
+      toosmall (_("resource ID"));
+      return -1;
+    }
 
   first = windres_get_16 (wrbfd, data, 2);
   if (first == 0xffff)
     {
       if (length < 4)
-	toosmall (_("resource ID"));
+	{
+	  toosmall (_("resource ID"));
+	  return -1;
+	}
       id->named = 0;
       id->u.id = windres_get_16 (wrbfd, data + 2, 2);
       return 4;
@@ -174,6 +183,8 @@  get_resid (windres_bfd *wrbfd, rc_res_id *id, const bfd_byte *data,
     {
       id->named = 1;
       id->u.n.name = get_unicode (wrbfd, data, length, &id->u.n.length);
+      if (id->u.n.name == NULL)
+	return -1;
       return id->u.n.length * 2 + 2;
     }
 }
@@ -204,7 +215,10 @@  bin_to_res_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length
   rc_res_resource *r;
 
   if (length < 4)
-    toosmall (_("cursor"));
+    {
+      toosmall (_("cursor"));
+      return NULL;
+    }
 
   c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
   c->xhotspot = windres_get_16 (wrbfd, data, 2);
@@ -235,32 +249,51 @@  bin_to_res_menu (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
   r->u.menu = m;
 
   if (length < 2)
-    toosmall (_("menu header"));
+    {
+      toosmall (_("menu header"));
+      return NULL;
+    }
 
   version = windres_get_16 (wrbfd, data, 2);
 
   if (version == 0)
     {
       if (length < 4)
-	toosmall (_("menu header"));
+	{
+	  toosmall (_("menu header"));
+	  return NULL;
+	}
       m->help = 0;
       m->items = bin_to_res_menuitems (wrbfd, data + 4, length - 4, &got);
+      if (m->items == NULL)
+	return NULL;
     }
   else if (version == 1)
     {
       rc_uint_type offset;
 
       if (length < 8)
-	toosmall (_("menuex header"));
+	{
+	  toosmall (_("menuex header"));
+	  return NULL;
+	}
       m->help = windres_get_32 (wrbfd, data + 4, 4);
       offset = windres_get_16 (wrbfd, data + 2, 2);
       if (offset + 4 >= length)
-	toosmall (_("menuex offset"));
+	{
+	  toosmall (_("menuex offset"));
+	  return NULL;
+	}
       m->items = bin_to_res_menuexitems (wrbfd, data + 4 + offset,
 					 length - (4 + offset), &got);
+      if (m->items == NULL)
+	return NULL;
     }
   else
-    fatal (_("unsupported menu version %d"), (int) version);
+    {
+      non_fatal (_("unsupported menu version %d"), (int) version);
+      return NULL;
+    }
 
   return r;
 }
@@ -285,7 +318,10 @@  bin_to_res_menuitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type len
       rc_menuitem *mi;
 
       if (length < 4)
-	toosmall (_("menuitem header"));
+	{
+	  toosmall (_("menuitem header"));
+	  return NULL;
+	}
 
       mi = (rc_menuitem *) res_alloc (sizeof *mi);
       mi->state = 0;
@@ -300,7 +336,10 @@  bin_to_res_menuitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type len
 	stroff = 2;
 
       if (length < stroff + 2)
-	toosmall (_("menuitem header"));
+	{
+	  toosmall (_("menuitem header"));
+	  return NULL;
+	}
 
       if (windres_get_16 (wrbfd, data + stroff, 2) == 0)
 	{
@@ -308,7 +347,11 @@  bin_to_res_menuitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type len
 	  mi->text = NULL;
 	}
       else
-	mi->text = get_unicode (wrbfd, data + stroff, length - stroff, &slen);
+	{
+	  mi->text = get_unicode (wrbfd, data + stroff, length - stroff, &slen);
+	  if (mi->text == NULL)
+	    return NULL;
+	}
 
       itemlen = stroff + slen * 2 + 2;
 
@@ -324,6 +367,8 @@  bin_to_res_menuitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type len
 	  mi->id = 0;
 	  mi->popup = bin_to_res_menuitems (wrbfd, data + itemlen, length - itemlen,
 	  				    &subread);
+	  if (mi->popup == NULL)
+	    return NULL;
 	  itemlen += subread;
 	}
 
@@ -362,7 +407,10 @@  bin_to_res_menuexitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type l
       rc_menuitem *mi;
 
       if (length < 16)
-	toosmall (_("menuitem header"));
+	{
+	  toosmall (_("menuitem header"));
+	  return NULL;
+	}
 
       mi = (rc_menuitem *) res_alloc (sizeof (rc_menuitem));
       mi->type = windres_get_32 (wrbfd, data, 4);
@@ -377,7 +425,11 @@  bin_to_res_menuexitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type l
 	  mi->text = NULL;
 	}
       else
-	mi->text = get_unicode (wrbfd, data + 14, length - 14, &slen);
+	{
+	  mi->text = get_unicode (wrbfd, data + 14, length - 14, &slen);
+	  if (mi->text == NULL)
+	    return NULL;
+	}
 
       itemlen = 14 + slen * 2 + 2;
       itemlen = (itemlen + 3) &~ 3;
@@ -392,12 +444,17 @@  bin_to_res_menuexitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type l
 	  rc_uint_type subread;
 
 	  if (length < itemlen + 4)
-	    toosmall (_("menuitem"));
+	    {
+	      toosmall (_("menuitem"));
+	      return NULL;
+	    }
 	  mi->help = windres_get_32 (wrbfd, data + itemlen, 4);
 	  itemlen += 4;
 
 	  mi->popup = bin_to_res_menuexitems (wrbfd, data + itemlen,
 					      length - itemlen, &subread);
+	  if (mi->popup == NULL)
+	    return NULL;
 	  itemlen += subread;
 	}
 
@@ -424,12 +481,16 @@  bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length
   rc_uint_type signature;
   rc_dialog *d;
   rc_uint_type c, sublen, i;
+  int ilen;
   rc_uint_type off;
   rc_dialog_control **pp;
   rc_res_resource *r;
 
   if (length < 18)
-    toosmall (_("dialog header"));
+    {
+      toosmall (_("dialog header"));
+      return NULL;
+    }
 
   d = (rc_dialog *) res_alloc (sizeof (rc_dialog));
 
@@ -447,7 +508,10 @@  bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length
 
       version = windres_get_16 (wrbfd, data, 2);
       if (version != 1)
-	fatal (_("unexpected DIALOGEX version %d"), version);
+	{
+	  non_fatal (_("unexpected DIALOGEX version %d"), version);
+	  return NULL;
+	}
 
       d->ex = (rc_dialog_ex *) res_alloc (sizeof (rc_dialog_ex));
       d->ex->help = windres_get_32 (wrbfd, data + 4, 4);
@@ -457,7 +521,10 @@  bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length
     }
 
   if (length < off + 10)
-    toosmall (_("dialog header"));
+    {
+      toosmall (_("dialog header"));
+      return NULL;
+    }
 
   c = windres_get_16 (wrbfd, data + off, 2);
   d->x = windres_get_16 (wrbfd, data + off + 2, 2);
@@ -467,13 +534,19 @@  bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length
 
   off += 10;
 
-  sublen = get_resid (wrbfd, &d->menu, data + off, length - off);
-  off += sublen;
+  ilen = get_resid (wrbfd, &d->menu, data + off, length - off);
+  if (ilen == -1)
+    return NULL;
+  off += ilen;
 
-  sublen = get_resid (wrbfd, &d->class, data + off, length - off);
-  off += sublen;
+  ilen = get_resid (wrbfd, &d->class, data + off, length - off);
+  if (ilen == -1)
+    return NULL;
+  off += ilen;
 
   d->caption = get_unicode (wrbfd, data + off, length - off, &sublen);
+  if (d->caption == NULL)
+    return NULL;
   off += sublen * 2 + 2;
   if (sublen == 0)
     d->caption = NULL;
@@ -492,7 +565,10 @@  bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length
   else
     {
       if (length < off + 2)
-	toosmall (_("dialog font point size"));
+	{
+	  toosmall (_("dialog font point size"));
+	  return NULL;
+	}
 
       d->pointsize = windres_get_16 (wrbfd, data + off, 2);
       off += 2;
@@ -500,7 +576,10 @@  bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length
       if (d->ex != NULL)
 	{
 	  if (length < off + 4)
-	    toosmall (_("dialogex font information"));
+	    {
+	      toosmall (_("dialogex font information"));
+	      return NULL;
+	    }
 	  d->ex->weight = windres_get_16 (wrbfd, data + off, 2);
 	  d->ex->italic = windres_get_8 (wrbfd, data + off + 2, 1);
 	  d->ex->charset = windres_get_8 (wrbfd, data + off + 3, 1);
@@ -508,6 +587,8 @@  bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length
 	}
 
       d->font = get_unicode (wrbfd, data + off, length - off, &sublen);
+      if (d->font == NULL)
+	return NULL;
       off += sublen * 2 + 2;
     }
 
@@ -526,7 +607,10 @@  bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length
       if (d->ex == NULL)
 	{
 	  if (length < off + 8)
-	    toosmall (_("dialog control"));
+	    {
+	      toosmall (_("dialog control"));
+	      return NULL;
+	    }
 
 	  dc->style = windres_get_32 (wrbfd, data + off, 4);
 	  dc->exstyle = windres_get_32 (wrbfd, data + off + 4, 4);
@@ -536,7 +620,10 @@  bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length
       else
 	{
 	  if (length < off + 12)
-	    toosmall (_("dialogex control"));
+	    {
+	      toosmall (_("dialogex control"));
+	      return NULL;
+	    }
 	  dc->help = windres_get_32 (wrbfd, data + off, 4);
 	  dc->exstyle = windres_get_32 (wrbfd, data + off + 4, 4);
 	  dc->style = windres_get_32 (wrbfd, data + off + 8, 4);
@@ -544,7 +631,10 @@  bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length
 	}
 
       if (length < off + (d->ex != NULL ? 2 : 0) + 10)
-	toosmall (_("dialog control"));
+	{
+	  toosmall (_("dialog control"));
+	  return NULL;
+	}
 
       dc->x = windres_get_16 (wrbfd, data + off, 2);
       dc->y = windres_get_16 (wrbfd, data + off + 2, 2);
@@ -558,14 +648,21 @@  bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length
 
       off += 10 + (d->ex != NULL ? 2 : 0);
 
-      sublen = get_resid (wrbfd, &dc->class, data + off, length - off);
-      off += sublen;
+      ilen = get_resid (wrbfd, &dc->class, data + off, length - off);
+      if (ilen == -1)
+	return NULL;
+      off += ilen;
 
-      sublen = get_resid (wrbfd, &dc->text, data + off, length - off);
-      off += sublen;
+      ilen = get_resid (wrbfd, &dc->text, data + off, length - off);
+      if (ilen == -1)
+	return NULL;
+      off += ilen;
 
       if (length < off + 2)
-	toosmall (_("dialog control end"));
+	{
+	  toosmall (_("dialog control end"));
+	  return NULL;
+	}
 
       datalen = windres_get_16 (wrbfd, data + off, 2);
       off += 2;
@@ -575,7 +672,10 @@  bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length
       else
 	{
 	  if (length < off + datalen)
-	    toosmall (_("dialog control data"));
+	    {
+	      toosmall (_("dialog control data"));
+	      return NULL;
+	    }
 
 	  dc->data = ((rc_rcdata_item *)
 		      res_alloc (sizeof (rc_rcdata_item)));
@@ -615,7 +715,10 @@  bin_to_res_string (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length
       unsigned int slen;
 
       if (length < 2)
-	toosmall (_("stringtable string length"));
+	{
+	  toosmall (_("stringtable string length"));
+	  return NULL;
+	}
       slen = windres_get_16 (wrbfd, data, 2);
       st->strings[i].length = slen;
 
@@ -625,7 +728,10 @@  bin_to_res_string (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length
 	  unsigned int j;
 
 	  if (length < 2 + 2 * slen)
-	    toosmall (_("stringtable string"));
+	    {
+	      toosmall (_("stringtable string"));
+	      return NULL;
+	    }
 
 	  s = (unichar *) res_alloc (slen * sizeof (unichar));
 	  st->strings[i].string = s;
@@ -655,7 +761,10 @@  bin_to_res_fontdir (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type lengt
   rc_res_resource *r;
 
   if (length < 2)
-    toosmall (_("fontdir header"));
+    {
+      toosmall (_("fontdir header"));
+      return NULL;
+    }
 
   c = windres_get_16 (wrbfd, data, 2);
 
@@ -669,7 +778,10 @@  bin_to_res_fontdir (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type lengt
       unsigned int off;
 
       if (length < 56)
-	toosmall (_("fontdir"));
+	{
+	  toosmall (_("fontdir"));
+	  return NULL;
+	}
 
       bfi = (const struct bin_fontdir_item *) data;
       fd = (rc_fontdir *) res_alloc (sizeof *fd);
@@ -686,13 +798,19 @@  bin_to_res_fontdir (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type lengt
       while (off < length && data[off] != '\0')
 	++off;
       if (off >= length)
-	toosmall (_("fontdir device name"));
+	{
+	  toosmall (_("fontdir device name"));
+	  return NULL;
+	}
       ++off;
 
       while (off < length && data[off] != '\0')
 	++off;
       if (off >= length)
-	toosmall (_("fontdir face name"));
+	{
+	  toosmall (_("fontdir face name"));
+	  return NULL;
+	}
       ++off;
 
       fd->length = off;
@@ -732,7 +850,10 @@  bin_to_res_accelerators (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type
       rc_accelerator *a;
 
       if (length < 8)
-	toosmall (_("accelerator"));
+	{
+	  toosmall (_("accelerator"));
+	  return NULL;
+	}
 
       a = (rc_accelerator *) res_alloc (sizeof (rc_accelerator));
 
@@ -791,11 +912,17 @@  bin_to_res_group_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type
   rc_res_resource *r;
 
   if (length < 6)
-    toosmall (_("group cursor header"));
+    {
+      toosmall (_("group cursor header"));
+      return NULL;
+    }
 
   type = windres_get_16 (wrbfd, data + 2, 2);
   if (type != 2)
-    fatal (_("unexpected group cursor type %d"), type);
+    {
+      non_fatal (_("unexpected group cursor type %d"), type);
+      return NULL;
+    }
 
   c = windres_get_16 (wrbfd, data + 4, 2);
 
@@ -810,7 +937,10 @@  bin_to_res_group_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type
       rc_group_cursor *gc;
 
       if (length < 14)
-	toosmall (_("group cursor"));
+	{
+	  toosmall (_("group cursor"));
+	  return NULL;
+	}
 
       gc = (rc_group_cursor *) res_alloc (sizeof *gc);
 
@@ -846,11 +976,17 @@  bin_to_res_group_icon (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type le
   rc_res_resource *r;
 
   if (length < 6)
-    toosmall (_("group icon header"));
+    {
+      toosmall (_("group icon header"));
+      return NULL;
+    }
 
   type = windres_get_16 (wrbfd, data + 2, 2);
   if (type != 1)
-    fatal (_("unexpected group icon type %d"), type);
+    {
+      non_fatal (_("unexpected group icon type %d"), type);
+      return NULL;
+    }
 
   c = windres_get_16 (wrbfd, data + 4, 2);
 
@@ -865,7 +1001,10 @@  bin_to_res_group_icon (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type le
       rc_group_icon *gi;
 
       if (length < 14)
-	toosmall (_("group icon"));
+	{
+	  toosmall (_("group icon"));
+	  return NULL;
+	}
 
       gi = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
 
@@ -897,14 +1036,17 @@  bin_to_res_group_icon (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type le
    sets *LEN to the total length, *VALLEN to the value length, *TYPE
    to the type, and *OFF to the offset to the children.  */
 
-static void
+static bool
 get_version_header (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
 		    const char *key, unichar **pkey,
 		    rc_uint_type *len, rc_uint_type *vallen, rc_uint_type *type,
 		    rc_uint_type *off)
 {
   if (length < 8)
-    toosmall (key);
+    {
+      toosmall (key);
+      return false;
+    }
 
   *len = (windres_get_16 (wrbfd, data, 2) + 3) & ~3;
   *vallen = windres_get_16 (wrbfd, data + 2, 2);
@@ -920,6 +1062,8 @@  get_version_header (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type lengt
       rc_uint_type sublen;
 
       *pkey = get_unicode (wrbfd, data, length, &sublen);
+      if (*pkey == NULL)
+	return false;
       *off += (sublen + 1) * sizeof (unichar);
     }
   else
@@ -927,9 +1071,15 @@  get_version_header (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type lengt
       while (1)
 	{
 	  if (length < 2)
-	    toosmall (key);
+	    {
+	      toosmall (key);
+	      return false;
+	    }
 	  if (windres_get_16 (wrbfd, data, 2) != (bfd_byte) *key)
-	    fatal (_("unexpected version string"));
+	    {
+	      non_fatal (_("unexpected version string"));
+	      return false;
+	    }
 
 	  *off += 2;
 	  length -= 2;
@@ -943,6 +1093,7 @@  get_version_header (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type lengt
     }
 
   *off = (*off + 3) &~ 3;
+  return true;
 }
 
 /* Convert a version resource from binary.  */
@@ -956,16 +1107,23 @@  bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type lengt
   rc_versioninfo *v;
   rc_res_resource *r;
 
-  get_version_header (wrbfd, data, length, "VS_VERSION_INFO",
-		      (unichar **) NULL, &verlen, &vallen, &type, &off);
+  if (!get_version_header (wrbfd, data, length, "VS_VERSION_INFO",
+			   (unichar **) NULL, &verlen, &vallen, &type, &off))
+    return NULL;
 
   /* PR 17512: The verlen field does not include padding length.  */
   if (verlen > length)
-    fatal (_("version length %lu greater than resource length %lu"),
-	   (unsigned long) verlen, (unsigned long) length);
+    {
+      non_fatal (_("version length %lu greater than resource length %lu"),
+		 (unsigned long) verlen, (unsigned long) length);
+      return NULL;
+    }
 
   if (type != 0)
-    fatal (_("unexpected version type %d"), (int) type);
+    {
+      non_fatal (_("unexpected version type %d"), (int) type);
+      return NULL;
+    }
 
   /* PR 27686: Ignore any padding bytes after the end of the version structure.  */
   length = verlen;
@@ -980,18 +1138,31 @@  bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type lengt
       unsigned long signature, fiv;
 
       if (vallen != 52)
-	fatal (_("unexpected fixed version information length %ld"), (long) vallen);
+	{
+	  non_fatal (_("unexpected fixed version information length %ld"),
+		     (long) vallen);
+	  return NULL;
+	}
 
       if (length < 52)
-	toosmall (_("fixed version info"));
+	{
+	  toosmall (_("fixed version info"));
+	  return NULL;
+	}
 
       signature = windres_get_32 (wrbfd, data, 4);
       if (signature != 0xfeef04bd)
-	fatal (_("unexpected fixed version signature %lu"), signature);
+	{
+	  non_fatal (_("unexpected fixed version signature %lu"), signature);
+	  return NULL;
+	}
 
       fiv = windres_get_32 (wrbfd, data + 4, 4);
       if (fiv != 0 && fiv != 0x10000)
-	fatal (_("unexpected fixed version info version %lu"), fiv);
+	{
+	  non_fatal (_("unexpected fixed version info version %lu"), fiv);
+	  return NULL;
+	}
 
       fi = (rc_fixed_versioninfo *) res_alloc (sizeof (rc_fixed_versioninfo));
 
@@ -1020,7 +1191,10 @@  bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type lengt
       int ch;
 
       if (length < 8)
-	toosmall (_("version var info"));
+	{
+	  toosmall (_("version var info"));
+	  return NULL;
+	}
 
       vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
 
@@ -1032,12 +1206,17 @@  bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type lengt
 
 	  vi->type = VERINFO_STRING;
 
-	  get_version_header (wrbfd, data, length, "StringFileInfo",
-			      (unichar **) NULL, &verlen, &vallen, &type,
-			      &off);
+	  if (!get_version_header (wrbfd, data, length, "StringFileInfo",
+				   (unichar **) NULL, &verlen, &vallen, &type,
+				   &off))
+	    return NULL;
 
 	  if (vallen != 0)
-	    fatal (_("unexpected stringfileinfo value length %ld"), (long) vallen);
+	    {
+	      non_fatal (_("unexpected stringfileinfo value length %ld"),
+			 (long) vallen);
+	      return NULL;
+	    }
 
 	  data += off;
 	  length -= off;
@@ -1054,15 +1233,24 @@  bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type lengt
 	      rc_ver_stringinfo **ppvs;
 
 	      if (length < 8)
-		toosmall (_("version stringtable"));
+		{
+		  toosmall (_("version stringtable"));
+		  return NULL;
+		}
 
 	      vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
 
-	      get_version_header (wrbfd, data, length, (const char *) NULL,
-				  &vst->language, &stverlen, &vallen, &type, &off);
+	      if (!get_version_header (wrbfd, data, length, (const char *) NULL,
+				       &vst->language, &stverlen, &vallen,
+				       &type, &off))
+		return NULL;
 
 	      if (vallen != 0)
-		fatal (_("unexpected version stringtable value length %ld"), (long) vallen);
+		{
+		  non_fatal (_("unexpected version stringtable value length %ld"),
+			     (long) vallen);
+		  return NULL;
+		}
 
 	      data += off;
 	      length -= off;
@@ -1079,30 +1267,42 @@  bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type lengt
 	      rc_uint_type sverlen, vslen, valoff;
 
 	      if (length < 8)
-		toosmall (_("version string"));
+		{
+		  toosmall (_("version string"));
+		  return NULL;
+		}
 
 	      vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
 
-	      get_version_header (wrbfd, data, length, (const char *) NULL,
-				  &vs->key, &sverlen, &vallen, &type, &off);
+	      if (!get_version_header (wrbfd, data, length, (const char *) NULL,
+				       &vs->key, &sverlen, &vallen, &type, &off))
+		return NULL;
 
 	      data += off;
 	      length -= off;
 
 	      vs->value = get_unicode (wrbfd, data, length, &vslen);
+	      if (vs->value == NULL)
+		return NULL;
 	      valoff = vslen * 2 + 2;
 	      valoff = (valoff + 3) & ~3;
 
 	      if (off + valoff != sverlen)
-		fatal (_("unexpected version string length %ld != %ld + %ld"),
-		       (long) sverlen, (long) off, (long) valoff);
+		{
+		  non_fatal (_("unexpected version string length %ld != %ld + %ld"),
+			     (long) sverlen, (long) off, (long) valoff);
+		  return NULL;
+		}
 
 	      data += valoff;
 	      length -= valoff;
 
 	      if (stverlen < sverlen)
-		fatal (_("unexpected version string length %ld < %ld"),
-		       (long) verlen, (long) sverlen);
+		{
+		  non_fatal (_("unexpected version string length %ld < %ld"),
+			     (long) verlen, (long) sverlen);
+		  return NULL;
+		}
 	      stverlen -= sverlen;
 	      verlen -= sverlen;
 
@@ -1122,18 +1322,25 @@  bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type lengt
 
 	  vi->type = VERINFO_VAR;
 
-	  get_version_header (wrbfd, data, length, "VarFileInfo",
-			      (unichar **) NULL, &verlen, &vallen, &type,
-			      &off);
+	  if (!get_version_header (wrbfd, data, length, "VarFileInfo",
+				   (unichar **) NULL, &verlen, &vallen,
+				   &type, &off))
+	    return NULL;
 
 	  if (vallen != 0)
-	    fatal (_("unexpected varfileinfo value length %ld"), (long) vallen);
+	    {
+	      non_fatal (_("unexpected varfileinfo value length %ld"),
+			 (long) vallen);
+	      return NULL;
+	    }
 
 	  data += off;
 	  length -= off;
 
-	  get_version_header (wrbfd, data, length, (const char *) NULL,
-			      &vi->u.var.key, &verlen, &vallen, &type, &off);
+	  if (!get_version_header (wrbfd, data, length, (const char *) NULL,
+				   &vi->u.var.key, &verlen, &vallen,
+				   &type, &off))
+	    return NULL;
 
 	  data += off;
 	  length -= off;
@@ -1146,7 +1353,10 @@  bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type lengt
 	      rc_ver_varinfo *vv;
 
 	      if (length < 4)
-		toosmall (_("version varfileinfo"));
+		{
+		  toosmall (_("version varfileinfo"));
+		  return NULL;
+		}
 
 	      vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
 
@@ -1161,7 +1371,11 @@  bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type lengt
 	      length -= 4;
 
 	      if (vallen < 4)
-		fatal (_("unexpected version value length %ld"), (long) vallen);
+		{
+		  non_fatal (_("unexpected version value length %ld"),
+			     (long) vallen);
+		  return NULL;
+		}
 
 	      vallen -= 4;
 	    }
@@ -1171,10 +1385,14 @@  bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type lengt
 	  if (length == 8)
 	    /* Padding - skip.  */
 	    break;
-	  fatal (_("nul bytes found in version string"));
+	  non_fatal (_("nul bytes found in version string"));
+	  return NULL;
 	}
       else
-	fatal (_("unexpected version string character: %x"), ch);
+	{
+	  non_fatal (_("unexpected version string character: %x"), ch);
+	  return NULL;
+	}
 
       vi->next = NULL;
       *pp = vi;
@@ -1224,7 +1442,10 @@  bin_to_res_toolbar (windres_bfd *wrbfd, const bfd_byte *data,
   rc_uint_type i;
 
   if (length < 12)
-    toosmall (_("toolbar"));
+    {
+      toosmall (_("toolbar"));
+      return NULL;
+    }
   ri = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
   ri->button_width = windres_get_32 (wrbfd, data, 4);
   ri->button_height = windres_get_32 (wrbfd, data + 4, 4);
@@ -1747,11 +1968,12 @@  res_to_bin_menuitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *i
       if (wrbfd)
 	{
 	  windres_put_16 (wrbfd, bmi.flags, flags);
-      if (mi->popup == NULL)
+	  if (mi->popup == NULL)
 	    windres_put_16 (wrbfd, bmi.id, mi->id);
 	  set_windres_bfd_content (wrbfd, &bmi, off,
-				   mi->popup == NULL ? BIN_MENUITEM_SIZE
-				   		     : BIN_MENUITEM_POPUP_SIZE);
+				   (mi->popup == NULL
+				    ? BIN_MENUITEM_SIZE
+				    : BIN_MENUITEM_POPUP_SIZE));
 	}
       off += (mi->popup == NULL ? BIN_MENUITEM_SIZE : BIN_MENUITEM_POPUP_SIZE);
 
@@ -1862,22 +2084,22 @@  res_to_bin_rcdata (windres_bfd *wrbfd, rc_uint_type off, const rc_rcdata_item *i
 	      break;
 	    case RCDATA_STRING:
 	      hp = (bfd_byte *) ri->u.string.s;
-	  break;
-	case RCDATA_WSTRING:
-	  {
+	      break;
+	    case RCDATA_WSTRING:
+	      {
 		rc_uint_type i;
 
 		hp = (bfd_byte *) reswr_alloc (len);
-	    for (i = 0; i < ri->u.wstring.length; i++)
+		for (i = 0; i < ri->u.wstring.length; i++)
 		  windres_put_16 (wrbfd, hp + i * sizeof (unichar), ri->u.wstring.w[i]);
-	  }
+	      }
 	      break;
-	case RCDATA_BUFFER:
+	    case RCDATA_BUFFER:
 	      hp = (bfd_byte *) ri->u.buffer.data;
-	  break;
-	}
+	      break;
+	    }
 	  set_windres_bfd_content (wrbfd, hp, off, len);
-    }
+	}
       off += len;
     }
   return off;
@@ -1909,10 +2131,10 @@  res_to_bin_stringtable (windres_bfd *wrbfd, rc_uint_type off,
 	  hp = (bfd_byte *) reswr_alloc (length);
 	  windres_put_16 (wrbfd, hp, slen);
 
-      for (j = 0; j < slen; j++)
+	  for (j = 0; j < slen; j++)
 	    windres_put_16 (wrbfd, hp + 2 + j * 2, s[j]);
 	  set_windres_bfd_content (wrbfd, hp, off, length);
-    }
+	}
       off += length;
     }
   return off;
diff --git a/binutils/rescoff.c b/binutils/rescoff.c
index f9a1e70d162..98e5eb0ea3b 100644
--- a/binutils/rescoff.c
+++ b/binutils/rescoff.c
@@ -120,27 +120,38 @@  read_coff_rsrc (const char *filename, const char *target)
   struct coff_file_info flaginfo;
 
   if (filename == NULL)
-    fatal (_("filename required for COFF input"));
+    {
+      non_fatal (_("filename required for COFF input"));
+      return NULL;
+    }
 
   abfd = bfd_openr (filename, target);
   if (abfd == NULL)
-    bfd_fatal (filename);
+    {
+      bfd_nonfatal (filename);
+      return NULL;
+    }
 
   if (! bfd_check_format_matches (abfd, bfd_object, &matching))
     {
       bfd_nonfatal (bfd_get_filename (abfd));
       if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
 	list_matching_formats (matching);
-      xexit (1);
+      free (matching);
+      return NULL;
     }
   if (bfd_get_flavour (abfd) != bfd_target_coff_flavour
       || !obj_pe (abfd))
-    fatal (_("%s: not a PE file"), filename);
+    {
+      non_fatal (_("%s: not a PE file"), filename);
+      return NULL;
+    }
 
   sec = bfd_get_section_by_name (abfd, ".rsrc");
   if (sec == NULL)
     {
-      fatal (_("%s: no resource section"), filename);
+      non_fatal (_("%s: no resource section"), filename);
+      return NULL;
     }
 
   set_windres_bfd (&wrbfd, abfd, sec, WR_KIND_BFD);
@@ -150,7 +161,10 @@  read_coff_rsrc (const char *filename, const char *target)
      but there is no other way to determine if the section size
      is reasonable.  */
   if (size > (bfd_size_type) get_file_size (filename))
-    fatal (_("%s: .rsrc section is bigger than the file!"), filename);
+    {
+      non_fatal (_("%s: .rsrc section is bigger than the file!"), filename);
+      return NULL;
+    }
 
   data = (bfd_byte *) res_alloc (size);
   get_windres_bfd_content (&wrbfd, data, 0, size);
@@ -178,7 +192,7 @@  read_coff_rsrc (const char *filename, const char *target)
 static void
 overrun (const struct coff_file_info *flaginfo, const char *msg)
 {
-  fatal (_("%s: %s: address out of bounds"), flaginfo->filename, msg);
+  non_fatal (_("%s: %s: address out of bounds"), flaginfo->filename, msg);
 }
 
 /* Read a resource directory.  */
@@ -199,10 +213,16 @@  read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
      Microsoft only defines 3 levels.  Corrupt files however might
      claim to use more.  */
   if (level > 4)
-    fatal (_("%s: resources nest too deep"), flaginfo->filename);
+    {
+      non_fatal (_("%s: resources nest too deep"), flaginfo->filename);
+      return NULL;
+    }
 
   if ((size_t) (flaginfo->data_end - data) < sizeof (struct extern_res_directory))
-    overrun (flaginfo, _("directory"));
+    {
+      overrun (flaginfo, _("directory"));
+      return NULL;
+    }
 
   erd = (const struct extern_res_directory *) data;
 
@@ -230,7 +250,10 @@  read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
       int length, j;
 
       if ((const bfd_byte *) ere >= flaginfo->data_end)
-	overrun (flaginfo, _("named directory entry"));
+	{
+	  overrun (flaginfo, _("named directory entry"));
+	  return NULL;
+	}
 
       name = windres_get_32 (wrbfd, ere->name, 4);
       rva = windres_get_32 (wrbfd, ere->rva, 4);
@@ -239,7 +262,10 @@  read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
       name &=~ 0x80000000;
 
       if (name > (rc_uint_type) (flaginfo->data_end - flaginfo->data))
-	overrun (flaginfo, _("directory entry name"));
+	{
+	  overrun (flaginfo, _("directory entry name"));
+	  return NULL;
+	}
 
       ers = flaginfo->data + name;
 
@@ -252,8 +278,12 @@  read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
       for (j = 0; j < length; j++)
 	{
 	  /* PR 17512: file: 05dc4a16.  */
-	  if (length < 0 || ers >= flaginfo->data_end || ers + j * 2 + 4 >= flaginfo->data_end)
-	    overrun (flaginfo, _("resource name"));
+	  if (length < 0 || ers >= flaginfo->data_end
+	      || ers + j * 2 + 4 >= flaginfo->data_end)
+	    {
+	      overrun (flaginfo, _("resource name"));
+	      return NULL;
+	    }
 	  re->id.u.n.name[j] = windres_get_16 (wrbfd, ers + j * 2 + 2, 2);
 	}
 
@@ -264,7 +294,10 @@  read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
 	{
 	  rva &=~ 0x80000000;
 	  if (rva >= (rc_uint_type) (flaginfo->data_end - flaginfo->data))
-	    overrun (flaginfo, _("named subdirectory"));
+	    {
+	      overrun (flaginfo, _("named subdirectory"));
+	      return NULL;
+	    }
 	  re->subdir = 1;
 	  re->u.dir = read_coff_res_dir (wrbfd, flaginfo->data + rva, flaginfo, type,
 					 level + 1);
@@ -272,7 +305,10 @@  read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
       else
 	{
 	  if (rva >= (rc_uint_type) (flaginfo->data_end - flaginfo->data))
-	    overrun (flaginfo, _("named resource"));
+	    {
+	      overrun (flaginfo, _("named resource"));
+	      return NULL;
+	    }
 	  re->subdir = 0;
 	  re->u.res = read_coff_data_entry (wrbfd, flaginfo->data + rva, flaginfo, type);
 	}
@@ -287,7 +323,10 @@  read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
       rc_res_entry *re;
 
       if ((const bfd_byte *) ere >= flaginfo->data_end)
-	overrun (flaginfo, _("ID directory entry"));
+	{
+	  overrun (flaginfo, _("ID directory entry"));
+	  return NULL;
+	}
 
       name = windres_get_32 (wrbfd, ere->name, 4);
       rva = windres_get_32 (wrbfd, ere->rva, 4);
@@ -304,7 +343,10 @@  read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
 	{
 	  rva &=~ 0x80000000;
 	  if (rva >= (rc_uint_type) (flaginfo->data_end - flaginfo->data))
-	    overrun (flaginfo, _("ID subdirectory"));
+	    {
+	      overrun (flaginfo, _("ID subdirectory"));
+	      return NULL;
+	    }
 	  re->subdir = 1;
 	  re->u.dir = read_coff_res_dir (wrbfd, flaginfo->data + rva, flaginfo, type,
 					 level + 1);
@@ -312,7 +354,10 @@  read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
       else
 	{
 	  if (rva >= (rc_uint_type) (flaginfo->data_end - flaginfo->data))
-	    overrun (flaginfo, _("ID resource"));
+	    {
+	      overrun (flaginfo, _("ID resource"));
+	      return NULL;
+	    }
 	  re->subdir = 0;
 	  re->u.res = read_coff_data_entry (wrbfd, flaginfo->data + rva, flaginfo, type);
 	}
@@ -337,10 +382,16 @@  read_coff_data_entry (windres_bfd *wrbfd, const bfd_byte *data,
   const bfd_byte *resdata;
 
   if (type == NULL)
-    fatal (_("resource type unknown"));
+    {
+      non_fatal (_("resource type unknown"));
+      return NULL;
+    }
 
   if ((size_t) (flaginfo->data_end - data) < sizeof (struct extern_res_data))
-    overrun (flaginfo, _("data entry"));
+    {
+      overrun (flaginfo, _("data entry"));
+      return NULL;
+    }
 
   erd = (const struct extern_res_data *) data;
 
@@ -348,18 +399,26 @@  read_coff_data_entry (windres_bfd *wrbfd, const bfd_byte *data,
   rva = windres_get_32 (wrbfd, erd->rva, 4);
   if (rva < flaginfo->secaddr
       || rva - flaginfo->secaddr >= (rc_uint_type) (flaginfo->data_end - flaginfo->data))
-    overrun (flaginfo, _("resource data"));
+    {
+      overrun (flaginfo, _("resource data"));
+      return NULL;
+    }
 
   resdata = flaginfo->data + (rva - flaginfo->secaddr);
 
   if (size > (rc_uint_type) (flaginfo->data_end - resdata))
-    overrun (flaginfo, _("resource data size"));
+    {
+      overrun (flaginfo, _("resource data size"));
+      return NULL;
+    }
 
   r = bin_to_res (wrbfd, *type, resdata, size);
-
-  memset (&r->res_info, 0, sizeof (rc_res_res_info));
-  r->coff_info.codepage = windres_get_32 (wrbfd, erd->codepage, 4);
-  r->coff_info.reserved = windres_get_32 (wrbfd, erd->reserved, 4);
+  if (r != NULL)
+    {
+      memset (&r->res_info, 0, sizeof (rc_res_res_info));
+      r->coff_info.codepage = windres_get_32 (wrbfd, erd->codepage, 4);
+      r->coff_info.reserved = windres_get_32 (wrbfd, erd->reserved, 4);
+    }
 
   return r;
 }
@@ -422,9 +481,9 @@  struct coff_write_info
 
 static void coff_bin_sizes (const rc_res_directory *, struct coff_write_info *);
 static bfd_byte *coff_alloc (struct bindata_build *, rc_uint_type);
-static void coff_to_bin
+static bool coff_to_bin
   (const rc_res_directory *, struct coff_write_info *);
-static void coff_res_to_bin
+static bool coff_res_to_bin
   (const rc_res_resource *, struct coff_write_info *);
 
 /* Write resources to a COFF file.  RESOURCES should already be
@@ -435,7 +494,7 @@  static void coff_res_to_bin
    would require doing the basic work of objcopy, just modifying or
    adding the .rsrc section.  */
 
-void
+bool
 write_coff_file (const char *filename, const char *target,
 		 const rc_res_directory *resources)
 {
@@ -448,44 +507,77 @@  write_coff_file (const char *filename, const char *target,
   unsigned long length, offset;
 
   if (filename == NULL)
-    fatal (_("filename required for COFF output"));
+    {
+      non_fatal (_("filename required for COFF output"));
+      return false;
+    }
 
   abfd = bfd_openw (filename, target);
   if (abfd == NULL)
-    bfd_fatal (filename);
+    {
+      bfd_nonfatal (filename);
+      return false;
+    }
 
   if (! bfd_set_format (abfd, bfd_object))
-    bfd_fatal ("bfd_set_format");
+    {
+      bfd_nonfatal ("bfd_set_format");
+      return false;
+    }
 
 #if defined DLLTOOL_SH
   if (! bfd_set_arch_mach (abfd, bfd_arch_sh, 0))
-    bfd_fatal ("bfd_set_arch_mach(sh)");
+    {
+      bfd_nonfatal ("bfd_set_arch_mach(sh)");
+      return false;
+    }
 #elif defined DLLTOOL_MIPS
   if (! bfd_set_arch_mach (abfd, bfd_arch_mips, 0))
-    bfd_fatal ("bfd_set_arch_mach(mips)");
+    {
+      bfd_nonfatal ("bfd_set_arch_mach(mips)");
+      return false;
+    }
 #elif defined DLLTOOL_ARM
   if (! bfd_set_arch_mach (abfd, bfd_arch_arm, 0))
-    bfd_fatal ("bfd_set_arch_mach(arm)");
+    {
+      bfd_nonfatal ("bfd_set_arch_mach(arm)");
+      return false;
+    }
 #elif defined DLLTOOL_AARCH64
   if (! bfd_set_arch_mach (abfd, bfd_arch_aarch64, 0))
-    bfd_fatal ("bfd_set_arch_mach(aarch64)");
+    {
+      bfd_nonfatal ("bfd_set_arch_mach(aarch64)");
+      return false;
+    }
 #else
   /* FIXME: This is obviously i386 specific.  */
   if (! bfd_set_arch_mach (abfd, bfd_arch_i386, 0))
-    bfd_fatal ("bfd_set_arch_mach(i386)");
+    {
+      bfd_nonfatal ("bfd_set_arch_mach(i386)");
+      return false;
+    }
 #endif
 
   if (! bfd_set_file_flags (abfd, HAS_SYMS | HAS_RELOC))
-    bfd_fatal ("bfd_set_file_flags");
+    {
+      bfd_nonfatal ("bfd_set_file_flags");
+      return false;
+    }
 
   sec = bfd_make_section_with_flags (abfd, ".rsrc",
 				     (SEC_HAS_CONTENTS | SEC_ALLOC
 				      | SEC_LOAD | SEC_DATA | SEC_READONLY));
   if (sec == NULL)
-    bfd_fatal ("bfd_make_section");
+    {
+      bfd_nonfatal ("bfd_make_section");
+      return false;
+    }
 
   if (! bfd_set_symtab (abfd, &sec->symbol, 1))
-    bfd_fatal ("bfd_set_symtab");
+    {
+      bfd_nonfatal ("bfd_set_symtab");
+      return false;
+    }
 
   /* Requiring this is probably a bug in BFD.  */
   sec->output_section = sec;
@@ -529,7 +621,8 @@  write_coff_file (const char *filename, const char *target,
   cwi.dirstrsize = (cwi.dirstrsize + 7) & ~7;
 
   /* Actually convert the resources to binary.  */
-  coff_to_bin (resources, &cwi);
+  if (!coff_to_bin (resources, &cwi))
+    return false;
 
   /* Add another few bytes to the directory strings if needed for
      alignment.  */
@@ -554,7 +647,10 @@  write_coff_file (const char *filename, const char *target,
 	    + cwi.resources.length);
 
   if (!bfd_set_section_size (sec, length))
-    bfd_fatal ("bfd_set_section_size");
+    {
+      bfd_nonfatal ("bfd_set_section_size");
+      return false;
+    }
 
   bfd_set_reloc (abfd, sec, cwi.relocs, cwi.reloc_count);
 
@@ -562,7 +658,10 @@  write_coff_file (const char *filename, const char *target,
   for (d = cwi.dirs.d; d != NULL; d = d->next)
     {
       if (! bfd_set_section_contents (abfd, sec, d->data, offset, d->length))
-	bfd_fatal ("bfd_set_section_contents");
+	{
+	  bfd_nonfatal ("bfd_set_section_contents");
+	  return false;
+	}
       offset += d->length;
     }
   for (d = cwi.dirstrs.d; d != NULL; d = d->next)
@@ -577,17 +676,23 @@  write_coff_file (const char *filename, const char *target,
     }
   for (rd = cwi.resources.d; rd != NULL; rd = rd->next)
     {
-      res_to_bin (cwi.wrbfd, (rc_uint_type) offset, rd->res);
+      if (res_to_bin (cwi.wrbfd, (rc_uint_type) offset, rd->res)
+	  == (rc_uint_type) -1)
+	return false;
       offset += rd->length;
     }
 
   assert (offset == length);
 
   if (! bfd_close (abfd))
-    bfd_fatal ("bfd_close");
+    {
+      bfd_nonfatal ("bfd_close");
+      return false;
+    }
 
   /* We allocated the relocs array using malloc.  */
   free (cwi.relocs);
+  return true;
 }
 
 /* Work out the sizes of the various fixed size resource directory
@@ -640,7 +745,7 @@  coff_alloc (struct bindata_build *bb, rc_uint_type size)
 
 /* Convert the resource directory RESDIR to binary.  */
 
-static void
+static bool
 coff_to_bin (const rc_res_directory *resdir, struct coff_write_info *cwi)
 {
   struct extern_res_directory *erd;
@@ -701,21 +806,24 @@  coff_to_bin (const rc_res_directory *resdir, struct coff_write_info *cwi)
       if (e->subdir)
 	{
 	  windres_put_32 (cwi->wrbfd, ere->rva, 0x80000000 | cwi->dirs.length);
-	  coff_to_bin (e->u.dir, cwi);
+	  if (!coff_to_bin (e->u.dir, cwi))
+	    return false;
 	}
       else
 	{
 	  windres_put_32 (cwi->wrbfd, ere->rva,
-		     cwi->dirsize + cwi->dirstrsize + cwi->dataents.length);
+			  cwi->dirsize + cwi->dirstrsize + cwi->dataents.length);
 
-	  coff_res_to_bin (e->u.res, cwi);
+	  if (!coff_res_to_bin (e->u.res, cwi))
+	    return false;
 	}
     }
+  return true;
 }
 
 /* Convert the resource RES to binary.  */
 
-static void
+static bool
 coff_res_to_bin (const rc_res_resource *res, struct coff_write_info *cwi)
 {
   arelent *r;
@@ -735,7 +843,10 @@  coff_res_to_bin (const rc_res_resource *res, struct coff_write_info *cwi)
   r->addend = 0;
   r->howto = bfd_reloc_type_lookup (WR_BFD (cwi->wrbfd), BFD_RELOC_RVA);
   if (r->howto == NULL)
-    bfd_fatal (_("can't get BFD_RELOC_RVA relocation type"));
+    {
+      bfd_nonfatal (_("can't get BFD_RELOC_RVA relocation type"));
+      return false;
+    }
 
   cwi->relocs = xrealloc (cwi->relocs,
 			  (cwi->reloc_count + 2) * sizeof (arelent *));
@@ -755,6 +866,8 @@  coff_res_to_bin (const rc_res_resource *res, struct coff_write_info *cwi)
 
   d = (coff_res_data *) reswr_alloc (sizeof (coff_res_data));
   d->length = res_to_bin (NULL, (rc_uint_type) 0, res);
+  if (d->length == (rc_uint_type) -1)
+    return false;
   d->res = res;
   d->next = NULL;
 
@@ -770,4 +883,5 @@  coff_res_to_bin (const rc_res_resource *res, struct coff_write_info *cwi)
 
   /* Force the next resource to have 64 bit alignment.  */
   d->length = (d->length + 7) & ~7;
+  return true;
 }
diff --git a/binutils/resrc.c b/binutils/resrc.c
index d265818bfd9..8f9451b659c 100644
--- a/binutils/resrc.c
+++ b/binutils/resrc.c
@@ -1938,7 +1938,7 @@  indent (FILE *e, int c)
    refer to that file, we use the user-data model for that to express it binary
    without the need to store it somewhere externally.  */
 
-void
+bool
 write_rc_file (const char *filename, const rc_res_directory *res_dir)
 {
   FILE *e;
@@ -1950,12 +1950,17 @@  write_rc_file (const char *filename, const rc_res_directory *res_dir)
     {
       e = fopen (filename, FOPEN_WT);
       if (e == NULL)
-	fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
+	{
+	  non_fatal (_("can't open `%s' for output: %s"),
+		     filename, strerror (errno));
+	  return false;
+	}
     }
 
   language = (rc_uint_type) ((bfd_signed_vma) -1);
   write_rc_directory (e, res_dir, (const rc_res_id *) NULL,
 		      (const rc_res_id *) NULL, &language, 1);
+  return true;
 }
 
 /* Write out a directory.  E is the file to write to.  RD is the
diff --git a/binutils/resres.c b/binutils/resres.c
index ab5aa66c71a..d96fb144a8c 100644
--- a/binutils/resres.c
+++ b/binutils/resres.c
@@ -109,14 +109,14 @@  read_res_file (const char *fn)
 }
 
 /* Write resource file */
-void
+bool
 write_res_file (const char *fn,const rc_res_directory *resdir)
 {
   asection *sec;
   rc_uint_type language;
   bfd *abfd;
   windres_bfd wrbfd;
-  unsigned long sec_length = 0,sec_length_wrote;
+  rc_uint_type sec_length = 0, sec_length_wrote;
   static const bfd_byte sign[] =
   {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
    0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
@@ -130,7 +130,10 @@  write_res_file (const char *fn,const rc_res_directory *resdir)
 				     (SEC_HAS_CONTENTS | SEC_ALLOC
 				      | SEC_LOAD | SEC_DATA));
   if (sec == NULL)
-    bfd_fatal ("bfd_make_section");
+    {
+      bfd_nonfatal ("bfd_make_section");
+      return false;
+    }
   /* Requiring this is probably a bug in BFD.  */
   sec->output_section = sec;
 
@@ -142,8 +145,13 @@  write_res_file (const char *fn,const rc_res_directory *resdir)
   sec_length = write_res_directory ((windres_bfd *) NULL, 0x20UL, resdir,
 				    (const rc_res_id *) NULL,
 				    (const rc_res_id *) NULL, &language, 1);
+  if (sec_length == (rc_uint_type) -1)
+    return false;
   if (!bfd_set_section_size (sec, (sec_length + 3) & ~3))
-    bfd_fatal ("bfd_set_section_size");
+    {
+      bfd_nonfatal ("bfd_set_section_size");
+      return false;
+    }
   if ((sec_length & 3) != 0)
     set_windres_bfd_content (&wrbfd, sign, sec_length, 4-(sec_length & 3));
   set_windres_bfd_content (&wrbfd, sign, 0, sizeof (sign));
@@ -152,12 +160,16 @@  write_res_file (const char *fn,const rc_res_directory *resdir)
 					  (const rc_res_id *) NULL,
 					  (const rc_res_id *) NULL,
 					  &language, 1);
+  if (sec_length_wrote == (rc_uint_type) -1)
+    return false;
   if (sec_length != sec_length_wrote)
-    fatal ("res write failed with different sizes (%lu/%lu).",
-	   (unsigned long) sec_length, (unsigned long) sec_length_wrote);
+    {
+      non_fatal ("res write failed with different sizes (%lu/%lu).",
+		 (unsigned long) sec_length, (unsigned long) sec_length_wrote);
+      return false;
+    }
 
-  bfd_close (abfd);
-  return;
+  return bfd_close (abfd);
 }
 
 /* Read a resource entry, returns 0 when all resources are read */
@@ -252,8 +264,12 @@  write_res_directory (windres_bfd *wrbfd, rc_uint_type off, const rc_res_director
 	}
 
       if (re->subdir)
-	off = write_res_directory (wrbfd, off, re->u.dir, type, name, language,
-				   level + 1);
+	{
+	  off = write_res_directory (wrbfd, off, re->u.dir, type, name, language,
+				     level + 1);
+	  if (off == (rc_uint_type) -1)
+	    return off;
+	}
       else
 	{
 	  if (level == 3)
@@ -265,12 +281,16 @@  write_res_directory (windres_bfd *wrbfd, rc_uint_type off, const rc_res_director
 	         resource itself records if anything.  */
 	      off = write_res_resource (wrbfd, off, type, name, re->u.res,
 	      				language);
+	      if (off == (rc_uint_type) -1)
+		return off;
 	    }
 	  else
 	    {
 	      fprintf (stderr, "// Resource at unexpected level %d\n", level);
 	      off = write_res_resource (wrbfd, off, type, (rc_res_id *) NULL,
 	      				re->u.res, language);
+	      if (off == (rc_uint_type) -1)
+		return off;
 	    }
 	}
     }
@@ -378,6 +398,8 @@  write_res_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res,
   rc_uint_type datasize = 0;
 
   noff = res_to_bin ((windres_bfd *) NULL, off, res);
+  if (noff == (rc_uint_type) -1)
+    return noff;
   datasize = noff - off;
 
   off = write_res_header (wrbfd, off, datasize, type, name, resinfo);
diff --git a/binutils/windres.c b/binutils/windres.c
index 18062f50c45..b41353b0b88 100644
--- a/binutils/windres.c
+++ b/binutils/windres.c
@@ -1056,23 +1056,24 @@  main (int argc, char **argv)
   /* Write the output file.  */
   reswr_init ();
 
+  bool ok;
   switch (output_format)
     {
     default:
       abort ();
     case RES_FORMAT_RC:
-      write_rc_file (output_filename, resources);
+      ok = write_rc_file (output_filename, resources);
       break;
     case RES_FORMAT_RES:
-      write_res_file (output_filename, resources);
+      ok = write_res_file (output_filename, resources);
       break;
     case RES_FORMAT_COFF:
-      write_coff_file (output_filename, target, resources);
+      ok = write_coff_file (output_filename, target, resources);
       break;
     }
 
-  xexit (0);
-  return 0;
+  xexit (ok ? 0 : 1);
+  return ok ? 0 : 1;
 }
 
 static void
@@ -1094,13 +1095,18 @@  windres_open_as_binary (const char *filename, int rdmode)
 {
   bfd *abfd;
 
-  abfd = (rdmode ? bfd_openr (filename, "binary") : bfd_openw (filename, "binary"));
-  if (! abfd)
-    fatal ("can't open `%s' for %s", filename, (rdmode ? "input" : "output"));
-
-  if (rdmode && ! bfd_check_format (abfd, bfd_object))
-    fatal ("can't open `%s' for input.", filename);
-
+  if (rdmode)
+    {
+      abfd = bfd_openr (filename, "binary");
+      if (abfd == NULL || !bfd_check_format (abfd, bfd_object))
+	fatal ("can't open `%s' for input", filename);
+    }
+  else
+    {
+      abfd = bfd_openw (filename, "binary");
+      if (abfd == NULL || !bfd_set_format (abfd, bfd_object))
+	fatal ("can't open `%s' for output", filename);
+    }
   return abfd;
 }
 
diff --git a/binutils/windres.h b/binutils/windres.h
index 309564ecf9d..15c6ad09b1d 100644
--- a/binutils/windres.h
+++ b/binutils/windres.h
@@ -35,9 +35,9 @@  extern int verbose;
 extern rc_res_directory *read_rc_file (const char *, const char *, const char *, int, int);
 extern rc_res_directory *read_res_file (const char *);
 extern rc_res_directory *read_coff_rsrc (const char *, const char *);
-extern void write_rc_file (const char *, const rc_res_directory *);
-extern void write_res_file (const char *, const rc_res_directory *);
-extern void write_coff_file (const char *, const char *, const rc_res_directory *);
+extern bool write_rc_file (const char *, const rc_res_directory *);
+extern bool write_res_file (const char *, const rc_res_directory *);
+extern bool write_coff_file (const char *, const char *, const rc_res_directory *);
 
 extern rc_res_resource *bin_to_res (windres_bfd *, rc_res_id, const bfd_byte *,
 				    rc_uint_type);