public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] libctf: ctf_member_next needs to return (ssize_t)-1 on error
@ 2023-08-24 11:32 Torbjörn SVENSSON
  2023-08-25  2:22 ` Alan Modra
  0 siblings, 1 reply; 41+ messages in thread
From: Torbjörn SVENSSON @ 2023-08-24 11:32 UTC (permalink / raw)
  To: binutils; +Cc: Torbjörn SVENSSON, Yvan ROUX

The function ctf_member_next should return (ssize_t)-1 on
error. As the function ctf_set_errno returns (ctf_id_t)-1L and that is
then casted to "unsigned long" as it's the return type of the function,
it's not compatible and causes the value 0xffffffff to be returned on
64-bit Windows builds. As a result, the check for a negative value in
ctf_dedup_rhash_type will never be true and a resulting infinit loop is
created.

This was found testing an arm-none-eabi toolchain built with
x86_64-w64-mingw32. If the same source tree is built with
i686-w64-mingw32, everything appears to be working correctly.

Signed-off-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
Co-Authored-By: Yvan ROUX <yvan.roux@foss.st.com>
---
 libctf/ctf-types.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index c20ff825d9a..058b647ba9a 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -233,7 +233,8 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
  end_iter:
   ctf_next_destroy (i);
   *it = NULL;
-  return ctf_set_errno (ofp, ECTF_NEXT_END);
+  ctf_set_errno (ofp, ECTF_NEXT_END);
+  return -1;
 }
 
 /* Iterate over the members of an ENUM.  We pass the string name and associated
-- 
2.25.1


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

* Re: [PATCH] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-08-24 11:32 [PATCH] libctf: ctf_member_next needs to return (ssize_t)-1 on error Torbjörn SVENSSON
@ 2023-08-25  2:22 ` Alan Modra
  2023-08-25 16:53   ` [PATCH v2] " Torbjörn SVENSSON
  0 siblings, 1 reply; 41+ messages in thread
From: Alan Modra @ 2023-08-25  2:22 UTC (permalink / raw)
  To: Torbjörn SVENSSON; +Cc: binutils, Yvan ROUX

On Thu, Aug 24, 2023 at 01:32:49PM +0200, Torbjörn SVENSSON via Binutils wrote:
> diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
> index c20ff825d9a..058b647ba9a 100644
> --- a/libctf/ctf-types.c
> +++ b/libctf/ctf-types.c
> @@ -233,7 +233,8 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
>   end_iter:
>    ctf_next_destroy (i);
>    *it = NULL;
> -  return ctf_set_errno (ofp, ECTF_NEXT_END);
> +  ctf_set_errno (ofp, ECTF_NEXT_END);
> +  return -1;
>  }
>  
>  /* Iterate over the members of an ENUM.  We pass the string name and associated

This isn't the correct fix.  There are many uses of ctf_set_errno,
even in the function you are patching.  Some other fix is needed to
cope with unsigned long being smaller than ssize_t for the Microsoft
64-bit ABIs.

-- 
Alan Modra
Australia Development Lab, IBM

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

* [PATCH v2] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-08-25  2:22 ` Alan Modra
@ 2023-08-25 16:53   ` Torbjörn SVENSSON
  2023-08-30  8:34     ` Torbjorn SVENSSON
  0 siblings, 1 reply; 41+ messages in thread
From: Torbjörn SVENSSON @ 2023-08-25 16:53 UTC (permalink / raw)
  To: binutils; +Cc: amodra, Torbjörn SVENSSON, Yvan ROUX

v1 -> v2:
Changed all functions with signed interger return type to return -1 based on
comment from Alan.


Ok for trunk?

---

The function ctf_member_next should return (ssize_t)-1 on
error. As the function ctf_set_errno returns (ctf_id_t)-1L and that is
then casted to "unsigned long" as it's the return type of the function,
it's not compatible and causes the value 0xffffffff to be returned on
64-bit Windows builds. As a result, the check for a negative value in
ctf_dedup_rhash_type will never be true and a resulting infinit loop is
created.

This was found testing an arm-none-eabi toolchain built with
x86_64-w64-mingw32. If the same source tree is built with
i686-w64-mingw32, everything appears to be working correctly.

libctf/
	* ctf-create.c (ctf_add_enumerator): Ensure function returns -1 on error.
	(ctf_add_funcobjt_sym): Likewise.
	(ctf_add_member_encoded): Likewise.
	(ctf_add_member_offset): Likewise.
	(ctf_add_variable): Likewise.
	(ctf_grow_ptrtab): Likewise.
	(ctf_grow_vlen): Likewise.
	(ctf_rollback): Likewise.
	(ctf_set_array): Likewise.
	(ctf_update): Likewise.
	* ctf-dedup.c (ctf_dedup_atoms_init): Likewise.
	(ctf_dedup_conflictify_unshared): Likewise.
	(ctf_dedup_detect_name_ambiguity): Likewise.
	(ctf_dedup_emit_struct_members): Likewise.
	(ctf_dedup_emit_type): Likewise.
	(ctf_dedup_hash_kind): Likewise.
	(ctf_dedup_init): Likewise.
	(ctf_dedup_mark_conflicting_hash): Likewise.
	(ctf_dedup_multiple_input_dicts): Likewise.
	(ctf_dedup_populate_mappings): Likewise.
	(ctf_dedup_record_origin): Likewise.
	(ctf_dedup_rwalk_output_mapping): Likewise.
	(ctf_dedup_walk_output_mapping): Likewise.
	* ctf-dump.c (ctf_dump_append): Likewise.
	(ctf_dump_header): Likewise.
	(ctf_dump_header_sectfield): Likewise.
	(ctf_dump_header_strfield): Likewise.
	(ctf_dump_label): Likewise.
	(ctf_dump_member): Likewise.
	(ctf_dump_str): Likewise.
	(ctf_dump_type): Likewise.
	(ctf_dump_var): Likewise.
	* ctf-labels.c (ctf_label_info): Likewise.
	(ctf_label_iter): Likewise.
	* ctf-link.c (ctf_link_add_ctf_internal): Likewise.
	(ctf_link_add_cu_mapping): Likewise.
	(ctf_link_add): Likewise.
	(ctf_link_deduplicating_one_symtypetab): Likewise.
	(ctf_link_deduplicating_per_cu): Likewise.
	(ctf_link_deduplicating_variables): Likewise.
	(ctf_link): Likewise.
	(ctf_link_one_variable): Likewise.
	* ctf-lookup.c (ctf_func_args): Likewise.
	(ctf_func_info): Likewise.
	(grow_pptrtab): Likewise.
	* ctf-open.c (ctf_cuname_set): Likewise.
	(ctf_import): Likewise.
	(ctf_parent_name_set): Likewise.
	(ctf_setmodel): Likewise.
	* ctf-serialize.c (ctf_gzwrite): Likewise.
	(ctf_serialize): Likewise.
	(symtypetab_density): Likewise.
	* ctf-string.c (ctf_str_move_pending): Likewise.
	* ctf-types.c (ctf_array_info): Likewise.
	(ctf_func_type_info): Likewise.
	(ctf_member_count): Likewise.
	(ctf_member_info): Likewise.
	(ctf_member_next): Likewise.
	(ctf_type_align): Likewise.
	(ctf_type_encoding): Likewise.
	(ctf_type_rvisit): Likewise.
	(ctf_type_size): Likewise.

Signed-off-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
Co-Authored-By: Yvan ROUX <yvan.roux@foss.st.com>
---
 libctf/ctf-create.c    | 137 ++++++++++++++++++++++++++++++++---------
 libctf/ctf-dedup.c     | 117 +++++++++++++++++++++++++----------
 libctf/ctf-dump.c      |  40 +++++++++---
 libctf/ctf-labels.c    |  15 +++--
 libctf/ctf-link.c      |  69 ++++++++++++++++-----
 libctf/ctf-lookup.c    |  15 ++++-
 libctf/ctf-open.c      |  33 +++++++---
 libctf/ctf-serialize.c |  43 +++++++++----
 libctf/ctf-string.c    |   5 +-
 libctf/ctf-types.c     |  78 +++++++++++++++++------
 10 files changed, 420 insertions(+), 132 deletions(-)

diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 6b342dc64a2..91c466519f7 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -60,7 +60,10 @@ ctf_grow_ptrtab (ctf_dict_t *fp)
 
       if ((new_ptrtab = realloc (fp->ctf_ptrtab,
 				 new_ptrtab_len * sizeof (uint32_t))) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	{
+	  ctf_set_errno (fp, ENOMEM);
+	  return -1;
+	}
 
       fp->ctf_ptrtab = new_ptrtab;
       memset (fp->ctf_ptrtab + fp->ctf_ptrtab_len, 0,
@@ -87,7 +90,8 @@ ctf_grow_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vlen)
 				dtd->dtd_vlen_alloc * 2)) == NULL)
     {
       dtd->dtd_vlen = old;
-      return (ctf_set_errno (fp, ENOMEM));
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
     }
   memset (dtd->dtd_vlen + dtd->dtd_vlen_alloc, 0, dtd->dtd_vlen_alloc);
   dtd->dtd_vlen_alloc *= 2;
@@ -197,7 +201,10 @@ int
 ctf_update (ctf_dict_t *fp)
 {
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return -1;
+    }
 
   fp->ctf_dtoldid = fp->ctf_typemax;
   return 0;
@@ -391,10 +398,16 @@ ctf_rollback (ctf_dict_t *fp, ctf_snapshot_id_t id)
   ctf_dvdef_t *dvd, *nvd;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return -1;
+    }
 
   if (fp->ctf_snapshot_lu >= id.snapshot_id)
-    return (ctf_set_errno (fp, ECTF_OVERROLLBACK));
+    {
+      ctf_set_errno (fp, ECTF_OVERROLLBACK);
+      return -1;
+    }
 
   for (dtd = ctf_list_next (&fp->ctf_dtdefs); dtd != NULL; dtd = ntd)
     {
@@ -723,11 +736,17 @@ ctf_set_array (ctf_dict_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
   ctf_array_t *vlen;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return -1;
+    }
 
   if (dtd == NULL
       || LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info) != CTF_K_ARRAY)
-    return (ctf_set_errno (fp, ECTF_BADID));
+    {
+      ctf_set_errno (fp, ECTF_BADID);
+      return -1;
+    }
 
   vlen = (ctf_array_t *) dtd->dtd_vlen;
   fp->ctf_flags |= LCTF_DIRTY;
@@ -1055,23 +1074,38 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
   uint32_t kind, vlen, root;
 
   if (name == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return -1;
+    }
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return -1;
+    }
 
   if (dtd == NULL)
-    return (ctf_set_errno (fp, ECTF_BADID));
+    {
+      ctf_set_errno (fp, ECTF_BADID);
+      return -1;
+    }
 
   kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
   root = LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info);
   vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
 
   if (kind != CTF_K_ENUM)
-    return (ctf_set_errno (fp, ECTF_NOTENUM));
+    {
+      ctf_set_errno (fp, ECTF_NOTENUM);
+      return -1;
+    }
 
   if (vlen == CTF_MAX_VLEN)
-    return (ctf_set_errno (fp, ECTF_DTFULL));
+    {
+      ctf_set_errno (fp, ECTF_DTFULL);
+      return -1;
+    }
 
   old_vlen = dtd->dtd_vlen;
   if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0)
@@ -1090,7 +1124,10 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
 
   for (i = 0; i < vlen; i++)
     if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
-      return (ctf_set_errno (fp, ECTF_DUPLICATE));
+      {
+	ctf_set_errno (fp, ECTF_DUPLICATE);
+	return -1;
+      }
 
   en[i].cte_name = ctf_str_add_pending (fp, name, &en[i].cte_name);
   en[i].cte_value = value;
@@ -1119,10 +1156,16 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   ctf_lmember_t *memb;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return -1;
+    }
 
   if (dtd == NULL)
-    return (ctf_set_errno (fp, ECTF_BADID));
+    {
+      ctf_set_errno (fp, ECTF_BADID);
+      return -1;
+    }
 
   if (name != NULL && name[0] == '\0')
     name = NULL;
@@ -1132,10 +1175,16 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
 
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
-    return (ctf_set_errno (fp, ECTF_NOTSOU));
+    {
+      ctf_set_errno (fp, ECTF_NOTSOU);
+      return -1;
+    }
 
   if (vlen == CTF_MAX_VLEN)
-    return (ctf_set_errno (fp, ECTF_DTFULL));
+    {
+      ctf_set_errno (fp, ECTF_DTFULL);
+      return -1;
+    }
 
   old_vlen = dtd->dtd_vlen;
   if (ctf_grow_vlen (fp, dtd, sizeof (ctf_lmember_t) * (vlen + 1)) < 0)
@@ -1156,7 +1205,10 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
     {
       for (i = 0; i < vlen; i++)
 	if (strcmp (ctf_strptr (fp, memb[i].ctlm_name), name) == 0)
-	  return (ctf_set_errno (fp, ECTF_DUPLICATE));
+	  {
+	    ctf_set_errno (fp, ECTF_DUPLICATE);
+	    return -1;
+	  }
     }
 
   if ((msize = ctf_type_size (fp, type)) < 0 ||
@@ -1212,7 +1264,8 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
 			      "incomplete type %lx to struct %lx without "
 			      "specifying explicit offset\n"),
 			    name ? name : _("(unnamed member)"), type, souid);
-	      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+	      ctf_set_errno (fp, ECTF_INCOMPLETE);
+	      return -1;
 	    }
 
 	  if (ctf_type_encoding (fp, ltype, &linfo) == 0)
@@ -1285,7 +1338,10 @@ ctf_add_member_encoded (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   int otype = type;
 
   if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) && (kind != CTF_K_ENUM))
-    return (ctf_set_errno (fp, ECTF_NOTINTFP));
+    {
+      ctf_set_errno (fp, ECTF_NOTINTFP);
+      return -1;
+    }
 
   if ((type = ctf_add_slice (fp, CTF_ADD_NONROOT, otype, &encoding)) == CTF_ERR)
     return -1;			/* errno is set for us.  */
@@ -1307,10 +1363,16 @@ ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
   ctf_dict_t *tmp = fp;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return -1;
+    }
 
   if (ctf_dvd_lookup (fp, name) != NULL)
-    return (ctf_set_errno (fp, ECTF_DUPLICATE));
+    {
+      ctf_set_errno (fp, ECTF_DUPLICATE);
+      return -1;
+    }
 
   if (ctf_lookup_by_id (&tmp, ref) == NULL)
     return -1;			/* errno is set for us.  */
@@ -1321,12 +1383,16 @@ ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
     return -1;
 
   if ((dvd = malloc (sizeof (ctf_dvdef_t))) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+    {
+      ctf_set_errno (fp, EAGAIN);
+      return -1;
+    }
 
   if (name != NULL && (dvd->dvd_name = strdup (name)) == NULL)
     {
       free (dvd);
-      return (ctf_set_errno (fp, EAGAIN));
+      ctf_set_errno (fp, EAGAIN);
+      return -1;
     }
   dvd->dvd_type = ref;
   dvd->dvd_snapshots = fp->ctf_snapshots;
@@ -1350,25 +1416,38 @@ ctf_add_funcobjt_sym (ctf_dict_t *fp, int is_function, const char *name, ctf_id_
   ctf_dynhash_t *h = is_function ? fp->ctf_funchash : fp->ctf_objthash;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return -1;
+    }
 
   if (ctf_dynhash_lookup (fp->ctf_objthash, name) != NULL ||
       ctf_dynhash_lookup (fp->ctf_funchash, name) != NULL)
-    return (ctf_set_errno (fp, ECTF_DUPLICATE));
+    {
+      ctf_set_errno (fp, ECTF_DUPLICATE);
+      return -1;
+    }
 
   if (ctf_lookup_by_id (&tmp, id) == NULL)
     return -1;                                  /* errno is set for us.  */
 
   if (is_function && ctf_type_kind (fp, id) != CTF_K_FUNCTION)
-    return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    {
+      ctf_set_errno (fp, ECTF_NOTFUNC);
+      return -1;
+    }
 
   if ((dupname = strdup (name)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    {
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
+    }
 
   if (ctf_dynhash_insert (h, dupname, (void *) (uintptr_t) id) < 0)
     {
       free (dupname);
-      return (ctf_set_errno (fp, ENOMEM));
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
     }
   return 0;
 }
diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c
index 5fdddfd0b54..f1c056caede 100644
--- a/libctf/ctf-dedup.c
+++ b/libctf/ctf-dedup.c
@@ -378,7 +378,10 @@ ctf_dedup_atoms_init (ctf_dict_t *fp)
       if ((fp->ctf_dedup_atoms_alloc
 	   = ctf_dynset_create (htab_hash_string, htab_eq_string,
 				free)) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	{
+	  ctf_set_errno (fp, ENOMEM);
+	  return -1;
+	}
     }
   fp->ctf_dedup_atoms = fp->ctf_dedup_atoms_alloc;
   return 0;
@@ -543,7 +546,10 @@ ctf_dedup_record_origin (ctf_dict_t *fp, int input_num, const char *decorated,
 
   if (populate_origin)
     if (ctf_dynhash_cinsert (d->cd_struct_origin, decorated, origin) < 0)
-      return ctf_set_errno (fp, errno);
+      {
+	ctf_set_errno (fp, errno);
+	return -1;
+      }
   return 0;
 }
 
@@ -1185,7 +1191,10 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
     }
   else
     if (ctf_dynhash_cinsert (d->cd_output_mapping_guard, id, hval) < 0)
-      return ctf_set_errno (fp, errno);
+      {
+	ctf_set_errno (fp, errno);
+	return -1;
+      }
 #endif
 
   /* Record the type in the output mapping: if this is the first time this type
@@ -1197,17 +1206,24 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
 				      hval)) == NULL)
     {
       if (ctf_dynhash_cinsert (d->cd_output_first_gid, hval, id) < 0)
-	return ctf_set_errno (fp, errno);
+	{
+	  ctf_set_errno (fp, errno);
+	  return -1;
+	}
 
       if ((type_ids = ctf_dynset_create (htab_hash_pointer,
 					 htab_eq_pointer,
 					 NULL)) == NULL)
-	return ctf_set_errno (fp, errno);
+	{
+	  ctf_set_errno (fp, errno);
+	  return -1;
+	}
       if (ctf_dynhash_insert (d->cd_output_mapping, (void *) hval,
 			      type_ids) < 0)
 	{
 	  ctf_dynset_destroy (type_ids);
-	  return ctf_set_errno (fp, errno);
+	  ctf_set_errno (fp, errno);
+	  return -1;
 	}
     }
 #ifdef ENABLE_LIBCTF_HASH_DEBUGGING
@@ -1248,7 +1264,10 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
 	    }
 	}
       if (err != ECTF_NEXT_END)
-	return ctf_set_errno (fp, err);
+	{
+	  ctf_set_errno (fp, err);
+	  return -1;
+	}
     }
 #endif
 
@@ -1256,7 +1275,10 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
      don't waste time reinserting the same keys in that case.  */
   if (!ctf_dynset_exists (type_ids, id, NULL)
       && ctf_dynset_insert (type_ids, id) < 0)
-    return ctf_set_errno (fp, errno);
+    {
+      ctf_set_errno (fp, errno);
+      return -1;
+    }
 
   /* The rest only needs to happen for types with names.  */
   if (!decorated_name)
@@ -1273,12 +1295,16 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
       if ((name_counts = ctf_dynhash_create (ctf_hash_string,
 					     ctf_hash_eq_string,
 					     NULL, NULL)) == NULL)
-	  return ctf_set_errno (fp, errno);
+	{
+	  ctf_set_errno (fp, errno);
+	  return -1;
+	}
       if (ctf_dynhash_cinsert (d->cd_name_counts, decorated_name,
 			       name_counts) < 0)
 	{
 	  ctf_dynhash_destroy (name_counts);
-	  return ctf_set_errno (fp, errno);
+	  ctf_set_errno (fp, errno);
+	  return -1;
 	}
     }
 
@@ -1287,7 +1313,10 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
 
   if (ctf_dynhash_cinsert (name_counts, hval,
 			   (const void *) (uintptr_t) (count + 1)) < 0)
-    return ctf_set_errno (fp, errno);
+    {
+      ctf_set_errno (fp, errno);
+      return -1;
+    }
 
   return 0;
 }
@@ -1339,10 +1368,11 @@ ctf_dedup_mark_conflicting_hash (ctf_dict_t *fp, const char *hval)
 	  return -1;				/* errno is set for us.  */
 	}
     }
-  if (err != ECTF_NEXT_END)
-    return ctf_set_errno (fp, err);
+  if (err == ECTF_NEXT_END)
+    return 0;
 
-  return 0;
+  ctf_set_errno (fp, err);
+  return -1;
 }
 
 /* Look up a type kind from the output mapping, given a type hash value.  */
@@ -1366,7 +1396,8 @@ ctf_dedup_hash_kind (ctf_dict_t *fp, ctf_dict_t **inputs, const char *hash)
   if (!type_ids)
     {
       ctf_dprintf ("Looked up type kind by nonexistent hash %s.\n", hash);
-      return ctf_set_errno (fp, ECTF_INTERNAL);
+      ctf_set_errno (fp, ECTF_INTERNAL);
+      return -1;
     }
   id = ctf_dynset_lookup_any (type_ids);
   if (!ctf_assert (fp, id))
@@ -1585,7 +1616,8 @@ ctf_dedup_detect_name_ambiguity (ctf_dict_t *fp, ctf_dict_t **inputs)
 
  iterr:
   ctf_err_warn (fp, 0, err, _("iteration failed: %s"), gettext (whaterr));
-  return ctf_set_errno (fp, err);
+  ctf_set_errno (fp, err);
+  return -1;
 
  assert_err:
   ctf_next_destroy (i);
@@ -1683,7 +1715,8 @@ ctf_dedup_init (ctf_dict_t *fp)
  oom:
   ctf_err_warn (fp, 0, ENOMEM, _("ctf_dedup_init: cannot initialize: "
 				 "out of memory"));
-  return ctf_set_errno (fp, ENOMEM);
+  ctf_set_errno (fp, ENOMEM);
+  return -1;
 }
 
 /* No ctf_dedup calls are allowed after this call other than starting a new
@@ -1784,7 +1817,8 @@ ctf_dedup_multiple_input_dicts (ctf_dict_t *output, ctf_dict_t **inputs,
     {
       ctf_err_warn (output, 0, err, _("iteration error "
 				      "propagating conflictedness"));
-      return ctf_set_errno (output, err);
+      ctf_set_errno (output, err);
+      return -1;
     }
 
   if (multiple)
@@ -1879,7 +1913,8 @@ ctf_dedup_conflictify_unshared (ctf_dict_t *output, ctf_dict_t **inputs)
  iterr:
   ctf_dynset_destroy (to_mark);
   ctf_err_warn (output, 0, err, _("conflictifying unshared types"));
-  return ctf_set_errno (output, err);
+  ctf_set_errno (output, err);
+  return -1;
 }
 
 /* The core deduplicator.  Populate cd_output_mapping in the output ctf_dedup
@@ -2219,7 +2254,8 @@ ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
     {
       ctf_err_warn (output, 0, ECTF_INTERNAL,
 		    _("looked up type kind by nonexistent hash %s"), hval);
-      return ctf_set_errno (output, ECTF_INTERNAL);
+      ctf_set_errno (output, ECTF_INTERNAL);
+      return -1;
     }
 
   /* Have we seen this type before?  */
@@ -2237,7 +2273,8 @@ ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
 	{
 	  ctf_err_warn (output, 0, ENOMEM,
 			_("out of memory tracking already-visited types"));
-	  return ctf_set_errno (output, ENOMEM);
+	  ctf_set_errno (output, ENOMEM);
+	  return -1;
 	}
     }
 
@@ -2274,7 +2311,8 @@ ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
   if (err != ECTF_NEXT_END)
     {
       ctf_err_warn (output, 0, err, _("cannot walk conflicted type"));
-      return ctf_set_errno (output, err);
+      ctf_set_errno (output, err);
+      return -1;
     }
 
   return 0;
@@ -2376,7 +2414,10 @@ ctf_dedup_walk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
   if ((already_visited = ctf_dynset_create (htab_hash_string,
 					    htab_eq_string,
 					    NULL)) == NULL)
-    return ctf_set_errno (output, ENOMEM);
+    {
+      ctf_set_errno (output, ENOMEM);
+      return -1;
+    }
 
   sort_arg.inputs = inputs;
   sort_arg.ninputs = ninputs;
@@ -2664,7 +2705,8 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
 	      ctf_err_warn (output, 0, err,
 			    _("cannot create per-CU CTF archive for CU %s"),
 			    ctf_link_input_name (input));
-	      return ctf_set_errno (output, err);
+	      ctf_set_errno (output, err);
+	      return -1;
 	    }
 
 	  ctf_import_unref (target, output);
@@ -2687,7 +2729,8 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
       ctf_err_warn (output, 0, ctf_errno (input),
 		    _("%s: lookup failure for type %lx"),
 		    ctf_link_input_name (real_input), type);
-      return ctf_set_errno (output, ctf_errno (input));
+      ctf_set_errno (output, ctf_errno (input));
+      return -1;
     }
 
   name = ctf_strraw (real_input, tp->ctt_name);
@@ -2765,7 +2808,8 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
 			      ctf_link_input_name (input), input_num, name,
 			      type);
 		ctf_next_destroy (i);
-		return ctf_set_errno (output, ctf_errno (target));
+		ctf_set_errno (output, ctf_errno (target));
+		return -1;
 	      }
 	  }
 	if (ctf_errno (input) != ECTF_NEXT_END)
@@ -2921,7 +2965,8 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
       ctf_err_warn (output, 0, ECTF_CORRUPT, _("%s: unknown type kind for "
 					       "input type %lx"),
 		    ctf_link_input_name (input), type);
-      return ctf_set_errno (output, ECTF_CORRUPT);
+      ctf_set_errno (output, ECTF_CORRUPT);
+      return -1;
     }
 
   if (!emission_hashed
@@ -2931,7 +2976,8 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
     {
       ctf_err_warn (output, 0, ENOMEM, _("out of memory tracking deduplicated "
 					 "global type IDs"));
-	return ctf_set_errno (output, ENOMEM);
+      ctf_set_errno (output, ENOMEM);
+      return -1;
     }
 
   if (!emission_hashed && new_type != 0)
@@ -2944,21 +2990,24 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
  oom_hash:
   ctf_err_warn (output, 0, ENOMEM, _("out of memory creating emission-tracking "
 				     "hashes"));
-  return ctf_set_errno (output, ENOMEM);
+  ctf_set_errno (output, ENOMEM);
+  return -1;
 
  err_input:
   ctf_err_warn (output, 0, ctf_errno (input),
 		_("%s (%i): while emitting deduplicated %s, error getting "
 		  "input type %lx"), ctf_link_input_name (input),
 		input_num, errtype, type);
-  return ctf_set_errno (output, ctf_errno (input));
+  ctf_set_errno (output, ctf_errno (input));
+  return -1;
  err_target:
   ctf_err_warn (output, 0, ctf_errno (target),
 		_("%s (%i): while emitting deduplicated %s, error emitting "
 		  "target type from input type %lx"),
 		ctf_link_input_name (input), input_num,
 		errtype, type);
-  return ctf_set_errno (output, ctf_errno (target));
+  ctf_set_errno (output, ctf_errno (target));
+  return -1;
 }
 
 /* Traverse the cd_emission_struct_members and emit the members of all
@@ -3051,11 +3100,13 @@ ctf_dedup_emit_struct_members (ctf_dict_t *output, ctf_dict_t **inputs,
   ctf_err_warn (output, 0, ctf_errno (err_fp),
 		_("%s (%i): error emitting members for structure type %lx"),
 		ctf_link_input_name (input_fp), input_num, err_type);
-  return ctf_set_errno (output, ctf_errno (err_fp));
+  ctf_set_errno (output, ctf_errno (err_fp));
+  return -1;
  iterr:
   ctf_err_warn (output, 0, err, _("iteration failure emitting "
 				  "structure members"));
-  return ctf_set_errno (output, err);
+  ctf_set_errno (output, err);
+  return -1;
 }
 
 /* Emit deduplicated types into the outputs.  The shared type repository is
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index 686951a9869..b5de3c76709 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -56,7 +56,10 @@ ctf_dump_append (ctf_dump_state_t *state, char *str)
   ctf_dump_item_t *cdi;
 
   if ((cdi = malloc (sizeof (struct ctf_dump_item))) == NULL)
-    return (ctf_set_errno (state->cds_fp, ENOMEM));
+    {
+      ctf_set_errno (state->cds_fp, ENOMEM);
+      return -1;
+    }
 
   cdi->cdi_item = str;
   ctf_list_append (&state->cds_items, cdi);
@@ -261,7 +264,8 @@ ctf_dump_header_strfield (ctf_dict_t *fp, ctf_dump_state_t *state,
   return 0;
 
  err:
-  return (ctf_set_errno (fp, errno));
+  ctf_set_errno (fp, errno);
+  return -1;
 }
 
 /* Dump one section-offset field from the file header into the cds_items.  */
@@ -281,7 +285,8 @@ ctf_dump_header_sectfield (ctf_dict_t *fp, ctf_dump_state_t *state,
   return 0;
 
  err:
-  return (ctf_set_errno (fp, errno));
+  ctf_set_errno (fp, errno);
+  return -1;
 }
 
 /* Dump the file header into the cds_items.  */
@@ -398,7 +403,8 @@ ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
   return 0;
  err:
   free (flagstr);
-  return (ctf_set_errno (fp, errno));
+  ctf_set_errno (fp, errno);
+  return -1;
 }
 
 /* Dump a single label into the cds_items.  */
@@ -412,7 +418,10 @@ ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
   ctf_dump_state_t *state = arg;
 
   if (asprintf (&str, "%s -> ", name) < 0)
-    return (ctf_set_errno (state->cds_fp, errno));
+    {
+      ctf_set_errno (state->cds_fp, errno);
+      return -1;
+    }
 
   if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type,
 				       CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
@@ -487,7 +496,10 @@ ctf_dump_var (const char *name, ctf_id_t type, void *arg)
   ctf_dump_state_t *state = arg;
 
   if (asprintf (&str, "%s -> ", name) < 0)
-    return (ctf_set_errno (state->cds_fp, errno));
+    {
+      ctf_set_errno (state->cds_fp, errno);
+      return -1;
+    }
 
   if ((typestr = ctf_dump_format_type (state->cds_fp, type,
 				       CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
@@ -540,7 +552,8 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
  oom:
   free (typestr);
   free (bit);
-  return (ctf_set_errno (state->cdm_fp, errno));
+  ctf_set_errno (state->cdm_fp, errno);
+  return -1;
 }
 
 /* Report the number of digits in the hexadecimal representation of a type
@@ -569,7 +582,10 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
 
   /* Indent neatly.  */
   if (asprintf (&indent, "    %*s", type_hex_digits (id), "") < 0)
-    return (ctf_set_errno (state->cds_fp, ENOMEM));
+    {
+      ctf_set_errno (state->cds_fp, ENOMEM);
+      return -1;
+    }
 
   /* Dump the type itself.  */
   if ((str = ctf_dump_format_type (state->cds_fp, id,
@@ -654,7 +670,8 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
  oom:
   free (indent);
   free (str);
-  return ctf_set_errno (state->cds_fp, ENOMEM);
+  ctf_set_errno (state->cds_fp, ENOMEM);
+  return -1;
 }
 
 /* Dump the string table into the cds_items.  */
@@ -671,7 +688,10 @@ ctf_dump_str (ctf_dict_t *fp, ctf_dump_state_t *state)
       if (asprintf (&str, "0x%lx: %s",
 		    (unsigned long) (s - fp->ctf_str[CTF_STRTAB_0].cts_strs),
 		    s) < 0)
-	return (ctf_set_errno (fp, errno));
+	{
+	  ctf_set_errno (fp, errno);
+	  return -1;
+	}
       ctf_dump_append (state, str);
       s += strlen (s) + 1;
     }
diff --git a/libctf/ctf-labels.c b/libctf/ctf-labels.c
index 16b111b14df..8aa2edc1847 100644
--- a/libctf/ctf-labels.c
+++ b/libctf/ctf-labels.c
@@ -74,7 +74,10 @@ ctf_label_iter (ctf_dict_t *fp, ctf_label_f *func, void *arg)
     return -1;			/* errno is set for us.  */
 
   if (num_labels == 0)
-    return (ctf_set_errno (fp, ECTF_NOLABELDATA));
+    {
+      ctf_set_errno (fp, ECTF_NOLABELDATA);
+      return -1;
+    }
 
   for (i = 0; i < num_labels; i++, ctlp++)
     {
@@ -84,7 +87,8 @@ ctf_label_iter (ctf_dict_t *fp, ctf_label_f *func, void *arg)
 	  ctf_err_warn (fp, 0, ECTF_CORRUPT,
 			"failed to decode label %u with type %u",
 			ctlp->ctl_label, ctlp->ctl_type);
-	  return (ctf_set_errno (fp, ECTF_CORRUPT));
+	  ctf_set_errno (fp, ECTF_CORRUPT);
+	  return -1;
 	}
 
       linfo.ctb_type = ctlp->ctl_type;
@@ -133,8 +137,9 @@ ctf_label_info (ctf_dict_t *fp, const char *lname, ctf_lblinfo_t *linfo)
   if ((rc = ctf_label_iter (fp, label_info_cb, &cb_arg)) < 0)
     return rc;
 
-  if (rc != 1)
-    return (ctf_set_errno (fp, ECTF_NOLABEL));
+  if (rc == 1)
+    return 0;
 
-  return 0;
+  ctf_set_errno (fp, ECTF_NOLABEL);
+  return -1;
 }
diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c
index 9babec2aa37..97beb36be83 100644
--- a/libctf/ctf-link.c
+++ b/libctf/ctf-link.c
@@ -142,7 +142,8 @@ ctf_link_add_ctf_internal (ctf_dict_t *fp, ctf_archive_t *ctf,
  oom1:
   free (filename);
  oom:
-  return ctf_set_errno (fp, ENOMEM);
+  ctf_set_errno (fp, ENOMEM);
+  return -1;
 }
 
 /* Add a file, memory buffer, or unopened file (by name) to a link.
@@ -173,12 +174,18 @@ ctf_link_add (ctf_dict_t *fp, ctf_archive_t *ctf, const char *name,
 	      void *buf _libctf_unused_, size_t n _libctf_unused_)
 {
   if (buf)
-    return (ctf_set_errno (fp, ECTF_NOTYET));
+    {
+      ctf_set_errno (fp, ECTF_NOTYET);
+      return -1;
+    }
 
   if (!((ctf && name && !buf)
 	|| (name && !buf && !ctf)
 	|| (buf && name && !ctf)))
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return -1;
+    }
 
   /* We can only lazily open files if libctf.so is in use rather than
      libctf-nobfd.so.  This is a little tricky: in shared libraries, we can use
@@ -187,21 +194,33 @@ ctf_link_add (ctf_dict_t *fp, ctf_archive_t *ctf, const char *name,
 
 #if defined (PIC)
   if (!buf && !ctf && name && !ctf_open)
-    return (ctf_set_errno (fp, ECTF_NEEDSBFD));
+    {
+      ctf_set_errno (fp, ECTF_NEEDSBFD);
+      return -1;
+    }
 #elif NOBFD
   if (!buf && !ctf && name)
-    return (ctf_set_errno (fp, ECTF_NEEDSBFD));
+    {
+      ctf_set_errno (fp, ECTF_NEEDSBFD);
+      return -1;
+    }
 #endif
 
   if (fp->ctf_link_outputs)
-    return (ctf_set_errno (fp, ECTF_LINKADDEDLATE));
+    {
+      ctf_set_errno (fp, ECTF_LINKADDEDLATE);
+      return -1;
+    }
   if (fp->ctf_link_inputs == NULL)
     fp->ctf_link_inputs = ctf_dynhash_create (ctf_hash_string,
 					      ctf_hash_eq_string, free,
 					      ctf_link_input_close);
 
   if (fp->ctf_link_inputs == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    {
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
+    }
 
   return ctf_link_add_ctf_internal (fp, ctf, NULL, name);
 }
@@ -378,7 +397,10 @@ ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
 
   /* Mappings cannot be set up if per-CU output dicts already exist.  */
   if (fp->ctf_link_outputs && ctf_dynhash_elements (fp->ctf_link_outputs) != 0)
-      return (ctf_set_errno (fp, ECTF_LINKADDEDLATE));
+    {
+      ctf_set_errno (fp, ECTF_LINKADDEDLATE);
+      return -1;
+    }
 
   if (fp->ctf_link_in_cu_mapping == NULL)
     fp->ctf_link_in_cu_mapping = ctf_dynhash_create (ctf_hash_string,
@@ -582,7 +604,10 @@ ctf_link_one_variable (ctf_dict_t *fp, ctf_dict_t *in_fp, const char *name,
 
   if (check_variable (name, per_cu_out_fp, dst_type, &dvd))
     if (ctf_add_variable (per_cu_out_fp, name, dst_type) < 0)
-      return (ctf_set_errno (fp, ctf_errno (per_cu_out_fp)));
+      {
+	ctf_set_errno (fp, ctf_errno (per_cu_out_fp));
+	return -1;
+      }
   return 0;
 }
 
@@ -915,7 +940,10 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
 	    }
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
-	return ctf_set_errno (fp, ctf_errno (inputs[i]));
+	{
+	  ctf_set_errno (fp, ctf_errno (inputs[i]));
+	  return -1;
+	}
 
       /* Next the symbols.  We integrate data symbols even though the compiler
 	 is currently doing the same, to allow the compiler to stop in
@@ -930,7 +958,10 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
 	    }
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
-	return ctf_set_errno (fp, ctf_errno (inputs[i]));
+	{
+	  ctf_set_errno (fp, ctf_errno (inputs[i]));
+	  return -1;
+	}
 
       /* Finally the function symbols.  */
 
@@ -943,7 +974,10 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
 	    }
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
-	return ctf_set_errno (fp, ctf_errno (inputs[i]));
+	{
+	  ctf_set_errno (fp, ctf_errno (inputs[i]));
+	  return -1;
+	}
     }
   return 0;
 }
@@ -1070,7 +1104,8 @@ ctf_link_deduplicating_one_symtypetab (ctf_dict_t *fp, ctf_dict_t *input,
 			_("symbol %s in input file %s found conflicting "
 			  "even when trying in per-CU dict."), name,
 			ctf_unnamed_cuname (input));
-	  return (ctf_set_errno (fp, ECTF_DUPLICATE));
+	  ctf_set_errno (fp, ECTF_DUPLICATE);
+	  return -1;
 	}
     }
   if (ctf_errno (input) != ECTF_NEXT_END)
@@ -1330,7 +1365,8 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
     {
       ctf_err_warn (fp, 0, err, _("iteration error in CU-mapped deduplicating "
 				  "link"));
-      return ctf_set_errno (fp, err);
+      ctf_set_errno (fp, err);
+      return -1;
     }
 
   return 0;
@@ -1503,7 +1539,10 @@ ctf_link (ctf_dict_t *fp, int flags)
 					       ctf_dict_close);
 
   if (fp->ctf_link_outputs == NULL)
-    return ctf_set_errno (fp, ENOMEM);
+    {
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
+    }
 
   fp->ctf_flags |= LCTF_LINKING;
   ctf_link_deduplicating (fp);
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index c65849118cb..7ad07e3bf84 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -30,7 +30,10 @@ grow_pptrtab (ctf_dict_t *fp, size_t new_len)
 
   if ((new_pptrtab = realloc (fp->ctf_pptrtab, sizeof (uint32_t)
 			      * new_len)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    {
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
+    }
 
   fp->ctf_pptrtab = new_pptrtab;
 
@@ -1046,7 +1049,10 @@ ctf_func_info (ctf_dict_t *fp, unsigned long symidx, ctf_funcinfo_t *fip)
     return -1;					/* errno is set for us.  */
 
   if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
-    return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    {
+      ctf_set_errno (fp, ECTF_NOTFUNC);
+      return -1;
+    }
 
   return ctf_func_type_info (fp, type, fip);
 }
@@ -1064,7 +1070,10 @@ ctf_func_args (ctf_dict_t *fp, unsigned long symidx, uint32_t argc,
     return -1;					/* errno is set for us.  */
 
   if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
-    return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    {
+      ctf_set_errno (fp, ECTF_NOTFUNC);
+      return -1;
+    }
 
   return ctf_func_type_args (fp, type, argc, argv);
 }
diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c
index 35f635b6559..fa5f2aab732 100644
--- a/libctf/ctf-open.c
+++ b/libctf/ctf-open.c
@@ -1935,7 +1935,10 @@ ctf_parent_name_set (ctf_dict_t *fp, const char *name)
     free (fp->ctf_dynparname);
 
   if ((fp->ctf_dynparname = strdup (name)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    {
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
+    }
   fp->ctf_parname = fp->ctf_dynparname;
   return 0;
 }
@@ -1956,7 +1959,10 @@ ctf_cuname_set (ctf_dict_t *fp, const char *name)
     free (fp->ctf_dyncuname);
 
   if ((fp->ctf_dyncuname = strdup (name)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    {
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
+    }
   fp->ctf_cuname = fp->ctf_dyncuname;
   return 0;
 }
@@ -1969,10 +1975,16 @@ int
 ctf_import (ctf_dict_t *fp, ctf_dict_t *pfp)
 {
   if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return -1;
+    }
 
   if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel)
-    return (ctf_set_errno (fp, ECTF_DMODEL));
+    {
+      ctf_set_errno (fp, ECTF_DMODEL);
+      return -1;
+    }
 
   if (fp->ctf_parent && !fp->ctf_parent_unreffed)
     ctf_dict_close (fp->ctf_parent);
@@ -2008,10 +2020,16 @@ int
 ctf_import_unref (ctf_dict_t *fp, ctf_dict_t *pfp)
 {
   if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return -1;
+    }
 
   if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel)
-    return (ctf_set_errno (fp, ECTF_DMODEL));
+    {
+      ctf_set_errno (fp, ECTF_DMODEL);
+      return -1;
+    }
 
   if (fp->ctf_parent && !fp->ctf_parent_unreffed)
     ctf_dict_close (fp->ctf_parent);
@@ -2052,7 +2070,8 @@ ctf_setmodel (ctf_dict_t *fp, int model)
 	}
     }
 
-  return (ctf_set_errno (fp, EINVAL));
+  ctf_set_errno (fp, EINVAL);
+  return -1;
 }
 
 /* Return the data model constant for the CTF dict.  */
diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
index ba830a2b095..258dec62366 100644
--- a/libctf/ctf-serialize.c
+++ b/libctf/ctf-serialize.c
@@ -123,7 +123,10 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 
       if ((linker_known = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
 					      NULL, NULL)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	{
+	  ctf_set_errno (fp, ENOMEM);
+	  return -1;
+	}
 
       while ((err = ctf_dynhash_cnext (symfp->ctf_dynsyms, &i,
 				       &name, &ctf_sym)) == 0)
@@ -147,7 +150,8 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 	  if (ctf_dynhash_cinsert (linker_known, name, ctf_sym) < 0)
 	    {
 	      ctf_dynhash_destroy (linker_known);
-	      return (ctf_set_errno (fp, ENOMEM));
+	      ctf_set_errno (fp, ENOMEM);
+	      return -1;
 	    }
 	}
       if (err != ECTF_NEXT_END)
@@ -155,7 +159,8 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols during "
 				  "serialization"));
 	  ctf_dynhash_destroy (linker_known);
-	  return (ctf_set_errno (fp, err));
+	  ctf_set_errno (fp, err);
+	  return -1;
 	}
     }
 
@@ -219,7 +224,8 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
       ctf_err_warn (fp, 0, err, _("iterating over CTF symtypetab during "
 				  "serialization"));
       ctf_dynhash_destroy (linker_known);
-      return (ctf_set_errno (fp, err));
+      ctf_set_errno (fp, err);
+      return -1;
     }
 
   if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
@@ -236,7 +242,8 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols "
 				      "during CTF serialization"));
 	  ctf_dynhash_destroy (linker_known);
-	  return (ctf_set_errno (fp, err));
+	  ctf_set_errno (fp, err);
+	  return -1;
 	}
     }
 
@@ -970,7 +977,10 @@ ctf_serialize (ctf_dict_t *fp)
   memset (&symstate, 0, sizeof (emit_symtypetab_state_t));
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return -1;
+    }
 
   /* Update required?  */
   if (!(fp->ctf_flags & LCTF_DIRTY))
@@ -1026,7 +1036,10 @@ ctf_serialize (ctf_dict_t *fp)
   buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
 
   if ((buf = malloc (buf_size)) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+    {
+      ctf_set_errno (fp, EAGAIN);
+      return -1;
+    }
 
   memcpy (buf, &hdr, sizeof (ctf_header_t));
   t = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_objtoff;
@@ -1106,7 +1119,8 @@ ctf_serialize (ctf_dict_t *fp)
 				       1, &err)) == NULL)
     {
       free (buf);
-      return (ctf_set_errno (fp, err));
+      ctf_set_errno (fp, err);
+      return -1;
     }
 
   (void) ctf_setmodel (nfp, ctf_getmodel (fp));
@@ -1221,7 +1235,8 @@ ctf_serialize (ctf_dict_t *fp)
 
 oom:
   free (buf);
-  return (ctf_set_errno (fp, EAGAIN));
+  ctf_set_errno (fp, EAGAIN);
+  return -1;
 err:
   free (buf);
   return -1;					/* errno is set for us.  */
@@ -1248,7 +1263,10 @@ ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
   while (resid != 0)
     {
       if ((len = gzwrite (fd, buf, resid)) <= 0)
-	return (ctf_set_errno (fp, errno));
+	{
+	  ctf_set_errno (fp, errno);
+	  return -1;
+	}
       resid -= len;
       buf += len;
     }
@@ -1258,7 +1276,10 @@ ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
   while (resid != 0)
     {
       if ((len = gzwrite (fd, buf, resid)) <= 0)
-	return (ctf_set_errno (fp, errno));
+	{
+	  ctf_set_errno (fp, errno);
+	  return -1;
+	}
       resid -= len;
       buf += len;
     }
diff --git a/libctf/ctf-string.c b/libctf/ctf-string.c
index 911e94700f1..ec8532fc47c 100644
--- a/libctf/ctf-string.c
+++ b/libctf/ctf-string.c
@@ -298,7 +298,10 @@ ctf_str_move_pending (ctf_dict_t *fp, uint32_t *new_ref, ptrdiff_t bytes)
     return 0;
 
   if (ctf_dynset_insert (fp->ctf_str_pending_ref, (void *) new_ref) < 0)
-    return (ctf_set_errno (fp, ENOMEM));
+    {
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
+    }
 
   ctf_dynset_remove (fp->ctf_str_pending_ref,
 		     (void *) ((signed char *) new_ref - bytes));
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index c20ff825d9a..22848a8c66b 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -119,7 +119,10 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 	return -1;			/* errno is set for us.  */
 
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (ofp, ENOMEM);
+	{
+	  ctf_set_errno (ofp, ENOMEM);
+	  return -1;
+	}
       i->cu.ctn_fp = ofp;
       i->ctn_tp = tp;
 
@@ -129,7 +132,8 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
       if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
 	{
 	  ctf_next_destroy (i);
-	  return (ctf_set_errno (ofp, ECTF_NOTSOU));
+	  ctf_set_errno (ofp, ECTF_NOTSOU);
+	  return -1;
 	}
 
       if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
@@ -150,14 +154,23 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
     }
 
   if ((void (*) (void)) ctf_member_next != i->ctn_iter_fun)
-    return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN));
+    {
+      ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN);
+      return -1
+    }
 
   if (ofp != i->cu.ctn_fp)
-    return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFP));
+    {
+      ctf_set_errno (ofp, ECTF_NEXT_WRONGFP);
+      return -1;
+    }
 
   /* Resolve to the native dict of this type.  */
   if ((fp = ctf_get_dict (ofp, type)) == NULL)
-    return (ctf_set_errno (ofp, ECTF_NOPARENT));
+    {
+      ctf_set_errno (ofp, ECTF_NOPARENT);
+      return -1;
+    }
 
   max_vlen = LCTF_INFO_VLEN (fp, i->ctn_tp->ctt_info);
 
@@ -177,7 +190,10 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 
       if (ctf_struct_member (fp, &memb, i->ctn_tp, i->u.ctn_vlen, i->ctn_size,
 			     i->ctn_n) < 0)
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+	{
+	  ctf_set_errno (ofp, ctf_errno (fp));
+	  return -1;
+	}
 
       membname = ctf_strptr (fp, memb.ctlm_name);
 
@@ -221,7 +237,10 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 	}
 
       if (!ctf_assert (fp, (i->ctn_next == NULL)))
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+	{
+	  ctf_set_errno (ofp, ctf_errno (fp));
+	  return -1;
+	}
 
       i->ctn_type = 0;
       /* This sub-struct has ended: on to the next real member.  */
@@ -233,7 +252,8 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
  end_iter:
   ctf_next_destroy (i);
   *it = NULL;
-  return ctf_set_errno (ofp, ECTF_NEXT_END);
+  ctf_set_errno (ofp, ECTF_NEXT_END);
+  return -1;
 }
 
 /* Iterate over the members of an ENUM.  We pass the string name and associated
@@ -956,7 +976,8 @@ ctf_type_size (ctf_dict_t *fp, ctf_id_t type)
 
     case CTF_K_FORWARD:
       /* Forwards do not have a meaningful size.  */
-      return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
+      ctf_set_errno (ofp, ECTF_INCOMPLETE);
+      return -1;
 
     default: /* including slices of enums, etc */
       return (ctf_get_ctt_size (fp, tp, NULL, NULL));
@@ -1039,7 +1060,8 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
 
     case CTF_K_FORWARD:
       /* Forwards do not have a meaningful alignment.  */
-      return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
+      ctf_set_errno (ofp, ECTF_INCOMPLETE);
+      return -1;
 
     default:  /* including slices of enums, etc */
       return (ctf_get_ctt_size (fp, tp, NULL, NULL));
@@ -1235,7 +1257,8 @@ ctf_type_encoding (ctf_dict_t *fp, ctf_id_t type, ctf_encoding_t *ep)
 	break;
       }
     default:
-      return (ctf_set_errno (ofp, ECTF_NOTINTFP));
+      ctf_set_errno (ofp, ECTF_NOTINTFP);
+      return -1;
     }
 
   return 0;
@@ -1370,7 +1393,10 @@ ctf_member_count (ctf_dict_t *fp, ctf_id_t type)
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION && kind != CTF_K_ENUM)
-    return (ctf_set_errno (ofp, ECTF_NOTSUE));
+    {
+      ctf_set_errno (ofp, ECTF_NOTSUE);
+      return -1;
+    }
 
   return LCTF_INFO_VLEN (fp, tp->ctt_info);
 }
@@ -1398,7 +1424,10 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
-    return (ctf_set_errno (ofp, ECTF_NOTSOU));
+    {
+      ctf_set_errno (ofp, ECTF_NOTSOU);
+      return -1;
+    }
 
   n = LCTF_INFO_VLEN (fp, tp->ctt_info);
   if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
@@ -1418,7 +1447,10 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
       const char *membname;
 
       if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0)
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+	{
+	  ctf_set_errno (ofp, ctf_errno (fp));
+	  return -1;
+	}
 
       membname = ctf_strptr (fp, memb.ctlm_name);
 
@@ -1439,7 +1471,8 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
 	}
     }
 
-  return (ctf_set_errno (ofp, ECTF_NOMEMBNAM));
+  ctf_set_errno (ofp, ECTF_NOMEMBNAM);
+  return -1;
 }
 
 /* Return the array type, index, and size information for the specified ARRAY.  */
@@ -1457,7 +1490,10 @@ ctf_array_info (ctf_dict_t *fp, ctf_id_t type, ctf_arinfo_t *arp)
     return -1;			/* errno is set for us.  */
 
   if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ARRAY)
-    return (ctf_set_errno (ofp, ECTF_NOTARRAY));
+    {
+      ctf_set_errno (ofp, ECTF_NOTARRAY);
+      return -1;
+    }
 
   if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
     ap = (const ctf_array_t *) dtd->dtd_vlen;
@@ -1584,7 +1620,10 @@ ctf_func_type_info (ctf_dict_t *fp, ctf_id_t type, ctf_funcinfo_t *fip)
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
   if (kind != CTF_K_FUNCTION)
-    return (ctf_set_errno (ofp, ECTF_NOTFUNC));
+    {
+      ctf_set_errno (ofp, ECTF_NOTFUNC);
+      return -1;
+    }
 
   fip->ctc_return = tp->ctt_type;
   fip->ctc_flags = 0;
@@ -1697,7 +1736,10 @@ ctf_type_rvisit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func,
       ctf_lmember_t memb;
 
       if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0)
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+	{
+	  ctf_set_errno (ofp, ctf_errno (fp));
+	  return -1;
+	}
 
       if ((rc = ctf_type_rvisit (fp, memb.ctlm_type,
 				 func, arg, ctf_strptr (fp, memb.ctlm_name),
-- 
2.25.1


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

* Re: [PATCH v2] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-08-25 16:53   ` [PATCH v2] " Torbjörn SVENSSON
@ 2023-08-30  8:34     ` Torbjorn SVENSSON
  2023-08-30  9:39       ` Alan Modra
  0 siblings, 1 reply; 41+ messages in thread
From: Torbjorn SVENSSON @ 2023-08-30  8:34 UTC (permalink / raw)
  To: amodra; +Cc: binutils, Yvan ROUX

@Alan, any additional comments on this updated patch (except the missing 
semicolon that I mention below)?

Kind regards,
Torbjörn

On 2023-08-25 18:53, Torbjörn SVENSSON wrote:
> v1 -> v2:
> Changed all functions with signed interger return type to return -1 based on
> comment from Alan.
> 
> 
> Ok for trunk?
> 
> ---
> 
> The function ctf_member_next should return (ssize_t)-1 on
> error. As the function ctf_set_errno returns (ctf_id_t)-1L and that is
> then casted to "unsigned long" as it's the return type of the function,
> it's not compatible and causes the value 0xffffffff to be returned on
> 64-bit Windows builds. As a result, the check for a negative value in
> ctf_dedup_rhash_type will never be true and a resulting infinit loop is
> created.
> 
> This was found testing an arm-none-eabi toolchain built with
> x86_64-w64-mingw32. If the same source tree is built with
> i686-w64-mingw32, everything appears to be working correctly.
> 
> libctf/
> 	* ctf-create.c (ctf_add_enumerator): Ensure function returns -1 on error.
> 	(ctf_add_funcobjt_sym): Likewise.
> 	(ctf_add_member_encoded): Likewise.
> 	(ctf_add_member_offset): Likewise.
> 	(ctf_add_variable): Likewise.
> 	(ctf_grow_ptrtab): Likewise.
> 	(ctf_grow_vlen): Likewise.
> 	(ctf_rollback): Likewise.
> 	(ctf_set_array): Likewise.
> 	(ctf_update): Likewise.
> 	* ctf-dedup.c (ctf_dedup_atoms_init): Likewise.
> 	(ctf_dedup_conflictify_unshared): Likewise.
> 	(ctf_dedup_detect_name_ambiguity): Likewise.
> 	(ctf_dedup_emit_struct_members): Likewise.
> 	(ctf_dedup_emit_type): Likewise.
> 	(ctf_dedup_hash_kind): Likewise.
> 	(ctf_dedup_init): Likewise.
> 	(ctf_dedup_mark_conflicting_hash): Likewise.
> 	(ctf_dedup_multiple_input_dicts): Likewise.
> 	(ctf_dedup_populate_mappings): Likewise.
> 	(ctf_dedup_record_origin): Likewise.
> 	(ctf_dedup_rwalk_output_mapping): Likewise.
> 	(ctf_dedup_walk_output_mapping): Likewise.
> 	* ctf-dump.c (ctf_dump_append): Likewise.
> 	(ctf_dump_header): Likewise.
> 	(ctf_dump_header_sectfield): Likewise.
> 	(ctf_dump_header_strfield): Likewise.
> 	(ctf_dump_label): Likewise.
> 	(ctf_dump_member): Likewise.
> 	(ctf_dump_str): Likewise.
> 	(ctf_dump_type): Likewise.
> 	(ctf_dump_var): Likewise.
> 	* ctf-labels.c (ctf_label_info): Likewise.
> 	(ctf_label_iter): Likewise.
> 	* ctf-link.c (ctf_link_add_ctf_internal): Likewise.
> 	(ctf_link_add_cu_mapping): Likewise.
> 	(ctf_link_add): Likewise.
> 	(ctf_link_deduplicating_one_symtypetab): Likewise.
> 	(ctf_link_deduplicating_per_cu): Likewise.
> 	(ctf_link_deduplicating_variables): Likewise.
> 	(ctf_link): Likewise.
> 	(ctf_link_one_variable): Likewise.
> 	* ctf-lookup.c (ctf_func_args): Likewise.
> 	(ctf_func_info): Likewise.
> 	(grow_pptrtab): Likewise.
> 	* ctf-open.c (ctf_cuname_set): Likewise.
> 	(ctf_import): Likewise.
> 	(ctf_parent_name_set): Likewise.
> 	(ctf_setmodel): Likewise.
> 	* ctf-serialize.c (ctf_gzwrite): Likewise.
> 	(ctf_serialize): Likewise.
> 	(symtypetab_density): Likewise.
> 	* ctf-string.c (ctf_str_move_pending): Likewise.
> 	* ctf-types.c (ctf_array_info): Likewise.
> 	(ctf_func_type_info): Likewise.
> 	(ctf_member_count): Likewise.
> 	(ctf_member_info): Likewise.
> 	(ctf_member_next): Likewise.
> 	(ctf_type_align): Likewise.
> 	(ctf_type_encoding): Likewise.
> 	(ctf_type_rvisit): Likewise.
> 	(ctf_type_size): Likewise.
> 
> Signed-off-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
> Co-Authored-By: Yvan ROUX <yvan.roux@foss.st.com>
> ---
>   libctf/ctf-create.c    | 137 ++++++++++++++++++++++++++++++++---------
>   libctf/ctf-dedup.c     | 117 +++++++++++++++++++++++++----------
>   libctf/ctf-dump.c      |  40 +++++++++---
>   libctf/ctf-labels.c    |  15 +++--
>   libctf/ctf-link.c      |  69 ++++++++++++++++-----
>   libctf/ctf-lookup.c    |  15 ++++-
>   libctf/ctf-open.c      |  33 +++++++---
>   libctf/ctf-serialize.c |  43 +++++++++----
>   libctf/ctf-string.c    |   5 +-
>   libctf/ctf-types.c     |  78 +++++++++++++++++------
>   10 files changed, 420 insertions(+), 132 deletions(-)
> 
> diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
> index 6b342dc64a2..91c466519f7 100644
> --- a/libctf/ctf-create.c
> +++ b/libctf/ctf-create.c
> @@ -60,7 +60,10 @@ ctf_grow_ptrtab (ctf_dict_t *fp)
>   
>         if ((new_ptrtab = realloc (fp->ctf_ptrtab,
>   				 new_ptrtab_len * sizeof (uint32_t))) == NULL)
> -	return (ctf_set_errno (fp, ENOMEM));
> +	{
> +	  ctf_set_errno (fp, ENOMEM);
> +	  return -1;
> +	}
>   
>         fp->ctf_ptrtab = new_ptrtab;
>         memset (fp->ctf_ptrtab + fp->ctf_ptrtab_len, 0,
> @@ -87,7 +90,8 @@ ctf_grow_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vlen)
>   				dtd->dtd_vlen_alloc * 2)) == NULL)
>       {
>         dtd->dtd_vlen = old;
> -      return (ctf_set_errno (fp, ENOMEM));
> +      ctf_set_errno (fp, ENOMEM);
> +      return -1;
>       }
>     memset (dtd->dtd_vlen + dtd->dtd_vlen_alloc, 0, dtd->dtd_vlen_alloc);
>     dtd->dtd_vlen_alloc *= 2;
> @@ -197,7 +201,10 @@ int
>   ctf_update (ctf_dict_t *fp)
>   {
>     if (!(fp->ctf_flags & LCTF_RDWR))
> -    return (ctf_set_errno (fp, ECTF_RDONLY));
> +    {
> +      ctf_set_errno (fp, ECTF_RDONLY);
> +      return -1;
> +    }
>   
>     fp->ctf_dtoldid = fp->ctf_typemax;
>     return 0;
> @@ -391,10 +398,16 @@ ctf_rollback (ctf_dict_t *fp, ctf_snapshot_id_t id)
>     ctf_dvdef_t *dvd, *nvd;
>   
>     if (!(fp->ctf_flags & LCTF_RDWR))
> -    return (ctf_set_errno (fp, ECTF_RDONLY));
> +    {
> +      ctf_set_errno (fp, ECTF_RDONLY);
> +      return -1;
> +    }
>   
>     if (fp->ctf_snapshot_lu >= id.snapshot_id)
> -    return (ctf_set_errno (fp, ECTF_OVERROLLBACK));
> +    {
> +      ctf_set_errno (fp, ECTF_OVERROLLBACK);
> +      return -1;
> +    }
>   
>     for (dtd = ctf_list_next (&fp->ctf_dtdefs); dtd != NULL; dtd = ntd)
>       {
> @@ -723,11 +736,17 @@ ctf_set_array (ctf_dict_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
>     ctf_array_t *vlen;
>   
>     if (!(fp->ctf_flags & LCTF_RDWR))
> -    return (ctf_set_errno (fp, ECTF_RDONLY));
> +    {
> +      ctf_set_errno (fp, ECTF_RDONLY);
> +      return -1;
> +    }
>   
>     if (dtd == NULL
>         || LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info) != CTF_K_ARRAY)
> -    return (ctf_set_errno (fp, ECTF_BADID));
> +    {
> +      ctf_set_errno (fp, ECTF_BADID);
> +      return -1;
> +    }
>   
>     vlen = (ctf_array_t *) dtd->dtd_vlen;
>     fp->ctf_flags |= LCTF_DIRTY;
> @@ -1055,23 +1074,38 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
>     uint32_t kind, vlen, root;
>   
>     if (name == NULL)
> -    return (ctf_set_errno (fp, EINVAL));
> +    {
> +      ctf_set_errno (fp, EINVAL);
> +      return -1;
> +    }
>   
>     if (!(fp->ctf_flags & LCTF_RDWR))
> -    return (ctf_set_errno (fp, ECTF_RDONLY));
> +    {
> +      ctf_set_errno (fp, ECTF_RDONLY);
> +      return -1;
> +    }
>   
>     if (dtd == NULL)
> -    return (ctf_set_errno (fp, ECTF_BADID));
> +    {
> +      ctf_set_errno (fp, ECTF_BADID);
> +      return -1;
> +    }
>   
>     kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
>     root = LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info);
>     vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
>   
>     if (kind != CTF_K_ENUM)
> -    return (ctf_set_errno (fp, ECTF_NOTENUM));
> +    {
> +      ctf_set_errno (fp, ECTF_NOTENUM);
> +      return -1;
> +    }
>   
>     if (vlen == CTF_MAX_VLEN)
> -    return (ctf_set_errno (fp, ECTF_DTFULL));
> +    {
> +      ctf_set_errno (fp, ECTF_DTFULL);
> +      return -1;
> +    }
>   
>     old_vlen = dtd->dtd_vlen;
>     if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0)
> @@ -1090,7 +1124,10 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
>   
>     for (i = 0; i < vlen; i++)
>       if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
> -      return (ctf_set_errno (fp, ECTF_DUPLICATE));
> +      {
> +	ctf_set_errno (fp, ECTF_DUPLICATE);
> +	return -1;
> +      }
>   
>     en[i].cte_name = ctf_str_add_pending (fp, name, &en[i].cte_name);
>     en[i].cte_value = value;
> @@ -1119,10 +1156,16 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
>     ctf_lmember_t *memb;
>   
>     if (!(fp->ctf_flags & LCTF_RDWR))
> -    return (ctf_set_errno (fp, ECTF_RDONLY));
> +    {
> +      ctf_set_errno (fp, ECTF_RDONLY);
> +      return -1;
> +    }
>   
>     if (dtd == NULL)
> -    return (ctf_set_errno (fp, ECTF_BADID));
> +    {
> +      ctf_set_errno (fp, ECTF_BADID);
> +      return -1;
> +    }
>   
>     if (name != NULL && name[0] == '\0')
>       name = NULL;
> @@ -1132,10 +1175,16 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
>     vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
>   
>     if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
> -    return (ctf_set_errno (fp, ECTF_NOTSOU));
> +    {
> +      ctf_set_errno (fp, ECTF_NOTSOU);
> +      return -1;
> +    }
>   
>     if (vlen == CTF_MAX_VLEN)
> -    return (ctf_set_errno (fp, ECTF_DTFULL));
> +    {
> +      ctf_set_errno (fp, ECTF_DTFULL);
> +      return -1;
> +    }
>   
>     old_vlen = dtd->dtd_vlen;
>     if (ctf_grow_vlen (fp, dtd, sizeof (ctf_lmember_t) * (vlen + 1)) < 0)
> @@ -1156,7 +1205,10 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
>       {
>         for (i = 0; i < vlen; i++)
>   	if (strcmp (ctf_strptr (fp, memb[i].ctlm_name), name) == 0)
> -	  return (ctf_set_errno (fp, ECTF_DUPLICATE));
> +	  {
> +	    ctf_set_errno (fp, ECTF_DUPLICATE);
> +	    return -1;
> +	  }
>       }
>   
>     if ((msize = ctf_type_size (fp, type)) < 0 ||
> @@ -1212,7 +1264,8 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
>   			      "incomplete type %lx to struct %lx without "
>   			      "specifying explicit offset\n"),
>   			    name ? name : _("(unnamed member)"), type, souid);
> -	      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
> +	      ctf_set_errno (fp, ECTF_INCOMPLETE);
> +	      return -1;
>   	    }
>   
>   	  if (ctf_type_encoding (fp, ltype, &linfo) == 0)
> @@ -1285,7 +1338,10 @@ ctf_add_member_encoded (ctf_dict_t *fp, ctf_id_t souid, const char *name,
>     int otype = type;
>   
>     if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) && (kind != CTF_K_ENUM))
> -    return (ctf_set_errno (fp, ECTF_NOTINTFP));
> +    {
> +      ctf_set_errno (fp, ECTF_NOTINTFP);
> +      return -1;
> +    }
>   
>     if ((type = ctf_add_slice (fp, CTF_ADD_NONROOT, otype, &encoding)) == CTF_ERR)
>       return -1;			/* errno is set for us.  */
> @@ -1307,10 +1363,16 @@ ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
>     ctf_dict_t *tmp = fp;
>   
>     if (!(fp->ctf_flags & LCTF_RDWR))
> -    return (ctf_set_errno (fp, ECTF_RDONLY));
> +    {
> +      ctf_set_errno (fp, ECTF_RDONLY);
> +      return -1;
> +    }
>   
>     if (ctf_dvd_lookup (fp, name) != NULL)
> -    return (ctf_set_errno (fp, ECTF_DUPLICATE));
> +    {
> +      ctf_set_errno (fp, ECTF_DUPLICATE);
> +      return -1;
> +    }
>   
>     if (ctf_lookup_by_id (&tmp, ref) == NULL)
>       return -1;			/* errno is set for us.  */
> @@ -1321,12 +1383,16 @@ ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
>       return -1;
>   
>     if ((dvd = malloc (sizeof (ctf_dvdef_t))) == NULL)
> -    return (ctf_set_errno (fp, EAGAIN));
> +    {
> +      ctf_set_errno (fp, EAGAIN);
> +      return -1;
> +    }
>   
>     if (name != NULL && (dvd->dvd_name = strdup (name)) == NULL)
>       {
>         free (dvd);
> -      return (ctf_set_errno (fp, EAGAIN));
> +      ctf_set_errno (fp, EAGAIN);
> +      return -1;
>       }
>     dvd->dvd_type = ref;
>     dvd->dvd_snapshots = fp->ctf_snapshots;
> @@ -1350,25 +1416,38 @@ ctf_add_funcobjt_sym (ctf_dict_t *fp, int is_function, const char *name, ctf_id_
>     ctf_dynhash_t *h = is_function ? fp->ctf_funchash : fp->ctf_objthash;
>   
>     if (!(fp->ctf_flags & LCTF_RDWR))
> -    return (ctf_set_errno (fp, ECTF_RDONLY));
> +    {
> +      ctf_set_errno (fp, ECTF_RDONLY);
> +      return -1;
> +    }
>   
>     if (ctf_dynhash_lookup (fp->ctf_objthash, name) != NULL ||
>         ctf_dynhash_lookup (fp->ctf_funchash, name) != NULL)
> -    return (ctf_set_errno (fp, ECTF_DUPLICATE));
> +    {
> +      ctf_set_errno (fp, ECTF_DUPLICATE);
> +      return -1;
> +    }
>   
>     if (ctf_lookup_by_id (&tmp, id) == NULL)
>       return -1;                                  /* errno is set for us.  */
>   
>     if (is_function && ctf_type_kind (fp, id) != CTF_K_FUNCTION)
> -    return (ctf_set_errno (fp, ECTF_NOTFUNC));
> +    {
> +      ctf_set_errno (fp, ECTF_NOTFUNC);
> +      return -1;
> +    }
>   
>     if ((dupname = strdup (name)) == NULL)
> -    return (ctf_set_errno (fp, ENOMEM));
> +    {
> +      ctf_set_errno (fp, ENOMEM);
> +      return -1;
> +    }
>   
>     if (ctf_dynhash_insert (h, dupname, (void *) (uintptr_t) id) < 0)
>       {
>         free (dupname);
> -      return (ctf_set_errno (fp, ENOMEM));
> +      ctf_set_errno (fp, ENOMEM);
> +      return -1;
>       }
>     return 0;
>   }
> diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c
> index 5fdddfd0b54..f1c056caede 100644
> --- a/libctf/ctf-dedup.c
> +++ b/libctf/ctf-dedup.c
> @@ -378,7 +378,10 @@ ctf_dedup_atoms_init (ctf_dict_t *fp)
>         if ((fp->ctf_dedup_atoms_alloc
>   	   = ctf_dynset_create (htab_hash_string, htab_eq_string,
>   				free)) == NULL)
> -	return ctf_set_errno (fp, ENOMEM);
> +	{
> +	  ctf_set_errno (fp, ENOMEM);
> +	  return -1;
> +	}
>       }
>     fp->ctf_dedup_atoms = fp->ctf_dedup_atoms_alloc;
>     return 0;
> @@ -543,7 +546,10 @@ ctf_dedup_record_origin (ctf_dict_t *fp, int input_num, const char *decorated,
>   
>     if (populate_origin)
>       if (ctf_dynhash_cinsert (d->cd_struct_origin, decorated, origin) < 0)
> -      return ctf_set_errno (fp, errno);
> +      {
> +	ctf_set_errno (fp, errno);
> +	return -1;
> +      }
>     return 0;
>   }
>   
> @@ -1185,7 +1191,10 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
>       }
>     else
>       if (ctf_dynhash_cinsert (d->cd_output_mapping_guard, id, hval) < 0)
> -      return ctf_set_errno (fp, errno);
> +      {
> +	ctf_set_errno (fp, errno);
> +	return -1;
> +      }
>   #endif
>   
>     /* Record the type in the output mapping: if this is the first time this type
> @@ -1197,17 +1206,24 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
>   				      hval)) == NULL)
>       {
>         if (ctf_dynhash_cinsert (d->cd_output_first_gid, hval, id) < 0)
> -	return ctf_set_errno (fp, errno);
> +	{
> +	  ctf_set_errno (fp, errno);
> +	  return -1;
> +	}
>   
>         if ((type_ids = ctf_dynset_create (htab_hash_pointer,
>   					 htab_eq_pointer,
>   					 NULL)) == NULL)
> -	return ctf_set_errno (fp, errno);
> +	{
> +	  ctf_set_errno (fp, errno);
> +	  return -1;
> +	}
>         if (ctf_dynhash_insert (d->cd_output_mapping, (void *) hval,
>   			      type_ids) < 0)
>   	{
>   	  ctf_dynset_destroy (type_ids);
> -	  return ctf_set_errno (fp, errno);
> +	  ctf_set_errno (fp, errno);
> +	  return -1;
>   	}
>       }
>   #ifdef ENABLE_LIBCTF_HASH_DEBUGGING
> @@ -1248,7 +1264,10 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
>   	    }
>   	}
>         if (err != ECTF_NEXT_END)
> -	return ctf_set_errno (fp, err);
> +	{
> +	  ctf_set_errno (fp, err);
> +	  return -1;
> +	}
>       }
>   #endif
>   
> @@ -1256,7 +1275,10 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
>        don't waste time reinserting the same keys in that case.  */
>     if (!ctf_dynset_exists (type_ids, id, NULL)
>         && ctf_dynset_insert (type_ids, id) < 0)
> -    return ctf_set_errno (fp, errno);
> +    {
> +      ctf_set_errno (fp, errno);
> +      return -1;
> +    }
>   
>     /* The rest only needs to happen for types with names.  */
>     if (!decorated_name)
> @@ -1273,12 +1295,16 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
>         if ((name_counts = ctf_dynhash_create (ctf_hash_string,
>   					     ctf_hash_eq_string,
>   					     NULL, NULL)) == NULL)
> -	  return ctf_set_errno (fp, errno);
> +	{
> +	  ctf_set_errno (fp, errno);
> +	  return -1;
> +	}
>         if (ctf_dynhash_cinsert (d->cd_name_counts, decorated_name,
>   			       name_counts) < 0)
>   	{
>   	  ctf_dynhash_destroy (name_counts);
> -	  return ctf_set_errno (fp, errno);
> +	  ctf_set_errno (fp, errno);
> +	  return -1;
>   	}
>       }
>   
> @@ -1287,7 +1313,10 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
>   
>     if (ctf_dynhash_cinsert (name_counts, hval,
>   			   (const void *) (uintptr_t) (count + 1)) < 0)
> -    return ctf_set_errno (fp, errno);
> +    {
> +      ctf_set_errno (fp, errno);
> +      return -1;
> +    }
>   
>     return 0;
>   }
> @@ -1339,10 +1368,11 @@ ctf_dedup_mark_conflicting_hash (ctf_dict_t *fp, const char *hval)
>   	  return -1;				/* errno is set for us.  */
>   	}
>       }
> -  if (err != ECTF_NEXT_END)
> -    return ctf_set_errno (fp, err);
> +  if (err == ECTF_NEXT_END)
> +    return 0;
>   
> -  return 0;
> +  ctf_set_errno (fp, err);
> +  return -1;
>   }
>   
>   /* Look up a type kind from the output mapping, given a type hash value.  */
> @@ -1366,7 +1396,8 @@ ctf_dedup_hash_kind (ctf_dict_t *fp, ctf_dict_t **inputs, const char *hash)
>     if (!type_ids)
>       {
>         ctf_dprintf ("Looked up type kind by nonexistent hash %s.\n", hash);
> -      return ctf_set_errno (fp, ECTF_INTERNAL);
> +      ctf_set_errno (fp, ECTF_INTERNAL);
> +      return -1;
>       }
>     id = ctf_dynset_lookup_any (type_ids);
>     if (!ctf_assert (fp, id))
> @@ -1585,7 +1616,8 @@ ctf_dedup_detect_name_ambiguity (ctf_dict_t *fp, ctf_dict_t **inputs)
>   
>    iterr:
>     ctf_err_warn (fp, 0, err, _("iteration failed: %s"), gettext (whaterr));
> -  return ctf_set_errno (fp, err);
> +  ctf_set_errno (fp, err);
> +  return -1;
>   
>    assert_err:
>     ctf_next_destroy (i);
> @@ -1683,7 +1715,8 @@ ctf_dedup_init (ctf_dict_t *fp)
>    oom:
>     ctf_err_warn (fp, 0, ENOMEM, _("ctf_dedup_init: cannot initialize: "
>   				 "out of memory"));
> -  return ctf_set_errno (fp, ENOMEM);
> +  ctf_set_errno (fp, ENOMEM);
> +  return -1;
>   }
>   
>   /* No ctf_dedup calls are allowed after this call other than starting a new
> @@ -1784,7 +1817,8 @@ ctf_dedup_multiple_input_dicts (ctf_dict_t *output, ctf_dict_t **inputs,
>       {
>         ctf_err_warn (output, 0, err, _("iteration error "
>   				      "propagating conflictedness"));
> -      return ctf_set_errno (output, err);
> +      ctf_set_errno (output, err);
> +      return -1;
>       }
>   
>     if (multiple)
> @@ -1879,7 +1913,8 @@ ctf_dedup_conflictify_unshared (ctf_dict_t *output, ctf_dict_t **inputs)
>    iterr:
>     ctf_dynset_destroy (to_mark);
>     ctf_err_warn (output, 0, err, _("conflictifying unshared types"));
> -  return ctf_set_errno (output, err);
> +  ctf_set_errno (output, err);
> +  return -1;
>   }
>   
>   /* The core deduplicator.  Populate cd_output_mapping in the output ctf_dedup
> @@ -2219,7 +2254,8 @@ ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
>       {
>         ctf_err_warn (output, 0, ECTF_INTERNAL,
>   		    _("looked up type kind by nonexistent hash %s"), hval);
> -      return ctf_set_errno (output, ECTF_INTERNAL);
> +      ctf_set_errno (output, ECTF_INTERNAL);
> +      return -1;
>       }
>   
>     /* Have we seen this type before?  */
> @@ -2237,7 +2273,8 @@ ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
>   	{
>   	  ctf_err_warn (output, 0, ENOMEM,
>   			_("out of memory tracking already-visited types"));
> -	  return ctf_set_errno (output, ENOMEM);
> +	  ctf_set_errno (output, ENOMEM);
> +	  return -1;
>   	}
>       }
>   
> @@ -2274,7 +2311,8 @@ ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
>     if (err != ECTF_NEXT_END)
>       {
>         ctf_err_warn (output, 0, err, _("cannot walk conflicted type"));
> -      return ctf_set_errno (output, err);
> +      ctf_set_errno (output, err);
> +      return -1;
>       }
>   
>     return 0;
> @@ -2376,7 +2414,10 @@ ctf_dedup_walk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
>     if ((already_visited = ctf_dynset_create (htab_hash_string,
>   					    htab_eq_string,
>   					    NULL)) == NULL)
> -    return ctf_set_errno (output, ENOMEM);
> +    {
> +      ctf_set_errno (output, ENOMEM);
> +      return -1;
> +    }
>   
>     sort_arg.inputs = inputs;
>     sort_arg.ninputs = ninputs;
> @@ -2664,7 +2705,8 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
>   	      ctf_err_warn (output, 0, err,
>   			    _("cannot create per-CU CTF archive for CU %s"),
>   			    ctf_link_input_name (input));
> -	      return ctf_set_errno (output, err);
> +	      ctf_set_errno (output, err);
> +	      return -1;
>   	    }
>   
>   	  ctf_import_unref (target, output);
> @@ -2687,7 +2729,8 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
>         ctf_err_warn (output, 0, ctf_errno (input),
>   		    _("%s: lookup failure for type %lx"),
>   		    ctf_link_input_name (real_input), type);
> -      return ctf_set_errno (output, ctf_errno (input));
> +      ctf_set_errno (output, ctf_errno (input));
> +      return -1;
>       }
>   
>     name = ctf_strraw (real_input, tp->ctt_name);
> @@ -2765,7 +2808,8 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
>   			      ctf_link_input_name (input), input_num, name,
>   			      type);
>   		ctf_next_destroy (i);
> -		return ctf_set_errno (output, ctf_errno (target));
> +		ctf_set_errno (output, ctf_errno (target));
> +		return -1;
>   	      }
>   	  }
>   	if (ctf_errno (input) != ECTF_NEXT_END)
> @@ -2921,7 +2965,8 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
>         ctf_err_warn (output, 0, ECTF_CORRUPT, _("%s: unknown type kind for "
>   					       "input type %lx"),
>   		    ctf_link_input_name (input), type);
> -      return ctf_set_errno (output, ECTF_CORRUPT);
> +      ctf_set_errno (output, ECTF_CORRUPT);
> +      return -1;
>       }
>   
>     if (!emission_hashed
> @@ -2931,7 +2976,8 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
>       {
>         ctf_err_warn (output, 0, ENOMEM, _("out of memory tracking deduplicated "
>   					 "global type IDs"));
> -	return ctf_set_errno (output, ENOMEM);
> +      ctf_set_errno (output, ENOMEM);
> +      return -1;
>       }
>   
>     if (!emission_hashed && new_type != 0)
> @@ -2944,21 +2990,24 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
>    oom_hash:
>     ctf_err_warn (output, 0, ENOMEM, _("out of memory creating emission-tracking "
>   				     "hashes"));
> -  return ctf_set_errno (output, ENOMEM);
> +  ctf_set_errno (output, ENOMEM);
> +  return -1;
>   
>    err_input:
>     ctf_err_warn (output, 0, ctf_errno (input),
>   		_("%s (%i): while emitting deduplicated %s, error getting "
>   		  "input type %lx"), ctf_link_input_name (input),
>   		input_num, errtype, type);
> -  return ctf_set_errno (output, ctf_errno (input));
> +  ctf_set_errno (output, ctf_errno (input));
> +  return -1;
>    err_target:
>     ctf_err_warn (output, 0, ctf_errno (target),
>   		_("%s (%i): while emitting deduplicated %s, error emitting "
>   		  "target type from input type %lx"),
>   		ctf_link_input_name (input), input_num,
>   		errtype, type);
> -  return ctf_set_errno (output, ctf_errno (target));
> +  ctf_set_errno (output, ctf_errno (target));
> +  return -1;
>   }
>   
>   /* Traverse the cd_emission_struct_members and emit the members of all
> @@ -3051,11 +3100,13 @@ ctf_dedup_emit_struct_members (ctf_dict_t *output, ctf_dict_t **inputs,
>     ctf_err_warn (output, 0, ctf_errno (err_fp),
>   		_("%s (%i): error emitting members for structure type %lx"),
>   		ctf_link_input_name (input_fp), input_num, err_type);
> -  return ctf_set_errno (output, ctf_errno (err_fp));
> +  ctf_set_errno (output, ctf_errno (err_fp));
> +  return -1;
>    iterr:
>     ctf_err_warn (output, 0, err, _("iteration failure emitting "
>   				  "structure members"));
> -  return ctf_set_errno (output, err);
> +  ctf_set_errno (output, err);
> +  return -1;
>   }
>   
>   /* Emit deduplicated types into the outputs.  The shared type repository is
> diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
> index 686951a9869..b5de3c76709 100644
> --- a/libctf/ctf-dump.c
> +++ b/libctf/ctf-dump.c
> @@ -56,7 +56,10 @@ ctf_dump_append (ctf_dump_state_t *state, char *str)
>     ctf_dump_item_t *cdi;
>   
>     if ((cdi = malloc (sizeof (struct ctf_dump_item))) == NULL)
> -    return (ctf_set_errno (state->cds_fp, ENOMEM));
> +    {
> +      ctf_set_errno (state->cds_fp, ENOMEM);
> +      return -1;
> +    }
>   
>     cdi->cdi_item = str;
>     ctf_list_append (&state->cds_items, cdi);
> @@ -261,7 +264,8 @@ ctf_dump_header_strfield (ctf_dict_t *fp, ctf_dump_state_t *state,
>     return 0;
>   
>    err:
> -  return (ctf_set_errno (fp, errno));
> +  ctf_set_errno (fp, errno);
> +  return -1;
>   }
>   
>   /* Dump one section-offset field from the file header into the cds_items.  */
> @@ -281,7 +285,8 @@ ctf_dump_header_sectfield (ctf_dict_t *fp, ctf_dump_state_t *state,
>     return 0;
>   
>    err:
> -  return (ctf_set_errno (fp, errno));
> +  ctf_set_errno (fp, errno);
> +  return -1;
>   }
>   
>   /* Dump the file header into the cds_items.  */
> @@ -398,7 +403,8 @@ ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
>     return 0;
>    err:
>     free (flagstr);
> -  return (ctf_set_errno (fp, errno));
> +  ctf_set_errno (fp, errno);
> +  return -1;
>   }
>   
>   /* Dump a single label into the cds_items.  */
> @@ -412,7 +418,10 @@ ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
>     ctf_dump_state_t *state = arg;
>   
>     if (asprintf (&str, "%s -> ", name) < 0)
> -    return (ctf_set_errno (state->cds_fp, errno));
> +    {
> +      ctf_set_errno (state->cds_fp, errno);
> +      return -1;
> +    }
>   
>     if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type,
>   				       CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
> @@ -487,7 +496,10 @@ ctf_dump_var (const char *name, ctf_id_t type, void *arg)
>     ctf_dump_state_t *state = arg;
>   
>     if (asprintf (&str, "%s -> ", name) < 0)
> -    return (ctf_set_errno (state->cds_fp, errno));
> +    {
> +      ctf_set_errno (state->cds_fp, errno);
> +      return -1;
> +    }
>   
>     if ((typestr = ctf_dump_format_type (state->cds_fp, type,
>   				       CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
> @@ -540,7 +552,8 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
>    oom:
>     free (typestr);
>     free (bit);
> -  return (ctf_set_errno (state->cdm_fp, errno));
> +  ctf_set_errno (state->cdm_fp, errno);
> +  return -1;
>   }
>   
>   /* Report the number of digits in the hexadecimal representation of a type
> @@ -569,7 +582,10 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
>   
>     /* Indent neatly.  */
>     if (asprintf (&indent, "    %*s", type_hex_digits (id), "") < 0)
> -    return (ctf_set_errno (state->cds_fp, ENOMEM));
> +    {
> +      ctf_set_errno (state->cds_fp, ENOMEM);
> +      return -1;
> +    }
>   
>     /* Dump the type itself.  */
>     if ((str = ctf_dump_format_type (state->cds_fp, id,
> @@ -654,7 +670,8 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
>    oom:
>     free (indent);
>     free (str);
> -  return ctf_set_errno (state->cds_fp, ENOMEM);
> +  ctf_set_errno (state->cds_fp, ENOMEM);
> +  return -1;
>   }
>   
>   /* Dump the string table into the cds_items.  */
> @@ -671,7 +688,10 @@ ctf_dump_str (ctf_dict_t *fp, ctf_dump_state_t *state)
>         if (asprintf (&str, "0x%lx: %s",
>   		    (unsigned long) (s - fp->ctf_str[CTF_STRTAB_0].cts_strs),
>   		    s) < 0)
> -	return (ctf_set_errno (fp, errno));
> +	{
> +	  ctf_set_errno (fp, errno);
> +	  return -1;
> +	}
>         ctf_dump_append (state, str);
>         s += strlen (s) + 1;
>       }
> diff --git a/libctf/ctf-labels.c b/libctf/ctf-labels.c
> index 16b111b14df..8aa2edc1847 100644
> --- a/libctf/ctf-labels.c
> +++ b/libctf/ctf-labels.c
> @@ -74,7 +74,10 @@ ctf_label_iter (ctf_dict_t *fp, ctf_label_f *func, void *arg)
>       return -1;			/* errno is set for us.  */
>   
>     if (num_labels == 0)
> -    return (ctf_set_errno (fp, ECTF_NOLABELDATA));
> +    {
> +      ctf_set_errno (fp, ECTF_NOLABELDATA);
> +      return -1;
> +    }
>   
>     for (i = 0; i < num_labels; i++, ctlp++)
>       {
> @@ -84,7 +87,8 @@ ctf_label_iter (ctf_dict_t *fp, ctf_label_f *func, void *arg)
>   	  ctf_err_warn (fp, 0, ECTF_CORRUPT,
>   			"failed to decode label %u with type %u",
>   			ctlp->ctl_label, ctlp->ctl_type);
> -	  return (ctf_set_errno (fp, ECTF_CORRUPT));
> +	  ctf_set_errno (fp, ECTF_CORRUPT);
> +	  return -1;
>   	}
>   
>         linfo.ctb_type = ctlp->ctl_type;
> @@ -133,8 +137,9 @@ ctf_label_info (ctf_dict_t *fp, const char *lname, ctf_lblinfo_t *linfo)
>     if ((rc = ctf_label_iter (fp, label_info_cb, &cb_arg)) < 0)
>       return rc;
>   
> -  if (rc != 1)
> -    return (ctf_set_errno (fp, ECTF_NOLABEL));
> +  if (rc == 1)
> +    return 0;
>   
> -  return 0;
> +  ctf_set_errno (fp, ECTF_NOLABEL);
> +  return -1;
>   }
> diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c
> index 9babec2aa37..97beb36be83 100644
> --- a/libctf/ctf-link.c
> +++ b/libctf/ctf-link.c
> @@ -142,7 +142,8 @@ ctf_link_add_ctf_internal (ctf_dict_t *fp, ctf_archive_t *ctf,
>    oom1:
>     free (filename);
>    oom:
> -  return ctf_set_errno (fp, ENOMEM);
> +  ctf_set_errno (fp, ENOMEM);
> +  return -1;
>   }
>   
>   /* Add a file, memory buffer, or unopened file (by name) to a link.
> @@ -173,12 +174,18 @@ ctf_link_add (ctf_dict_t *fp, ctf_archive_t *ctf, const char *name,
>   	      void *buf _libctf_unused_, size_t n _libctf_unused_)
>   {
>     if (buf)
> -    return (ctf_set_errno (fp, ECTF_NOTYET));
> +    {
> +      ctf_set_errno (fp, ECTF_NOTYET);
> +      return -1;
> +    }
>   
>     if (!((ctf && name && !buf)
>   	|| (name && !buf && !ctf)
>   	|| (buf && name && !ctf)))
> -    return (ctf_set_errno (fp, EINVAL));
> +    {
> +      ctf_set_errno (fp, EINVAL);
> +      return -1;
> +    }
>   
>     /* We can only lazily open files if libctf.so is in use rather than
>        libctf-nobfd.so.  This is a little tricky: in shared libraries, we can use
> @@ -187,21 +194,33 @@ ctf_link_add (ctf_dict_t *fp, ctf_archive_t *ctf, const char *name,
>   
>   #if defined (PIC)
>     if (!buf && !ctf && name && !ctf_open)
> -    return (ctf_set_errno (fp, ECTF_NEEDSBFD));
> +    {
> +      ctf_set_errno (fp, ECTF_NEEDSBFD);
> +      return -1;
> +    }
>   #elif NOBFD
>     if (!buf && !ctf && name)
> -    return (ctf_set_errno (fp, ECTF_NEEDSBFD));
> +    {
> +      ctf_set_errno (fp, ECTF_NEEDSBFD);
> +      return -1;
> +    }
>   #endif
>   
>     if (fp->ctf_link_outputs)
> -    return (ctf_set_errno (fp, ECTF_LINKADDEDLATE));
> +    {
> +      ctf_set_errno (fp, ECTF_LINKADDEDLATE);
> +      return -1;
> +    }
>     if (fp->ctf_link_inputs == NULL)
>       fp->ctf_link_inputs = ctf_dynhash_create (ctf_hash_string,
>   					      ctf_hash_eq_string, free,
>   					      ctf_link_input_close);
>   
>     if (fp->ctf_link_inputs == NULL)
> -    return (ctf_set_errno (fp, ENOMEM));
> +    {
> +      ctf_set_errno (fp, ENOMEM);
> +      return -1;
> +    }
>   
>     return ctf_link_add_ctf_internal (fp, ctf, NULL, name);
>   }
> @@ -378,7 +397,10 @@ ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
>   
>     /* Mappings cannot be set up if per-CU output dicts already exist.  */
>     if (fp->ctf_link_outputs && ctf_dynhash_elements (fp->ctf_link_outputs) != 0)
> -      return (ctf_set_errno (fp, ECTF_LINKADDEDLATE));
> +    {
> +      ctf_set_errno (fp, ECTF_LINKADDEDLATE);
> +      return -1;
> +    }
>   
>     if (fp->ctf_link_in_cu_mapping == NULL)
>       fp->ctf_link_in_cu_mapping = ctf_dynhash_create (ctf_hash_string,
> @@ -582,7 +604,10 @@ ctf_link_one_variable (ctf_dict_t *fp, ctf_dict_t *in_fp, const char *name,
>   
>     if (check_variable (name, per_cu_out_fp, dst_type, &dvd))
>       if (ctf_add_variable (per_cu_out_fp, name, dst_type) < 0)
> -      return (ctf_set_errno (fp, ctf_errno (per_cu_out_fp)));
> +      {
> +	ctf_set_errno (fp, ctf_errno (per_cu_out_fp));
> +	return -1;
> +      }
>     return 0;
>   }
>   
> @@ -915,7 +940,10 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
>   	    }
>   	}
>         if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
> -	return ctf_set_errno (fp, ctf_errno (inputs[i]));
> +	{
> +	  ctf_set_errno (fp, ctf_errno (inputs[i]));
> +	  return -1;
> +	}
>   
>         /* Next the symbols.  We integrate data symbols even though the compiler
>   	 is currently doing the same, to allow the compiler to stop in
> @@ -930,7 +958,10 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
>   	    }
>   	}
>         if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
> -	return ctf_set_errno (fp, ctf_errno (inputs[i]));
> +	{
> +	  ctf_set_errno (fp, ctf_errno (inputs[i]));
> +	  return -1;
> +	}
>   
>         /* Finally the function symbols.  */
>   
> @@ -943,7 +974,10 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
>   	    }
>   	}
>         if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
> -	return ctf_set_errno (fp, ctf_errno (inputs[i]));
> +	{
> +	  ctf_set_errno (fp, ctf_errno (inputs[i]));
> +	  return -1;
> +	}
>       }
>     return 0;
>   }
> @@ -1070,7 +1104,8 @@ ctf_link_deduplicating_one_symtypetab (ctf_dict_t *fp, ctf_dict_t *input,
>   			_("symbol %s in input file %s found conflicting "
>   			  "even when trying in per-CU dict."), name,
>   			ctf_unnamed_cuname (input));
> -	  return (ctf_set_errno (fp, ECTF_DUPLICATE));
> +	  ctf_set_errno (fp, ECTF_DUPLICATE);
> +	  return -1;
>   	}
>       }
>     if (ctf_errno (input) != ECTF_NEXT_END)
> @@ -1330,7 +1365,8 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
>       {
>         ctf_err_warn (fp, 0, err, _("iteration error in CU-mapped deduplicating "
>   				  "link"));
> -      return ctf_set_errno (fp, err);
> +      ctf_set_errno (fp, err);
> +      return -1;
>       }
>   
>     return 0;
> @@ -1503,7 +1539,10 @@ ctf_link (ctf_dict_t *fp, int flags)
>   					       ctf_dict_close);
>   
>     if (fp->ctf_link_outputs == NULL)
> -    return ctf_set_errno (fp, ENOMEM);
> +    {
> +      ctf_set_errno (fp, ENOMEM);
> +      return -1;
> +    }
>   
>     fp->ctf_flags |= LCTF_LINKING;
>     ctf_link_deduplicating (fp);
> diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
> index c65849118cb..7ad07e3bf84 100644
> --- a/libctf/ctf-lookup.c
> +++ b/libctf/ctf-lookup.c
> @@ -30,7 +30,10 @@ grow_pptrtab (ctf_dict_t *fp, size_t new_len)
>   
>     if ((new_pptrtab = realloc (fp->ctf_pptrtab, sizeof (uint32_t)
>   			      * new_len)) == NULL)
> -    return (ctf_set_errno (fp, ENOMEM));
> +    {
> +      ctf_set_errno (fp, ENOMEM);
> +      return -1;
> +    }
>   
>     fp->ctf_pptrtab = new_pptrtab;
>   
> @@ -1046,7 +1049,10 @@ ctf_func_info (ctf_dict_t *fp, unsigned long symidx, ctf_funcinfo_t *fip)
>       return -1;					/* errno is set for us.  */
>   
>     if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
> -    return (ctf_set_errno (fp, ECTF_NOTFUNC));
> +    {
> +      ctf_set_errno (fp, ECTF_NOTFUNC);
> +      return -1;
> +    }
>   
>     return ctf_func_type_info (fp, type, fip);
>   }
> @@ -1064,7 +1070,10 @@ ctf_func_args (ctf_dict_t *fp, unsigned long symidx, uint32_t argc,
>       return -1;					/* errno is set for us.  */
>   
>     if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
> -    return (ctf_set_errno (fp, ECTF_NOTFUNC));
> +    {
> +      ctf_set_errno (fp, ECTF_NOTFUNC);
> +      return -1;
> +    }
>   
>     return ctf_func_type_args (fp, type, argc, argv);
>   }
> diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c
> index 35f635b6559..fa5f2aab732 100644
> --- a/libctf/ctf-open.c
> +++ b/libctf/ctf-open.c
> @@ -1935,7 +1935,10 @@ ctf_parent_name_set (ctf_dict_t *fp, const char *name)
>       free (fp->ctf_dynparname);
>   
>     if ((fp->ctf_dynparname = strdup (name)) == NULL)
> -    return (ctf_set_errno (fp, ENOMEM));
> +    {
> +      ctf_set_errno (fp, ENOMEM);
> +      return -1;
> +    }
>     fp->ctf_parname = fp->ctf_dynparname;
>     return 0;
>   }
> @@ -1956,7 +1959,10 @@ ctf_cuname_set (ctf_dict_t *fp, const char *name)
>       free (fp->ctf_dyncuname);
>   
>     if ((fp->ctf_dyncuname = strdup (name)) == NULL)
> -    return (ctf_set_errno (fp, ENOMEM));
> +    {
> +      ctf_set_errno (fp, ENOMEM);
> +      return -1;
> +    }
>     fp->ctf_cuname = fp->ctf_dyncuname;
>     return 0;
>   }
> @@ -1969,10 +1975,16 @@ int
>   ctf_import (ctf_dict_t *fp, ctf_dict_t *pfp)
>   {
>     if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
> -    return (ctf_set_errno (fp, EINVAL));
> +    {
> +      ctf_set_errno (fp, EINVAL);
> +      return -1;
> +    }
>   
>     if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel)
> -    return (ctf_set_errno (fp, ECTF_DMODEL));
> +    {
> +      ctf_set_errno (fp, ECTF_DMODEL);
> +      return -1;
> +    }
>   
>     if (fp->ctf_parent && !fp->ctf_parent_unreffed)
>       ctf_dict_close (fp->ctf_parent);
> @@ -2008,10 +2020,16 @@ int
>   ctf_import_unref (ctf_dict_t *fp, ctf_dict_t *pfp)
>   {
>     if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
> -    return (ctf_set_errno (fp, EINVAL));
> +    {
> +      ctf_set_errno (fp, EINVAL);
> +      return -1;
> +    }
>   
>     if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel)
> -    return (ctf_set_errno (fp, ECTF_DMODEL));
> +    {
> +      ctf_set_errno (fp, ECTF_DMODEL);
> +      return -1;
> +    }
>   
>     if (fp->ctf_parent && !fp->ctf_parent_unreffed)
>       ctf_dict_close (fp->ctf_parent);
> @@ -2052,7 +2070,8 @@ ctf_setmodel (ctf_dict_t *fp, int model)
>   	}
>       }
>   
> -  return (ctf_set_errno (fp, EINVAL));
> +  ctf_set_errno (fp, EINVAL);
> +  return -1;
>   }
>   
>   /* Return the data model constant for the CTF dict.  */
> diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
> index ba830a2b095..258dec62366 100644
> --- a/libctf/ctf-serialize.c
> +++ b/libctf/ctf-serialize.c
> @@ -123,7 +123,10 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
>   
>         if ((linker_known = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
>   					      NULL, NULL)) == NULL)
> -	return (ctf_set_errno (fp, ENOMEM));
> +	{
> +	  ctf_set_errno (fp, ENOMEM);
> +	  return -1;
> +	}
>   
>         while ((err = ctf_dynhash_cnext (symfp->ctf_dynsyms, &i,
>   				       &name, &ctf_sym)) == 0)
> @@ -147,7 +150,8 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
>   	  if (ctf_dynhash_cinsert (linker_known, name, ctf_sym) < 0)
>   	    {
>   	      ctf_dynhash_destroy (linker_known);
> -	      return (ctf_set_errno (fp, ENOMEM));
> +	      ctf_set_errno (fp, ENOMEM);
> +	      return -1;
>   	    }
>   	}
>         if (err != ECTF_NEXT_END)
> @@ -155,7 +159,8 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
>   	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols during "
>   				  "serialization"));
>   	  ctf_dynhash_destroy (linker_known);
> -	  return (ctf_set_errno (fp, err));
> +	  ctf_set_errno (fp, err);
> +	  return -1;
>   	}
>       }
>   
> @@ -219,7 +224,8 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
>         ctf_err_warn (fp, 0, err, _("iterating over CTF symtypetab during "
>   				  "serialization"));
>         ctf_dynhash_destroy (linker_known);
> -      return (ctf_set_errno (fp, err));
> +      ctf_set_errno (fp, err);
> +      return -1;
>       }
>   
>     if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
> @@ -236,7 +242,8 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
>   	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols "
>   				      "during CTF serialization"));
>   	  ctf_dynhash_destroy (linker_known);
> -	  return (ctf_set_errno (fp, err));
> +	  ctf_set_errno (fp, err);
> +	  return -1;
>   	}
>       }
>   
> @@ -970,7 +977,10 @@ ctf_serialize (ctf_dict_t *fp)
>     memset (&symstate, 0, sizeof (emit_symtypetab_state_t));
>   
>     if (!(fp->ctf_flags & LCTF_RDWR))
> -    return (ctf_set_errno (fp, ECTF_RDONLY));
> +    {
> +      ctf_set_errno (fp, ECTF_RDONLY);
> +      return -1;
> +    }
>   
>     /* Update required?  */
>     if (!(fp->ctf_flags & LCTF_DIRTY))
> @@ -1026,7 +1036,10 @@ ctf_serialize (ctf_dict_t *fp)
>     buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
>   
>     if ((buf = malloc (buf_size)) == NULL)
> -    return (ctf_set_errno (fp, EAGAIN));
> +    {
> +      ctf_set_errno (fp, EAGAIN);
> +      return -1;
> +    }
>   
>     memcpy (buf, &hdr, sizeof (ctf_header_t));
>     t = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_objtoff;
> @@ -1106,7 +1119,8 @@ ctf_serialize (ctf_dict_t *fp)
>   				       1, &err)) == NULL)
>       {
>         free (buf);
> -      return (ctf_set_errno (fp, err));
> +      ctf_set_errno (fp, err);
> +      return -1;
>       }
>   
>     (void) ctf_setmodel (nfp, ctf_getmodel (fp));
> @@ -1221,7 +1235,8 @@ ctf_serialize (ctf_dict_t *fp)
>   
>   oom:
>     free (buf);
> -  return (ctf_set_errno (fp, EAGAIN));
> +  ctf_set_errno (fp, EAGAIN);
> +  return -1;
>   err:
>     free (buf);
>     return -1;					/* errno is set for us.  */
> @@ -1248,7 +1263,10 @@ ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
>     while (resid != 0)
>       {
>         if ((len = gzwrite (fd, buf, resid)) <= 0)
> -	return (ctf_set_errno (fp, errno));
> +	{
> +	  ctf_set_errno (fp, errno);
> +	  return -1;
> +	}
>         resid -= len;
>         buf += len;
>       }
> @@ -1258,7 +1276,10 @@ ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
>     while (resid != 0)
>       {
>         if ((len = gzwrite (fd, buf, resid)) <= 0)
> -	return (ctf_set_errno (fp, errno));
> +	{
> +	  ctf_set_errno (fp, errno);
> +	  return -1;
> +	}
>         resid -= len;
>         buf += len;
>       }
> diff --git a/libctf/ctf-string.c b/libctf/ctf-string.c
> index 911e94700f1..ec8532fc47c 100644
> --- a/libctf/ctf-string.c
> +++ b/libctf/ctf-string.c
> @@ -298,7 +298,10 @@ ctf_str_move_pending (ctf_dict_t *fp, uint32_t *new_ref, ptrdiff_t bytes)
>       return 0;
>   
>     if (ctf_dynset_insert (fp->ctf_str_pending_ref, (void *) new_ref) < 0)
> -    return (ctf_set_errno (fp, ENOMEM));
> +    {
> +      ctf_set_errno (fp, ENOMEM);
> +      return -1;
> +    }
>   
>     ctf_dynset_remove (fp->ctf_str_pending_ref,
>   		     (void *) ((signed char *) new_ref - bytes));
> diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
> index c20ff825d9a..22848a8c66b 100644
> --- a/libctf/ctf-types.c
> +++ b/libctf/ctf-types.c
> @@ -119,7 +119,10 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
>   	return -1;			/* errno is set for us.  */
>   
>         if ((i = ctf_next_create ()) == NULL)
> -	return ctf_set_errno (ofp, ENOMEM);
> +	{
> +	  ctf_set_errno (ofp, ENOMEM);
> +	  return -1;
> +	}
>         i->cu.ctn_fp = ofp;
>         i->ctn_tp = tp;
>   
> @@ -129,7 +132,8 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
>         if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
>   	{
>   	  ctf_next_destroy (i);
> -	  return (ctf_set_errno (ofp, ECTF_NOTSOU));
> +	  ctf_set_errno (ofp, ECTF_NOTSOU);
> +	  return -1;
>   	}
>   
>         if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
> @@ -150,14 +154,23 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
>       }
>   
>     if ((void (*) (void)) ctf_member_next != i->ctn_iter_fun)
> -    return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN));
> +    {
> +      ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN);
> +      return -1

The semicolon got lost when I prepared the mail. It will obviously be 
there when pushed.

> +    }
>   
>     if (ofp != i->cu.ctn_fp)
> -    return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFP));
> +    {
> +      ctf_set_errno (ofp, ECTF_NEXT_WRONGFP);
> +      return -1;
> +    }
>   
>     /* Resolve to the native dict of this type.  */
>     if ((fp = ctf_get_dict (ofp, type)) == NULL)
> -    return (ctf_set_errno (ofp, ECTF_NOPARENT));
> +    {
> +      ctf_set_errno (ofp, ECTF_NOPARENT);
> +      return -1;
> +    }
>   
>     max_vlen = LCTF_INFO_VLEN (fp, i->ctn_tp->ctt_info);
>   
> @@ -177,7 +190,10 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
>   
>         if (ctf_struct_member (fp, &memb, i->ctn_tp, i->u.ctn_vlen, i->ctn_size,
>   			     i->ctn_n) < 0)
> -        return (ctf_set_errno (ofp, ctf_errno (fp)));
> +	{
> +	  ctf_set_errno (ofp, ctf_errno (fp));
> +	  return -1;
> +	}
>   
>         membname = ctf_strptr (fp, memb.ctlm_name);
>   
> @@ -221,7 +237,10 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
>   	}
>   
>         if (!ctf_assert (fp, (i->ctn_next == NULL)))
> -        return (ctf_set_errno (ofp, ctf_errno (fp)));
> +	{
> +	  ctf_set_errno (ofp, ctf_errno (fp));
> +	  return -1;
> +	}
>   
>         i->ctn_type = 0;
>         /* This sub-struct has ended: on to the next real member.  */
> @@ -233,7 +252,8 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
>    end_iter:
>     ctf_next_destroy (i);
>     *it = NULL;
> -  return ctf_set_errno (ofp, ECTF_NEXT_END);
> +  ctf_set_errno (ofp, ECTF_NEXT_END);
> +  return -1;
>   }
>   
>   /* Iterate over the members of an ENUM.  We pass the string name and associated
> @@ -956,7 +976,8 @@ ctf_type_size (ctf_dict_t *fp, ctf_id_t type)
>   
>       case CTF_K_FORWARD:
>         /* Forwards do not have a meaningful size.  */
> -      return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
> +      ctf_set_errno (ofp, ECTF_INCOMPLETE);
> +      return -1;
>   
>       default: /* including slices of enums, etc */
>         return (ctf_get_ctt_size (fp, tp, NULL, NULL));
> @@ -1039,7 +1060,8 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
>   
>       case CTF_K_FORWARD:
>         /* Forwards do not have a meaningful alignment.  */
> -      return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
> +      ctf_set_errno (ofp, ECTF_INCOMPLETE);
> +      return -1;
>   
>       default:  /* including slices of enums, etc */
>         return (ctf_get_ctt_size (fp, tp, NULL, NULL));
> @@ -1235,7 +1257,8 @@ ctf_type_encoding (ctf_dict_t *fp, ctf_id_t type, ctf_encoding_t *ep)
>   	break;
>         }
>       default:
> -      return (ctf_set_errno (ofp, ECTF_NOTINTFP));
> +      ctf_set_errno (ofp, ECTF_NOTINTFP);
> +      return -1;
>       }
>   
>     return 0;
> @@ -1370,7 +1393,10 @@ ctf_member_count (ctf_dict_t *fp, ctf_id_t type)
>     kind = LCTF_INFO_KIND (fp, tp->ctt_info);
>   
>     if (kind != CTF_K_STRUCT && kind != CTF_K_UNION && kind != CTF_K_ENUM)
> -    return (ctf_set_errno (ofp, ECTF_NOTSUE));
> +    {
> +      ctf_set_errno (ofp, ECTF_NOTSUE);
> +      return -1;
> +    }
>   
>     return LCTF_INFO_VLEN (fp, tp->ctt_info);
>   }
> @@ -1398,7 +1424,10 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
>     kind = LCTF_INFO_KIND (fp, tp->ctt_info);
>   
>     if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
> -    return (ctf_set_errno (ofp, ECTF_NOTSOU));
> +    {
> +      ctf_set_errno (ofp, ECTF_NOTSOU);
> +      return -1;
> +    }
>   
>     n = LCTF_INFO_VLEN (fp, tp->ctt_info);
>     if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
> @@ -1418,7 +1447,10 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
>         const char *membname;
>   
>         if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0)
> -        return (ctf_set_errno (ofp, ctf_errno (fp)));
> +	{
> +	  ctf_set_errno (ofp, ctf_errno (fp));
> +	  return -1;
> +	}
>   
>         membname = ctf_strptr (fp, memb.ctlm_name);
>   
> @@ -1439,7 +1471,8 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
>   	}
>       }
>   
> -  return (ctf_set_errno (ofp, ECTF_NOMEMBNAM));
> +  ctf_set_errno (ofp, ECTF_NOMEMBNAM);
> +  return -1;
>   }
>   
>   /* Return the array type, index, and size information for the specified ARRAY.  */
> @@ -1457,7 +1490,10 @@ ctf_array_info (ctf_dict_t *fp, ctf_id_t type, ctf_arinfo_t *arp)
>       return -1;			/* errno is set for us.  */
>   
>     if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ARRAY)
> -    return (ctf_set_errno (ofp, ECTF_NOTARRAY));
> +    {
> +      ctf_set_errno (ofp, ECTF_NOTARRAY);
> +      return -1;
> +    }
>   
>     if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
>       ap = (const ctf_array_t *) dtd->dtd_vlen;
> @@ -1584,7 +1620,10 @@ ctf_func_type_info (ctf_dict_t *fp, ctf_id_t type, ctf_funcinfo_t *fip)
>     kind = LCTF_INFO_KIND (fp, tp->ctt_info);
>   
>     if (kind != CTF_K_FUNCTION)
> -    return (ctf_set_errno (ofp, ECTF_NOTFUNC));
> +    {
> +      ctf_set_errno (ofp, ECTF_NOTFUNC);
> +      return -1;
> +    }
>   
>     fip->ctc_return = tp->ctt_type;
>     fip->ctc_flags = 0;
> @@ -1697,7 +1736,10 @@ ctf_type_rvisit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func,
>         ctf_lmember_t memb;
>   
>         if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0)
> -        return (ctf_set_errno (ofp, ctf_errno (fp)));
> +	{
> +	  ctf_set_errno (ofp, ctf_errno (fp));
> +	  return -1;
> +	}
>   
>         if ((rc = ctf_type_rvisit (fp, memb.ctlm_type,
>   				 func, arg, ctf_strptr (fp, memb.ctlm_name),

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

* Re: [PATCH v2] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-08-30  8:34     ` Torbjorn SVENSSON
@ 2023-08-30  9:39       ` Alan Modra
  2023-09-07 12:10         ` Nick Alcock
  0 siblings, 1 reply; 41+ messages in thread
From: Alan Modra @ 2023-08-30  9:39 UTC (permalink / raw)
  To: Torbjorn SVENSSON, Nick Alcock; +Cc: binutils, Yvan ROUX

On Wed, Aug 30, 2023 at 10:34:05AM +0200, Torbjorn SVENSSON wrote:
> @Alan, any additional comments on this updated patch (except the missing
> semicolon that I mention below)?

I'm leaving it to Nick Alcock to decide what to do here.

-- 
Alan Modra
Australia Development Lab, IBM

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

* Re: [PATCH v2] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-08-30  9:39       ` Alan Modra
@ 2023-09-07 12:10         ` Nick Alcock
  2023-09-08 12:58           ` Torbjorn SVENSSON
  0 siblings, 1 reply; 41+ messages in thread
From: Nick Alcock @ 2023-09-07 12:10 UTC (permalink / raw)
  To: Torbjorn SVENSSON, Alan Modra, Yvan ROUX; +Cc: binutils

On 30 Aug 2023, Alan Modra via Binutils outgrape:

> On Wed, Aug 30, 2023 at 10:34:05AM +0200, Torbjorn SVENSSON wrote:
>> @Alan, any additional comments on this updated patch (except the missing
>> semicolon that I mention below)?
>
> I'm leaving it to Nick Alcock to decide what to do here.

I agree that we should indeed be returning -1 from all functions that
return an int (it used to, but ctf_id_t has to be an unsigned long). But
I think it might be less disruptive to do so via a new
ctf_set_errno_int() which is just like ctf_set_errno but returns an int
rather than an unsigned long. That eliminates a lot of {}ery and makes
each individual hunk smaller.

My concern is that it's really hard to validate all this -- can anyone
think of a trick that would emit *consistent* warnings if we called
return (ctf_set_errno()) from a function returning int? I mean this
returning-int thing is a change I made ages ago, and despite making it
*and* attempting to validate on 64-bit Windows I have clearly not got it
right because it's drifted right out of correctness again.

(Similarly, does anyone have a build/target triplet on which this goes
wrong? because it's not going wrong on any of my mingw64 or cygwin tests
as far as I can tell.)

I kinda wish we could rely on having C11 -- type-generic macros are made
for cases like this :(

-- 
NULL && (void)

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

* Re: [PATCH v2] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-09-07 12:10         ` Nick Alcock
@ 2023-09-08 12:58           ` Torbjorn SVENSSON
  2023-09-12 14:23             ` Nick Alcock
  0 siblings, 1 reply; 41+ messages in thread
From: Torbjorn SVENSSON @ 2023-09-08 12:58 UTC (permalink / raw)
  To: Nick Alcock, Alan Modra, Yvan ROUX; +Cc: binutils



On 2023-09-07 14:10, Nick Alcock wrote:
> On 30 Aug 2023, Alan Modra via Binutils outgrape:
> 
>> On Wed, Aug 30, 2023 at 10:34:05AM +0200, Torbjorn SVENSSON wrote:
>>> @Alan, any additional comments on this updated patch (except the missing
>>> semicolon that I mention below)?
>>
>> I'm leaving it to Nick Alcock to decide what to do here.
> 
> I agree that we should indeed be returning -1 from all functions that
> return an int (it used to, but ctf_id_t has to be an unsigned long). But
> I think it might be less disruptive to do so via a new
> ctf_set_errno_int() which is just like ctf_set_errno but returns an int
> rather than an unsigned long. That eliminates a lot of {}ery and makes
> each individual hunk smaller.

Ok, I can do that instead if that's considered the proper way.

> My concern is that it's really hard to validate all this -- can anyone
> think of a trick that would emit *consistent* warnings if we called
> return (ctf_set_errno()) from a function returning int? I mean this
> returning-int thing is a change I made ages ago, and despite making it
> *and* attempting to validate on 64-bit Windows I have clearly not got it
> right because it's drifted right out of correctness again.
>
> (Similarly, does anyone have a build/target triplet on which this goes
> wrong? because it's not going wrong on any of my mingw64 or cygwin tests
> as far as I can tell.)

I discovered the issue using the GCC12 package for arm-none-eabi that 
Arm released 
(https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads), but 
built using the x86_64-w64-mingw GCC compiler on Linux.

I've opened a ticket for the issue where I've attached 2 object files 
that you can use to reproduce the issue without needing to rebuild GCC + 
multlibs to verify the problem.
https://sourceware.org/bugzilla/show_bug.cgi?id=30836

> I kinda wish we could rely on having C11 -- type-generic macros are made
> for cases like this :(

Looks like it would be a nice fix indeed, but is there anything else 
that could be done to improve the situation without needing to go to C11?

Kind regards,
Torbjörn

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

* Re: [PATCH v2] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-09-08 12:58           ` Torbjorn SVENSSON
@ 2023-09-12 14:23             ` Nick Alcock
  2023-09-12 18:44               ` Torbjorn SVENSSON
  2023-09-13  9:57               ` [PATCH v3] " Torbjörn SVENSSON
  0 siblings, 2 replies; 41+ messages in thread
From: Nick Alcock @ 2023-09-12 14:23 UTC (permalink / raw)
  To: Torbjorn SVENSSON; +Cc: Alan Modra, Yvan ROUX, binutils

On 8 Sep 2023, Torbjorn SVENSSON told this:

> On 2023-09-07 14:10, Nick Alcock wrote:
>> On 30 Aug 2023, Alan Modra via Binutils outgrape:
>> 
>>> On Wed, Aug 30, 2023 at 10:34:05AM +0200, Torbjorn SVENSSON wrote:
>>>> @Alan, any additional comments on this updated patch (except the missing
>>>> semicolon that I mention below)?
>>>
>>> I'm leaving it to Nick Alcock to decide what to do here.
>> I agree that we should indeed be returning -1 from all functions that
>> return an int (it used to, but ctf_id_t has to be an unsigned long). But
>> I think it might be less disruptive to do so via a new
>> ctf_set_errno_int() which is just like ctf_set_errno but returns an int
>> rather than an unsigned long. That eliminates a lot of {}ery and makes
>> each individual hunk smaller.
>
> Ok, I can do that instead if that's considered the proper way.

I think it might be a good bit neater and a good bit less work :)

>> My concern is that it's really hard to validate all this -- can anyone
>> think of a trick that would emit *consistent* warnings if we called
>> return (ctf_set_errno()) from a function returning int? I mean this
>> returning-int thing is a change I made ages ago, and despite making it
>> *and* attempting to validate on 64-bit Windows I have clearly not got it
>> right because it's drifted right out of correctness again.
>>
>> (Similarly, does anyone have a build/target triplet on which this goes
>> wrong? because it's not going wrong on any of my mingw64 or cygwin tests
>> as far as I can tell.)
>
> I discovered the issue using the GCC12 package for arm-none-eabi that Arm released
> (https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads), but built using the x86_64-w64-mingw GCC compiler on Linux.

I'm wondering what the configure options were for binutils itself --
anything? was it a cross at all? (I'll admit this description has
confused me a bit: is this a cross from mingw64 to aarch64 or what?)

> I've opened a ticket for the issue where I've attached 2 object files that you can use to reproduce the issue without needing to
> rebuild GCC + multlibs to verify the problem.
> https://sourceware.org/bugzilla/show_bug.cgi?id=30836

Thanks! I hope I won't need them, but they might well come in handy...

>> I kinda wish we could rely on having C11 -- type-generic macros are made
>> for cases like this :(
>
> Looks like it would be a nice fix indeed, but is there anything else
> that could be done to improve the situation without needing to go to
> C11?

I've been trying to think of something other than adding whatever the
build is you saw this on to my regular test matrix.

-- 
NULL && (void)

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

* Re: [PATCH v2] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-09-12 14:23             ` Nick Alcock
@ 2023-09-12 18:44               ` Torbjorn SVENSSON
  2023-09-13  9:57               ` [PATCH v3] " Torbjörn SVENSSON
  1 sibling, 0 replies; 41+ messages in thread
From: Torbjorn SVENSSON @ 2023-09-12 18:44 UTC (permalink / raw)
  To: Nick Alcock; +Cc: Alan Modra, Yvan ROUX, binutils



On 2023-09-12 16:23, Nick Alcock wrote:
> On 8 Sep 2023, Torbjorn SVENSSON told this:
> 
>> On 2023-09-07 14:10, Nick Alcock wrote:
>>> On 30 Aug 2023, Alan Modra via Binutils outgrape:
>>>
>>>> On Wed, Aug 30, 2023 at 10:34:05AM +0200, Torbjorn SVENSSON wrote:
>>>>> @Alan, any additional comments on this updated patch (except the missing
>>>>> semicolon that I mention below)?
>>>>
>>>> I'm leaving it to Nick Alcock to decide what to do here.
>>> I agree that we should indeed be returning -1 from all functions that
>>> return an int (it used to, but ctf_id_t has to be an unsigned long). But
>>> I think it might be less disruptive to do so via a new
>>> ctf_set_errno_int() which is just like ctf_set_errno but returns an int
>>> rather than an unsigned long. That eliminates a lot of {}ery and makes
>>> each individual hunk smaller.
>>
>> Ok, I can do that instead if that's considered the proper way.
> 
> I think it might be a good bit neater and a good bit less work :)

Ok, I'll send a revised patch in the next few days.

>>> My concern is that it's really hard to validate all this -- can anyone
>>> think of a trick that would emit *consistent* warnings if we called
>>> return (ctf_set_errno()) from a function returning int? I mean this
>>> returning-int thing is a change I made ages ago, and despite making it
>>> *and* attempting to validate on 64-bit Windows I have clearly not got it
>>> right because it's drifted right out of correctness again.
>>>
>>> (Similarly, does anyone have a build/target triplet on which this goes
>>> wrong? because it's not going wrong on any of my mingw64 or cygwin tests
>>> as far as I can tell.)
>>
>> I discovered the issue using the GCC12 package for arm-none-eabi that Arm released
>> (https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads), but built using the x86_64-w64-mingw GCC compiler on Linux.
> 
> I'm wondering what the configure options were for binutils itself --
> anything? was it a cross at all? (I'll admit this description has
> confused me a bit: is this a cross from mingw64 to aarch64 or what?)

Sorry for not being more clear on this point.
This is the configure line used to reproduce the issue outside a full 
build of an arm-none-eabi toolchain. I'm sure that a few of the 
arguments to configure can be dropped without impact on the problem, but 
I leave that to the reader to decide.

INSTALL=/tmp/pr30836-libctf-inifinit-loop
./configure \
   --build=x86_64-linux-gnu \
   --host=x86_64-w64-mingw32 \
   --target=arm-none-eabi \
   --prefix=$INSTALL \
   --infodir=$INSTALL/share/doc/gcc-arm-none-eabi/info \
   --mandir=$INSTALL/share/doc/gcc-arm-none-eabi/man \
   --htmldir=$INSTALL/share/doc/gcc-arm-none-eabi/html \
   --pdfdir=$INSTALL/share/doc/gcc-arm-none-eabi/pdf \
   --disable-nls \
   --disable-werror \
   --disable-sim \
   --disable-gdb \
   --enable-interwork \
   --enable-plugins \
   --with-sysroot=$INSTALL/arm-none-eabi \
   --with-pkgversion=foo
make -j8 V=1 CFLAGS="-O0 -g"
make install


>> I've opened a ticket for the issue where I've attached 2 object files that you can use to reproduce the issue without needing to
>> rebuild GCC + multlibs to verify the problem.
>> https://sourceware.org/bugzilla/show_bug.cgi?id=30836
> 
> Thanks! I hope I won't need them, but they might well come in handy...

Using the above built binutils (ld.exe in this case) with the 
pr41893-1.o object file is enough to trigger the loop.

>>> I kinda wish we could rely on having C11 -- type-generic macros are made
>>> for cases like this :(
>>
>> Looks like it would be a nice fix indeed, but is there anything else
>> that could be done to improve the situation without needing to go to
>> C11?
> 
> I've been trying to think of something other than adding whatever the
> build is you saw this on to my regular test matrix.

You know both the code and the CTF format better than I do, so maybe you 
can take a look at the .ctf section in pr41893-1.o and see why it is 
wrongly handled. It might well be that the error that I stumbled on (not 
returning -1 on failure) is not the real problem... Maybe the real 
problem is something less obvious in the parsing of the object file itself?

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

* [PATCH v3] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-09-12 14:23             ` Nick Alcock
  2023-09-12 18:44               ` Torbjorn SVENSSON
@ 2023-09-13  9:57               ` Torbjörn SVENSSON
  2023-09-13 18:37                 ` Nick Alcock
  1 sibling, 1 reply; 41+ messages in thread
From: Torbjörn SVENSSON @ 2023-09-13  9:57 UTC (permalink / raw)
  To: binutils; +Cc: amodra, nick.alcock, Torbjörn SVENSSON, Yvan ROUX

v1 -> v2:
Changed all functions with signed interger return type to return -1 based on
comment from Alan.

v2 -> v3:
Added ctf_set_errno_signed function to return a signed -1 value based on
comment from Nick.


Ok for trunk?

---

The function ctf_member_next should return (ssize_t)-1 on
error. As the function ctf_set_errno returns (ctf_id_t)-1L and that is
then cast to "unsigned long" as it's the return type of the function,
it's not compatible and causes the value 0xffffffff to be returned on
64-bit Windows builds. As a result, the check for a negative value in
ctf_dedup_rhash_type will never be true and a resulting infinit loop is
created.

This was found testing an arm-none-eabi toolchain built with
x86_64-w64-mingw32. If the same source tree is built with
i686-w64-mingw32, everything appears to be working correctly.

libctf/
        * ctf-impl.h (ctf_set_errno_signed): New function.
        * ctf-util.c (ctf_set_errno_signed): Likewise.
        * ctf-create.c (ctf_add_enumerator): Call ctf_set_errno_signed.
        (ctf_add_funcobjt_sym): Likewise.
        (ctf_add_member_encoded): Likewise.
        (ctf_add_member_offset): Likewise.
        (ctf_add_variable): Likewise.
        (ctf_grow_ptrtab): Likewise.
        (ctf_grow_vlen): Likewise.
        (ctf_rollback): Likewise.
        (ctf_set_array): Likewise.
        (ctf_update): Likewise.
        * ctf-dedup.c (ctf_dedup_atoms_init): Likewise.
        (ctf_dedup_conflictify_unshared): Likewise.
        (ctf_dedup_detect_name_ambiguity): Likewise.
        (ctf_dedup_emit_struct_members): Likewise.
        (ctf_dedup_emit_type): Likewise.
        (ctf_dedup_hash_kind): Likewise.
        (ctf_dedup_init): Likewise.
        (ctf_dedup_mark_conflicting_hash): Likewise.
        (ctf_dedup_multiple_input_dicts): Likewise.
        (ctf_dedup_populate_mappings): Likewise.
        (ctf_dedup_record_origin): Likewise.
        (ctf_dedup_rwalk_output_mapping): Likewise.
        (ctf_dedup_walk_output_mapping): Likewise.
        * ctf-dump.c (ctf_dump_append): Likewise.
        (ctf_dump_header): Likewise.
        (ctf_dump_header_sectfield): Likewise.
        (ctf_dump_header_strfield): Likewise.
        (ctf_dump_label): Likewise.
        (ctf_dump_member): Likewise.
        (ctf_dump_str): Likewise.
        (ctf_dump_type): Likewise.
        (ctf_dump_var): Likewise.
        * ctf-labels.c (ctf_label_info): Likewise.
        (ctf_label_iter): Likewise.
        * ctf-link.c (ctf_link_add_ctf_internal): Likewise.
        (ctf_link_add_cu_mapping): Likewise.
        (ctf_link_add): Likewise.
        (ctf_link_deduplicating_one_symtypetab): Likewise.
        (ctf_link_deduplicating_per_cu): Likewise.
        (ctf_link_deduplicating_variables): Likewise.
        (ctf_link): Likewise.
        (ctf_link_one_variable): Likewise.
        * ctf-lookup.c (ctf_func_args): Likewise.
        (ctf_func_info): Likewise.
        (grow_pptrtab): Likewise.
        * ctf-open.c (ctf_cuname_set): Likewise.
        (ctf_import): Likewise.
        (ctf_parent_name_set): Likewise.
        (ctf_setmodel): Likewise.
        * ctf-serialize.c (ctf_gzwrite): Likewise.
        (ctf_serialize): Likewise.
        (symtypetab_density): Likewise.
        * ctf-string.c (ctf_str_move_pending): Likewise.
        * ctf-types.c (ctf_array_info): Likewise.
        (ctf_func_type_info): Likewise.
        (ctf_member_count): Likewise.
        (ctf_member_info): Likewise.
        (ctf_member_next): Likewise.
        (ctf_type_align): Likewise.
        (ctf_type_encoding): Likewise.
        (ctf_type_rvisit): Likewise.
        (ctf_type_size): Likewise.

Signed-off-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
Co-Authored-By: Yvan ROUX <yvan.roux@foss.st.com>
---
 libctf/ctf-create.c    | 66 +++++++++++++++++------------------
 libctf/ctf-dedup.c     | 78 +++++++++++++++++++++---------------------
 libctf/ctf-dump.c      | 22 ++++++------
 libctf/ctf-impl.h      |  1 +
 libctf/ctf-labels.c    |  6 ++--
 libctf/ctf-link.c      | 74 +++++++++++++++++++--------------------
 libctf/ctf-lookup.c    |  6 ++--
 libctf/ctf-open.c      | 16 ++++-----
 libctf/ctf-serialize.c | 28 +++++++--------
 libctf/ctf-string.c    |  6 ++--
 libctf/ctf-types.c     | 44 ++++++++++++------------
 libctf/ctf-util.c      | 12 +++++++
 12 files changed, 186 insertions(+), 173 deletions(-)

diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 6b342dc64a2..c6e64244aa9 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -60,7 +60,7 @@ ctf_grow_ptrtab (ctf_dict_t *fp)
 
       if ((new_ptrtab = realloc (fp->ctf_ptrtab,
 				 new_ptrtab_len * sizeof (uint32_t))) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_errno_signed (fp, ENOMEM));
 
       fp->ctf_ptrtab = new_ptrtab;
       memset (fp->ctf_ptrtab + fp->ctf_ptrtab_len, 0,
@@ -87,7 +87,7 @@ ctf_grow_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vlen)
 				dtd->dtd_vlen_alloc * 2)) == NULL)
     {
       dtd->dtd_vlen = old;
-      return (ctf_set_errno (fp, ENOMEM));
+      return (ctf_set_errno_signed (fp, ENOMEM));
     }
   memset (dtd->dtd_vlen + dtd->dtd_vlen_alloc, 0, dtd->dtd_vlen_alloc);
   dtd->dtd_vlen_alloc *= 2;
@@ -197,7 +197,7 @@ int
 ctf_update (ctf_dict_t *fp)
 {
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_errno_signed (fp, ECTF_RDONLY));
 
   fp->ctf_dtoldid = fp->ctf_typemax;
   return 0;
@@ -226,7 +226,7 @@ ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
   if (ctf_dynhash_insert (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type,
 			  dtd) < 0)
     {
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_errno_signed (fp, ENOMEM);
       return -1;
     }
 
@@ -239,7 +239,7 @@ ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
 	{
 	  ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t)
 			      dtd->dtd_type);
-	  ctf_set_errno (fp, ENOMEM);
+	  ctf_set_errno_signed (fp, ENOMEM);
 	  return -1;
 	}
     }
@@ -330,7 +330,7 @@ ctf_dvd_insert (ctf_dict_t *fp, ctf_dvdef_t *dvd)
 {
   if (ctf_dynhash_insert (fp->ctf_dvhash, dvd->dvd_name, dvd) < 0)
     {
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_errno_signed (fp, ENOMEM);
       return -1;
     }
   ctf_list_append (&fp->ctf_dvdefs, dvd);
@@ -391,10 +391,10 @@ ctf_rollback (ctf_dict_t *fp, ctf_snapshot_id_t id)
   ctf_dvdef_t *dvd, *nvd;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_errno_signed (fp, ECTF_RDONLY));
 
   if (fp->ctf_snapshot_lu >= id.snapshot_id)
-    return (ctf_set_errno (fp, ECTF_OVERROLLBACK));
+    return (ctf_set_errno_signed (fp, ECTF_OVERROLLBACK));
 
   for (dtd = ctf_list_next (&fp->ctf_dtdefs); dtd != NULL; dtd = ntd)
     {
@@ -723,11 +723,11 @@ ctf_set_array (ctf_dict_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
   ctf_array_t *vlen;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_errno_signed (fp, ECTF_RDONLY));
 
   if (dtd == NULL
       || LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info) != CTF_K_ARRAY)
-    return (ctf_set_errno (fp, ECTF_BADID));
+    return (ctf_set_errno_signed (fp, ECTF_BADID));
 
   vlen = (ctf_array_t *) dtd->dtd_vlen;
   fp->ctf_flags |= LCTF_DIRTY;
@@ -1055,23 +1055,23 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
   uint32_t kind, vlen, root;
 
   if (name == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_errno_signed (fp, EINVAL));
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_errno_signed (fp, ECTF_RDONLY));
 
   if (dtd == NULL)
-    return (ctf_set_errno (fp, ECTF_BADID));
+    return (ctf_set_errno_signed (fp, ECTF_BADID));
 
   kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
   root = LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info);
   vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
 
   if (kind != CTF_K_ENUM)
-    return (ctf_set_errno (fp, ECTF_NOTENUM));
+    return (ctf_set_errno_signed (fp, ECTF_NOTENUM));
 
   if (vlen == CTF_MAX_VLEN)
-    return (ctf_set_errno (fp, ECTF_DTFULL));
+    return (ctf_set_errno_signed (fp, ECTF_DTFULL));
 
   old_vlen = dtd->dtd_vlen;
   if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0)
@@ -1090,7 +1090,7 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
 
   for (i = 0; i < vlen; i++)
     if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
-      return (ctf_set_errno (fp, ECTF_DUPLICATE));
+      return (ctf_set_errno_signed (fp, ECTF_DUPLICATE));
 
   en[i].cte_name = ctf_str_add_pending (fp, name, &en[i].cte_name);
   en[i].cte_value = value;
@@ -1119,10 +1119,10 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   ctf_lmember_t *memb;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_errno_signed (fp, ECTF_RDONLY));
 
   if (dtd == NULL)
-    return (ctf_set_errno (fp, ECTF_BADID));
+    return (ctf_set_errno_signed (fp, ECTF_BADID));
 
   if (name != NULL && name[0] == '\0')
     name = NULL;
@@ -1132,10 +1132,10 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
 
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
-    return (ctf_set_errno (fp, ECTF_NOTSOU));
+    return (ctf_set_errno_signed (fp, ECTF_NOTSOU));
 
   if (vlen == CTF_MAX_VLEN)
-    return (ctf_set_errno (fp, ECTF_DTFULL));
+    return (ctf_set_errno_signed (fp, ECTF_DTFULL));
 
   old_vlen = dtd->dtd_vlen;
   if (ctf_grow_vlen (fp, dtd, sizeof (ctf_lmember_t) * (vlen + 1)) < 0)
@@ -1156,7 +1156,7 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
     {
       for (i = 0; i < vlen; i++)
 	if (strcmp (ctf_strptr (fp, memb[i].ctlm_name), name) == 0)
-	  return (ctf_set_errno (fp, ECTF_DUPLICATE));
+	  return (ctf_set_errno_signed (fp, ECTF_DUPLICATE));
     }
 
   if ((msize = ctf_type_size (fp, type)) < 0 ||
@@ -1174,7 +1174,7 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
       msize = 0;
       malign = 0;
       if (ctf_errno (fp) == ECTF_NONREPRESENTABLE)
-	ctf_set_errno (fp, 0);
+	ctf_set_errno_signed (fp, 0);
       else if (ctf_errno (fp) == ECTF_INCOMPLETE)
 	is_incomplete = 1;
       else
@@ -1212,7 +1212,7 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
 			      "incomplete type %lx to struct %lx without "
 			      "specifying explicit offset\n"),
 			    name ? name : _("(unnamed member)"), type, souid);
-	      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+	      return (ctf_set_errno_signed (fp, ECTF_INCOMPLETE));
 	    }
 
 	  if (ctf_type_encoding (fp, ltype, &linfo) == 0)
@@ -1285,7 +1285,7 @@ ctf_add_member_encoded (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   int otype = type;
 
   if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) && (kind != CTF_K_ENUM))
-    return (ctf_set_errno (fp, ECTF_NOTINTFP));
+    return (ctf_set_errno_signed (fp, ECTF_NOTINTFP));
 
   if ((type = ctf_add_slice (fp, CTF_ADD_NONROOT, otype, &encoding)) == CTF_ERR)
     return -1;			/* errno is set for us.  */
@@ -1307,10 +1307,10 @@ ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
   ctf_dict_t *tmp = fp;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_errno_signed (fp, ECTF_RDONLY));
 
   if (ctf_dvd_lookup (fp, name) != NULL)
-    return (ctf_set_errno (fp, ECTF_DUPLICATE));
+    return (ctf_set_errno_signed (fp, ECTF_DUPLICATE));
 
   if (ctf_lookup_by_id (&tmp, ref) == NULL)
     return -1;			/* errno is set for us.  */
@@ -1321,12 +1321,12 @@ ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
     return -1;
 
   if ((dvd = malloc (sizeof (ctf_dvdef_t))) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+    return (ctf_set_errno_signed (fp, EAGAIN));
 
   if (name != NULL && (dvd->dvd_name = strdup (name)) == NULL)
     {
       free (dvd);
-      return (ctf_set_errno (fp, EAGAIN));
+      return (ctf_set_errno_signed (fp, EAGAIN));
     }
   dvd->dvd_type = ref;
   dvd->dvd_snapshots = fp->ctf_snapshots;
@@ -1350,25 +1350,25 @@ ctf_add_funcobjt_sym (ctf_dict_t *fp, int is_function, const char *name, ctf_id_
   ctf_dynhash_t *h = is_function ? fp->ctf_funchash : fp->ctf_objthash;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_errno_signed (fp, ECTF_RDONLY));
 
   if (ctf_dynhash_lookup (fp->ctf_objthash, name) != NULL ||
       ctf_dynhash_lookup (fp->ctf_funchash, name) != NULL)
-    return (ctf_set_errno (fp, ECTF_DUPLICATE));
+    return (ctf_set_errno_signed (fp, ECTF_DUPLICATE));
 
   if (ctf_lookup_by_id (&tmp, id) == NULL)
     return -1;                                  /* errno is set for us.  */
 
   if (is_function && ctf_type_kind (fp, id) != CTF_K_FUNCTION)
-    return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    return (ctf_set_errno_signed (fp, ECTF_NOTFUNC));
 
   if ((dupname = strdup (name)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_errno_signed (fp, ENOMEM));
 
   if (ctf_dynhash_insert (h, dupname, (void *) (uintptr_t) id) < 0)
     {
       free (dupname);
-      return (ctf_set_errno (fp, ENOMEM));
+      return (ctf_set_errno_signed (fp, ENOMEM));
     }
   return 0;
 }
diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c
index 5fdddfd0b54..5ad15ffd67f 100644
--- a/libctf/ctf-dedup.c
+++ b/libctf/ctf-dedup.c
@@ -378,7 +378,7 @@ ctf_dedup_atoms_init (ctf_dict_t *fp)
       if ((fp->ctf_dedup_atoms_alloc
 	   = ctf_dynset_create (htab_hash_string, htab_eq_string,
 				free)) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	return ctf_set_errno_signed (fp, ENOMEM);
     }
   fp->ctf_dedup_atoms = fp->ctf_dedup_atoms_alloc;
   return 0;
@@ -543,7 +543,7 @@ ctf_dedup_record_origin (ctf_dict_t *fp, int input_num, const char *decorated,
 
   if (populate_origin)
     if (ctf_dynhash_cinsert (d->cd_struct_origin, decorated, origin) < 0)
-      return ctf_set_errno (fp, errno);
+      return ctf_set_errno_signed (fp, errno);
   return 0;
 }
 
@@ -1185,7 +1185,7 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
     }
   else
     if (ctf_dynhash_cinsert (d->cd_output_mapping_guard, id, hval) < 0)
-      return ctf_set_errno (fp, errno);
+      return ctf_set_errno_signed (fp, errno);
 #endif
 
   /* Record the type in the output mapping: if this is the first time this type
@@ -1197,17 +1197,17 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
 				      hval)) == NULL)
     {
       if (ctf_dynhash_cinsert (d->cd_output_first_gid, hval, id) < 0)
-	return ctf_set_errno (fp, errno);
+	return ctf_set_errno_signed (fp, errno);
 
       if ((type_ids = ctf_dynset_create (htab_hash_pointer,
 					 htab_eq_pointer,
 					 NULL)) == NULL)
-	return ctf_set_errno (fp, errno);
+	return ctf_set_errno_signed (fp, errno);
       if (ctf_dynhash_insert (d->cd_output_mapping, (void *) hval,
 			      type_ids) < 0)
 	{
 	  ctf_dynset_destroy (type_ids);
-	  return ctf_set_errno (fp, errno);
+	  return ctf_set_errno_signed (fp, errno);
 	}
     }
 #ifdef ENABLE_LIBCTF_HASH_DEBUGGING
@@ -1248,7 +1248,7 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
 	    }
 	}
       if (err != ECTF_NEXT_END)
-	return ctf_set_errno (fp, err);
+	return ctf_set_errno_signed (fp, err);
     }
 #endif
 
@@ -1256,7 +1256,7 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
      don't waste time reinserting the same keys in that case.  */
   if (!ctf_dynset_exists (type_ids, id, NULL)
       && ctf_dynset_insert (type_ids, id) < 0)
-    return ctf_set_errno (fp, errno);
+    return ctf_set_errno_signed (fp, errno);
 
   /* The rest only needs to happen for types with names.  */
   if (!decorated_name)
@@ -1273,12 +1273,12 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
       if ((name_counts = ctf_dynhash_create (ctf_hash_string,
 					     ctf_hash_eq_string,
 					     NULL, NULL)) == NULL)
-	  return ctf_set_errno (fp, errno);
+	  return ctf_set_errno_signed (fp, errno);
       if (ctf_dynhash_cinsert (d->cd_name_counts, decorated_name,
 			       name_counts) < 0)
 	{
 	  ctf_dynhash_destroy (name_counts);
-	  return ctf_set_errno (fp, errno);
+	  return ctf_set_errno_signed (fp, errno);
 	}
     }
 
@@ -1287,7 +1287,7 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
 
   if (ctf_dynhash_cinsert (name_counts, hval,
 			   (const void *) (uintptr_t) (count + 1)) < 0)
-    return ctf_set_errno (fp, errno);
+    return ctf_set_errno_signed (fp, errno);
 
   return 0;
 }
@@ -1318,7 +1318,7 @@ ctf_dedup_mark_conflicting_hash (ctf_dict_t *fp, const char *hval)
   if (ctf_dynset_cinsert (d->cd_conflicting_types, hval) < 0)
     {
       ctf_dprintf ("Out of memory marking %s as conflicted\n", hval);
-      ctf_set_errno (fp, errno);
+      ctf_set_errno_signed (fp, errno);
       return -1;
     }
 
@@ -1340,7 +1340,7 @@ ctf_dedup_mark_conflicting_hash (ctf_dict_t *fp, const char *hval)
 	}
     }
   if (err != ECTF_NEXT_END)
-    return ctf_set_errno (fp, err);
+    return ctf_set_errno_signed (fp, err);
 
   return 0;
 }
@@ -1366,7 +1366,7 @@ ctf_dedup_hash_kind (ctf_dict_t *fp, ctf_dict_t **inputs, const char *hash)
   if (!type_ids)
     {
       ctf_dprintf ("Looked up type kind by nonexistent hash %s.\n", hash);
-      return ctf_set_errno (fp, ECTF_INTERNAL);
+      return ctf_set_errno_signed (fp, ECTF_INTERNAL);
     }
   id = ctf_dynset_lookup_any (type_ids);
   if (!ctf_assert (fp, id))
@@ -1585,7 +1585,7 @@ ctf_dedup_detect_name_ambiguity (ctf_dict_t *fp, ctf_dict_t **inputs)
 
  iterr:
   ctf_err_warn (fp, 0, err, _("iteration failed: %s"), gettext (whaterr));
-  return ctf_set_errno (fp, err);
+  return ctf_set_errno_signed (fp, err);
 
  assert_err:
   ctf_next_destroy (i);
@@ -1683,7 +1683,7 @@ ctf_dedup_init (ctf_dict_t *fp)
  oom:
   ctf_err_warn (fp, 0, ENOMEM, _("ctf_dedup_init: cannot initialize: "
 				 "out of memory"));
-  return ctf_set_errno (fp, ENOMEM);
+  return ctf_set_errno_signed (fp, ENOMEM);
 }
 
 /* No ctf_dedup calls are allowed after this call other than starting a new
@@ -1784,7 +1784,7 @@ ctf_dedup_multiple_input_dicts (ctf_dict_t *output, ctf_dict_t **inputs,
     {
       ctf_err_warn (output, 0, err, _("iteration error "
 				      "propagating conflictedness"));
-      return ctf_set_errno (output, err);
+      return ctf_set_errno_signed (output, err);
     }
 
   if (multiple)
@@ -1872,14 +1872,14 @@ ctf_dedup_conflictify_unshared (ctf_dict_t *output, ctf_dict_t **inputs)
   return 0;
 
  err_no:
-  ctf_set_errno (output, errno);
+  ctf_set_errno_signed (output, errno);
  err:
   err = ctf_errno (output);
   ctf_next_destroy (i);
  iterr:
   ctf_dynset_destroy (to_mark);
   ctf_err_warn (output, 0, err, _("conflictifying unshared types"));
-  return ctf_set_errno (output, err);
+  return ctf_set_errno_signed (output, err);
 }
 
 /* The core deduplicator.  Populate cd_output_mapping in the output ctf_dedup
@@ -1913,7 +1913,7 @@ ctf_dedup (ctf_dict_t *output, ctf_dict_t **inputs, uint32_t ninputs,
       if (ctf_dynhash_insert (d->cd_input_nums, inputs[i],
 			      (void *) (uintptr_t) i) < 0)
 	{
-	  ctf_set_errno (output, errno);
+	  ctf_set_errno_signed (output, errno);
 	  ctf_err_warn (output, 0, errno, _("ctf_dedup: cannot initialize: %s\n"),
 			ctf_errmsg (errno));
 	  goto err;
@@ -1950,7 +1950,7 @@ ctf_dedup (ctf_dict_t *output, ctf_dict_t **inputs, uint32_t ninputs,
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
 	{
-	  ctf_set_errno (output, ctf_errno (inputs[i]));
+	  ctf_set_errno_signed (output, ctf_errno (inputs[i]));
 	  ctf_err_warn (output, 0, 0, _("iteration failure "
 					"computing type hashes"));
 	  goto err;
@@ -2176,7 +2176,7 @@ ctf_dedup_rwalk_one_output_mapping (ctf_dict_t *output,
 		    type_id, depth, arg);
 
  err_msg:
-  ctf_set_errno (output, ctf_errno (fp));
+  ctf_set_errno_signed (output, ctf_errno (fp));
   ctf_err_warn (output, 0, 0, _("%s in input file %s at type ID %lx"),
 		gettext (whaterr), ctf_link_input_name (fp), type);
  err:
@@ -2219,7 +2219,7 @@ ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
     {
       ctf_err_warn (output, 0, ECTF_INTERNAL,
 		    _("looked up type kind by nonexistent hash %s"), hval);
-      return ctf_set_errno (output, ECTF_INTERNAL);
+      return ctf_set_errno_signed (output, ECTF_INTERNAL);
     }
 
   /* Have we seen this type before?  */
@@ -2237,7 +2237,7 @@ ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
 	{
 	  ctf_err_warn (output, 0, ENOMEM,
 			_("out of memory tracking already-visited types"));
-	  return ctf_set_errno (output, ENOMEM);
+	  return ctf_set_errno_signed (output, ENOMEM);
 	}
     }
 
@@ -2274,7 +2274,7 @@ ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
   if (err != ECTF_NEXT_END)
     {
       ctf_err_warn (output, 0, err, _("cannot walk conflicted type"));
-      return ctf_set_errno (output, err);
+      return ctf_set_errno_signed (output, err);
     }
 
   return 0;
@@ -2376,7 +2376,7 @@ ctf_dedup_walk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
   if ((already_visited = ctf_dynset_create (htab_hash_string,
 					    htab_eq_string,
 					    NULL)) == NULL)
-    return ctf_set_errno (output, ENOMEM);
+    return ctf_set_errno_signed (output, ENOMEM);
 
   sort_arg.inputs = inputs;
   sort_arg.ninputs = ninputs;
@@ -2400,7 +2400,7 @@ ctf_dedup_walk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
   if (err != ECTF_NEXT_END)
     {
       ctf_err_warn (output, 0, err, _("cannot recurse over output mapping"));
-      ctf_set_errno (output, err);
+      ctf_set_errno_signed (output, err);
       goto err;
     }
   ctf_dynset_destroy (already_visited);
@@ -2664,7 +2664,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
 	      ctf_err_warn (output, 0, err,
 			    _("cannot create per-CU CTF archive for CU %s"),
 			    ctf_link_input_name (input));
-	      return ctf_set_errno (output, err);
+	      return ctf_set_errno_signed (output, err);
 	    }
 
 	  ctf_import_unref (target, output);
@@ -2687,7 +2687,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
       ctf_err_warn (output, 0, ctf_errno (input),
 		    _("%s: lookup failure for type %lx"),
 		    ctf_link_input_name (real_input), type);
-      return ctf_set_errno (output, ctf_errno (input));
+      return ctf_set_errno_signed (output, ctf_errno (input));
     }
 
   name = ctf_strraw (real_input, tp->ctt_name);
@@ -2765,7 +2765,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
 			      ctf_link_input_name (input), input_num, name,
 			      type);
 		ctf_next_destroy (i);
-		return ctf_set_errno (output, ctf_errno (target));
+		return ctf_set_errno_signed (output, ctf_errno (target));
 	      }
 	  }
 	if (ctf_errno (input) != ECTF_NEXT_END)
@@ -2860,7 +2860,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
 
 	if ((args = calloc (fi.ctc_argc, sizeof (ctf_id_t))) == NULL)
 	  {
-	    ctf_set_errno (input, ENOMEM);
+	    ctf_set_errno_signed (input, ENOMEM);
 	    goto err_input;
 	  }
 
@@ -2912,7 +2912,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
 	/* Record the need to emit the members of this structure later.  */
 	if (ctf_dynhash_insert (d->cd_emission_struct_members, id, out_id) < 0)
 	  {
-	    ctf_set_errno (target, errno);
+	    ctf_set_errno_signed (target, errno);
 	    goto err_target;
 	  }
 	break;
@@ -2921,7 +2921,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
       ctf_err_warn (output, 0, ECTF_CORRUPT, _("%s: unknown type kind for "
 					       "input type %lx"),
 		    ctf_link_input_name (input), type);
-      return ctf_set_errno (output, ECTF_CORRUPT);
+      return ctf_set_errno_signed (output, ECTF_CORRUPT);
     }
 
   if (!emission_hashed
@@ -2931,7 +2931,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
     {
       ctf_err_warn (output, 0, ENOMEM, _("out of memory tracking deduplicated "
 					 "global type IDs"));
-	return ctf_set_errno (output, ENOMEM);
+	return ctf_set_errno_signed (output, ENOMEM);
     }
 
   if (!emission_hashed && new_type != 0)
@@ -2944,21 +2944,21 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
  oom_hash:
   ctf_err_warn (output, 0, ENOMEM, _("out of memory creating emission-tracking "
 				     "hashes"));
-  return ctf_set_errno (output, ENOMEM);
+  return ctf_set_errno_signed (output, ENOMEM);
 
  err_input:
   ctf_err_warn (output, 0, ctf_errno (input),
 		_("%s (%i): while emitting deduplicated %s, error getting "
 		  "input type %lx"), ctf_link_input_name (input),
 		input_num, errtype, type);
-  return ctf_set_errno (output, ctf_errno (input));
+  return ctf_set_errno_signed (output, ctf_errno (input));
  err_target:
   ctf_err_warn (output, 0, ctf_errno (target),
 		_("%s (%i): while emitting deduplicated %s, error emitting "
 		  "target type from input type %lx"),
 		ctf_link_input_name (input), input_num,
 		errtype, type);
-  return ctf_set_errno (output, ctf_errno (target));
+  return ctf_set_errno_signed (output, ctf_errno (target));
 }
 
 /* Traverse the cd_emission_struct_members and emit the members of all
@@ -3051,11 +3051,11 @@ ctf_dedup_emit_struct_members (ctf_dict_t *output, ctf_dict_t **inputs,
   ctf_err_warn (output, 0, ctf_errno (err_fp),
 		_("%s (%i): error emitting members for structure type %lx"),
 		ctf_link_input_name (input_fp), input_num, err_type);
-  return ctf_set_errno (output, ctf_errno (err_fp));
+  return ctf_set_errno_signed (output, ctf_errno (err_fp));
  iterr:
   ctf_err_warn (output, 0, err, _("iteration failure emitting "
 				  "structure members"));
-  return ctf_set_errno (output, err);
+  return ctf_set_errno_signed (output, err);
 }
 
 /* Emit deduplicated types into the outputs.  The shared type repository is
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index 686951a9869..28b38c1d765 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -56,7 +56,7 @@ ctf_dump_append (ctf_dump_state_t *state, char *str)
   ctf_dump_item_t *cdi;
 
   if ((cdi = malloc (sizeof (struct ctf_dump_item))) == NULL)
-    return (ctf_set_errno (state->cds_fp, ENOMEM));
+    return (ctf_set_errno_signed (state->cds_fp, ENOMEM));
 
   cdi->cdi_item = str;
   ctf_list_append (&state->cds_items, cdi);
@@ -261,7 +261,7 @@ ctf_dump_header_strfield (ctf_dict_t *fp, ctf_dump_state_t *state,
   return 0;
 
  err:
-  return (ctf_set_errno (fp, errno));
+  return (ctf_set_errno_signed (fp, errno));
 }
 
 /* Dump one section-offset field from the file header into the cds_items.  */
@@ -281,7 +281,7 @@ ctf_dump_header_sectfield (ctf_dict_t *fp, ctf_dump_state_t *state,
   return 0;
 
  err:
-  return (ctf_set_errno (fp, errno));
+  return (ctf_set_errno_signed (fp, errno));
 }
 
 /* Dump the file header into the cds_items.  */
@@ -398,7 +398,7 @@ ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
   return 0;
  err:
   free (flagstr);
-  return (ctf_set_errno (fp, errno));
+  return (ctf_set_errno_signed (fp, errno));
 }
 
 /* Dump a single label into the cds_items.  */
@@ -412,7 +412,7 @@ ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
   ctf_dump_state_t *state = arg;
 
   if (asprintf (&str, "%s -> ", name) < 0)
-    return (ctf_set_errno (state->cds_fp, errno));
+    return (ctf_set_errno_signed (state->cds_fp, errno));
 
   if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type,
 				       CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
@@ -471,7 +471,7 @@ ctf_dump_objts (ctf_dict_t *fp, ctf_dump_state_t *state, int functions)
       continue;
 
     oom:
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_errno_signed (fp, ENOMEM);
       ctf_next_destroy (i);
       return -1;
     }
@@ -487,7 +487,7 @@ ctf_dump_var (const char *name, ctf_id_t type, void *arg)
   ctf_dump_state_t *state = arg;
 
   if (asprintf (&str, "%s -> ", name) < 0)
-    return (ctf_set_errno (state->cds_fp, errno));
+    return (ctf_set_errno_signed (state->cds_fp, errno));
 
   if ((typestr = ctf_dump_format_type (state->cds_fp, type,
 				       CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
@@ -540,7 +540,7 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
  oom:
   free (typestr);
   free (bit);
-  return (ctf_set_errno (state->cdm_fp, errno));
+  return (ctf_set_errno_signed (state->cdm_fp, errno));
 }
 
 /* Report the number of digits in the hexadecimal representation of a type
@@ -569,7 +569,7 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
 
   /* Indent neatly.  */
   if (asprintf (&indent, "    %*s", type_hex_digits (id), "") < 0)
-    return (ctf_set_errno (state->cds_fp, ENOMEM));
+    return (ctf_set_errno_signed (state->cds_fp, ENOMEM));
 
   /* Dump the type itself.  */
   if ((str = ctf_dump_format_type (state->cds_fp, id,
@@ -654,7 +654,7 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
  oom:
   free (indent);
   free (str);
-  return ctf_set_errno (state->cds_fp, ENOMEM);
+  return ctf_set_errno_signed (state->cds_fp, ENOMEM);
 }
 
 /* Dump the string table into the cds_items.  */
@@ -671,7 +671,7 @@ ctf_dump_str (ctf_dict_t *fp, ctf_dump_state_t *state)
       if (asprintf (&str, "0x%lx: %s",
 		    (unsigned long) (s - fp->ctf_str[CTF_STRTAB_0].cts_strs),
 		    s) < 0)
-	return (ctf_set_errno (fp, errno));
+	return (ctf_set_errno_signed (fp, errno));
       ctf_dump_append (state, str);
       s += strlen (s) + 1;
     }
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index da687762c89..ff3d2bf1f01 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -742,6 +742,7 @@ extern void ctf_arc_close_internal (struct ctf_archive *);
 extern const ctf_preamble_t *ctf_arc_bufpreamble (const ctf_sect_t *);
 extern void *ctf_set_open_errno (int *, int);
 extern unsigned long ctf_set_errno (ctf_dict_t *, int);
+extern int ctf_set_errno_signed (ctf_dict_t *, int);
 extern void ctf_flip_header (ctf_header_t *);
 extern int ctf_flip (ctf_dict_t *, ctf_header_t *, unsigned char *, int);
 
diff --git a/libctf/ctf-labels.c b/libctf/ctf-labels.c
index 16b111b14df..20d007d36d0 100644
--- a/libctf/ctf-labels.c
+++ b/libctf/ctf-labels.c
@@ -74,7 +74,7 @@ ctf_label_iter (ctf_dict_t *fp, ctf_label_f *func, void *arg)
     return -1;			/* errno is set for us.  */
 
   if (num_labels == 0)
-    return (ctf_set_errno (fp, ECTF_NOLABELDATA));
+    return (ctf_set_errno_signed (fp, ECTF_NOLABELDATA));
 
   for (i = 0; i < num_labels; i++, ctlp++)
     {
@@ -84,7 +84,7 @@ ctf_label_iter (ctf_dict_t *fp, ctf_label_f *func, void *arg)
 	  ctf_err_warn (fp, 0, ECTF_CORRUPT,
 			"failed to decode label %u with type %u",
 			ctlp->ctl_label, ctlp->ctl_type);
-	  return (ctf_set_errno (fp, ECTF_CORRUPT));
+	  return (ctf_set_errno_signed (fp, ECTF_CORRUPT));
 	}
 
       linfo.ctb_type = ctlp->ctl_type;
@@ -134,7 +134,7 @@ ctf_label_info (ctf_dict_t *fp, const char *lname, ctf_lblinfo_t *linfo)
     return rc;
 
   if (rc != 1)
-    return (ctf_set_errno (fp, ECTF_NOLABEL));
+    return (ctf_set_errno_signed (fp, ECTF_NOLABEL));
 
   return 0;
 }
diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c
index 9babec2aa37..33c8cc0cdcc 100644
--- a/libctf/ctf-link.c
+++ b/libctf/ctf-link.c
@@ -142,7 +142,7 @@ ctf_link_add_ctf_internal (ctf_dict_t *fp, ctf_archive_t *ctf,
  oom1:
   free (filename);
  oom:
-  return ctf_set_errno (fp, ENOMEM);
+  return ctf_set_errno_signed (fp, ENOMEM);
 }
 
 /* Add a file, memory buffer, or unopened file (by name) to a link.
@@ -173,12 +173,12 @@ ctf_link_add (ctf_dict_t *fp, ctf_archive_t *ctf, const char *name,
 	      void *buf _libctf_unused_, size_t n _libctf_unused_)
 {
   if (buf)
-    return (ctf_set_errno (fp, ECTF_NOTYET));
+    return (ctf_set_errno_signed (fp, ECTF_NOTYET));
 
   if (!((ctf && name && !buf)
 	|| (name && !buf && !ctf)
 	|| (buf && name && !ctf)))
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_errno_signed (fp, EINVAL));
 
   /* We can only lazily open files if libctf.so is in use rather than
      libctf-nobfd.so.  This is a little tricky: in shared libraries, we can use
@@ -187,21 +187,21 @@ ctf_link_add (ctf_dict_t *fp, ctf_archive_t *ctf, const char *name,
 
 #if defined (PIC)
   if (!buf && !ctf && name && !ctf_open)
-    return (ctf_set_errno (fp, ECTF_NEEDSBFD));
+    return (ctf_set_errno_signed (fp, ECTF_NEEDSBFD));
 #elif NOBFD
   if (!buf && !ctf && name)
-    return (ctf_set_errno (fp, ECTF_NEEDSBFD));
+    return (ctf_set_errno_signed (fp, ECTF_NEEDSBFD));
 #endif
 
   if (fp->ctf_link_outputs)
-    return (ctf_set_errno (fp, ECTF_LINKADDEDLATE));
+    return (ctf_set_errno_signed (fp, ECTF_LINKADDEDLATE));
   if (fp->ctf_link_inputs == NULL)
     fp->ctf_link_inputs = ctf_dynhash_create (ctf_hash_string,
 					      ctf_hash_eq_string, free,
 					      ctf_link_input_close);
 
   if (fp->ctf_link_inputs == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_errno_signed (fp, ENOMEM));
 
   return ctf_link_add_ctf_internal (fp, ctf, NULL, name);
 }
@@ -243,7 +243,7 @@ ctf_link_lazy_open (ctf_dict_t *fp, ctf_link_input_t *input)
 #else
   ctf_err_warn (fp, 0, ECTF_NEEDSBFD, _("cannot open %s lazily"),
 		input->clin_filename);
-  ctf_set_errno (fp, ECTF_NEEDSBFD);
+  ctf_set_errno_signed (fp, ECTF_NEEDSBFD);
   return -1;
 #endif
 
@@ -257,7 +257,7 @@ ctf_link_lazy_open (ctf_dict_t *fp, ctf_link_input_t *input)
 
       ctf_err_warn (fp, 0, err, _("opening CTF %s failed"),
 		    input->clin_filename);
-      ctf_set_errno (fp, err);
+      ctf_set_errno_signed (fp, err);
       return -1;
     }
 
@@ -378,7 +378,7 @@ ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
 
   /* Mappings cannot be set up if per-CU output dicts already exist.  */
   if (fp->ctf_link_outputs && ctf_dynhash_elements (fp->ctf_link_outputs) != 0)
-      return (ctf_set_errno (fp, ECTF_LINKADDEDLATE));
+      return (ctf_set_errno_signed (fp, ECTF_LINKADDEDLATE));
 
   if (fp->ctf_link_in_cu_mapping == NULL)
     fp->ctf_link_in_cu_mapping = ctf_dynhash_create (ctf_hash_string,
@@ -407,7 +407,7 @@ ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
 
   if ((err = ctf_dynhash_insert (fp->ctf_link_in_cu_mapping, f, t)) < 0)
     {
-      ctf_set_errno (fp, err);
+      ctf_set_errno_signed (fp, err);
       goto oom_noerrno;
     }
 
@@ -426,7 +426,7 @@ ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
 				     t, one_out)) < 0)
 	{
 	  ctf_dynhash_destroy (one_out);
-	  ctf_set_errno (fp, err);
+	  ctf_set_errno_signed (fp, err);
 	  goto oom_noerrno;
 	}
     }
@@ -438,14 +438,14 @@ ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
 
   if (ctf_dynhash_insert (one_out, f, NULL) < 0)
     {
-      ctf_set_errno (fp, err);
+      ctf_set_errno_signed (fp, err);
       goto oom_noerrno;
     }
 
   return 0;
 
  oom:
-  ctf_set_errno (fp, errno);
+  ctf_set_errno_signed (fp, errno);
  oom_noerrno:
   free (f);
   free (t);
@@ -582,7 +582,7 @@ ctf_link_one_variable (ctf_dict_t *fp, ctf_dict_t *in_fp, const char *name,
 
   if (check_variable (name, per_cu_out_fp, dst_type, &dvd))
     if (ctf_add_variable (per_cu_out_fp, name, dst_type) < 0)
-      return (ctf_set_errno (fp, ctf_errno (per_cu_out_fp)));
+      return (ctf_set_errno_signed (fp, ctf_errno (per_cu_out_fp)));
   return 0;
 }
 
@@ -680,7 +680,7 @@ ctf_link_deduplicating_count_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names,
     {
       ctf_err_warn (fp, 0, err, _("iteration error counting deduplicating "
 				  "CTF link inputs"));
-      ctf_set_errno (fp, err);
+      ctf_set_errno_signed (fp, err);
       return -1;
     }
 
@@ -877,7 +877,7 @@ ctf_link_deduplicating_close_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names,
 	{
 	  ctf_err_warn (fp, 0, err, _("iteration error in deduplicating link "
 				      "input freeing"));
-	  ctf_set_errno (fp, err);
+	  ctf_set_errno_signed (fp, err);
 	}
     }
   else
@@ -915,7 +915,7 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
 	    }
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
-	return ctf_set_errno (fp, ctf_errno (inputs[i]));
+	return ctf_set_errno_signed (fp, ctf_errno (inputs[i]));
 
       /* Next the symbols.  We integrate data symbols even though the compiler
 	 is currently doing the same, to allow the compiler to stop in
@@ -930,7 +930,7 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
 	    }
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
-	return ctf_set_errno (fp, ctf_errno (inputs[i]));
+	return ctf_set_errno_signed (fp, ctf_errno (inputs[i]));
 
       /* Finally the function symbols.  */
 
@@ -943,7 +943,7 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
 	    }
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
-	return ctf_set_errno (fp, ctf_errno (inputs[i]));
+	return ctf_set_errno_signed (fp, ctf_errno (inputs[i]));
     }
   return 0;
 }
@@ -1070,12 +1070,12 @@ ctf_link_deduplicating_one_symtypetab (ctf_dict_t *fp, ctf_dict_t *input,
 			_("symbol %s in input file %s found conflicting "
 			  "even when trying in per-CU dict."), name,
 			ctf_unnamed_cuname (input));
-	  return (ctf_set_errno (fp, ECTF_DUPLICATE));
+	  return (ctf_set_errno_signed (fp, ECTF_DUPLICATE));
 	}
     }
   if (ctf_errno (input) != ECTF_NEXT_END)
     {
-      ctf_set_errno (fp, ctf_errno (input));
+      ctf_set_errno_signed (fp, ctf_errno (input));
       ctf_err_warn (fp, 0, ctf_errno (input),
 		    functions ? _("iterating over function symbols") :
 		    _("iterating over data symbols"));
@@ -1147,7 +1147,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
 	{
 	  ctf_err_warn (fp, 0, EFBIG, _("too many inputs in deduplicating "
 					"link: %li"), (long int) ninputs);
-	  ctf_set_errno (fp, EFBIG);
+	  ctf_set_errno_signed (fp, EFBIG);
 	  goto err_open_inputs;
 	}
 
@@ -1172,7 +1172,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
 	      ctf_err_warn (fp, 0, err, _("cannot open archive %s in "
 					  "CU-mapped CTF link"),
 			    only_input->clin_filename);
-	      ctf_set_errno (fp, err);
+	      ctf_set_errno_signed (fp, err);
 	      goto err_open_inputs;
 	    }
 	  ctf_next_destroy (ai);
@@ -1218,7 +1218,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
 	  ctf_err_warn (fp, 0, err, _("cannot create per-CU CTF archive "
 				      "for %s"),
 			out_name);
-	  ctf_set_errno (fp, err);
+	  ctf_set_errno_signed (fp, err);
 	  goto err_inputs;
 	}
 
@@ -1233,7 +1233,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
 
       if (ctf_dedup (out, inputs, ninputs, parents, 1) < 0)
 	{
-	  ctf_set_errno (fp, ctf_errno (out));
+	  ctf_set_errno_signed (fp, ctf_errno (out));
 	  ctf_err_warn (fp, 0, 0, _("CU-mapped deduplication failed for %s"),
 			out_name);
 	  goto err_inputs;
@@ -1242,7 +1242,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
       if ((outputs = ctf_dedup_emit (out, inputs, ninputs, parents,
 				     &noutputs, 1)) == NULL)
 	{
-	  ctf_set_errno (fp, ctf_errno (out));
+	  ctf_set_errno_signed (fp, ctf_errno (out));
 	  ctf_err_warn (fp, 0, 0, _("CU-mapped deduplicating link type emission "
 				     "failed for %s"), out_name);
 	  goto err_inputs;
@@ -1258,7 +1258,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
       if (!(fp->ctf_link_flags & CTF_LINK_OMIT_VARIABLES_SECTION)
 	  && ctf_link_deduplicating_variables (out, inputs, ninputs, 1) < 0)
 	{
-	  ctf_set_errno (fp, ctf_errno (out));
+	  ctf_set_errno_signed (fp, ctf_errno (out));
 	  ctf_err_warn (fp, 0, 0, _("CU-mapped deduplicating link variable "
 				    "emission failed for %s"), out_name);
 	  goto err_inputs_outputs;
@@ -1291,7 +1291,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
       if ((in_arc = ctf_new_archive_internal (0, 0, NULL, outputs[0], NULL,
 					      NULL, &err)) == NULL)
 	{
-	  ctf_set_errno (fp, err);
+	  ctf_set_errno_signed (fp, err);
 	  goto err_outputs;
 	}
 
@@ -1330,7 +1330,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
     {
       ctf_err_warn (fp, 0, err, _("iteration error in CU-mapped deduplicating "
 				  "link"));
-      return ctf_set_errno (fp, err);
+      return ctf_set_errno_signed (fp, err);
     }
 
   return 0;
@@ -1355,7 +1355,7 @@ ctf_link_empty_outputs (ctf_dict_t *fp)
     {
       fp->ctf_flags &= ~LCTF_LINKING;
       ctf_err_warn (fp, 1, err, _("iteration error removing old outputs"));
-      ctf_set_errno (fp, err);
+      ctf_set_errno_signed (fp, err);
       return -1;
     }
   return 0;
@@ -1503,7 +1503,7 @@ ctf_link (ctf_dict_t *fp, int flags)
 					       ctf_dict_close);
 
   if (fp->ctf_link_outputs == NULL)
-    return ctf_set_errno (fp, ENOMEM);
+    return ctf_set_errno_signed (fp, ENOMEM);
 
   fp->ctf_flags |= LCTF_LINKING;
   ctf_link_deduplicating (fp);
@@ -1536,7 +1536,7 @@ ctf_link (ctf_dict_t *fp, int flags)
 	{
 	  fp->ctf_flags &= ~LCTF_LINKING;
 	  ctf_err_warn (fp, 1, err, _("iteration error creating empty CUs"));
-	  ctf_set_errno (fp, err);
+	  ctf_set_errno_signed (fp, err);
 	  return -1;
 	}
     }
@@ -1593,7 +1593,7 @@ ctf_link_add_strtab (ctf_dict_t *fp, ctf_link_strtab_string_f *add_string,
     }
 
   if (err)
-    ctf_set_errno (fp, err);
+    ctf_set_errno_signed (fp, err);
 
   return -err;
 }
@@ -1635,7 +1635,7 @@ ctf_link_add_linker_symbol (ctf_dict_t *fp, ctf_link_sym_t *sym)
  oom:
   ctf_dynhash_destroy (fp->ctf_dynsyms);
   fp->ctf_dynsyms = NULL;
-  ctf_set_errno (fp, ENOMEM);
+  ctf_set_errno_signed (fp, ENOMEM);
   return -ENOMEM;
 }
 
@@ -1658,7 +1658,7 @@ ctf_link_shuffle_syms (ctf_dict_t *fp)
 					    NULL, free);
       if (!fp->ctf_dynsyms)
 	{
-	  ctf_set_errno (fp, ENOMEM);
+	  ctf_set_errno_signed (fp, ENOMEM);
 	  return -ENOMEM;
 	}
     }
@@ -1758,7 +1758,7 @@ ctf_link_shuffle_syms (ctf_dict_t *fp)
   free (fp->ctf_dynsymidx);
   fp->ctf_dynsymidx = NULL;
   fp->ctf_dynsymmax = 0;
-  ctf_set_errno (fp, err);
+  ctf_set_errno_signed (fp, err);
   return -err;
 }
 
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index c65849118cb..61cde7a041f 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -30,7 +30,7 @@ grow_pptrtab (ctf_dict_t *fp, size_t new_len)
 
   if ((new_pptrtab = realloc (fp->ctf_pptrtab, sizeof (uint32_t)
 			      * new_len)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_errno_signed (fp, ENOMEM));
 
   fp->ctf_pptrtab = new_pptrtab;
 
@@ -1046,7 +1046,7 @@ ctf_func_info (ctf_dict_t *fp, unsigned long symidx, ctf_funcinfo_t *fip)
     return -1;					/* errno is set for us.  */
 
   if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
-    return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    return (ctf_set_errno_signed (fp, ECTF_NOTFUNC));
 
   return ctf_func_type_info (fp, type, fip);
 }
@@ -1064,7 +1064,7 @@ ctf_func_args (ctf_dict_t *fp, unsigned long symidx, uint32_t argc,
     return -1;					/* errno is set for us.  */
 
   if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
-    return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    return (ctf_set_errno_signed (fp, ECTF_NOTFUNC));
 
   return ctf_func_type_args (fp, type, argc, argv);
 }
diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c
index 35f635b6559..4c60d62f648 100644
--- a/libctf/ctf-open.c
+++ b/libctf/ctf-open.c
@@ -159,7 +159,7 @@ get_vbytes_common (ctf_dict_t *fp, unsigned short kind,
     case CTF_K_RESTRICT:
       return 0;
     default:
-      ctf_set_errno (fp, ECTF_CORRUPT);
+      ctf_set_errno_signed (fp, ECTF_CORRUPT);
       ctf_err_warn (fp, 0, 0, _("detected invalid CTF kind: %x"), kind);
       return -1;
     }
@@ -1935,7 +1935,7 @@ ctf_parent_name_set (ctf_dict_t *fp, const char *name)
     free (fp->ctf_dynparname);
 
   if ((fp->ctf_dynparname = strdup (name)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_errno_signed (fp, ENOMEM));
   fp->ctf_parname = fp->ctf_dynparname;
   return 0;
 }
@@ -1956,7 +1956,7 @@ ctf_cuname_set (ctf_dict_t *fp, const char *name)
     free (fp->ctf_dyncuname);
 
   if ((fp->ctf_dyncuname = strdup (name)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_errno_signed (fp, ENOMEM));
   fp->ctf_cuname = fp->ctf_dyncuname;
   return 0;
 }
@@ -1969,10 +1969,10 @@ int
 ctf_import (ctf_dict_t *fp, ctf_dict_t *pfp)
 {
   if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_errno_signed (fp, EINVAL));
 
   if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel)
-    return (ctf_set_errno (fp, ECTF_DMODEL));
+    return (ctf_set_errno_signed (fp, ECTF_DMODEL));
 
   if (fp->ctf_parent && !fp->ctf_parent_unreffed)
     ctf_dict_close (fp->ctf_parent);
@@ -2008,10 +2008,10 @@ int
 ctf_import_unref (ctf_dict_t *fp, ctf_dict_t *pfp)
 {
   if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_errno_signed (fp, EINVAL));
 
   if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel)
-    return (ctf_set_errno (fp, ECTF_DMODEL));
+    return (ctf_set_errno_signed (fp, ECTF_DMODEL));
 
   if (fp->ctf_parent && !fp->ctf_parent_unreffed)
     ctf_dict_close (fp->ctf_parent);
@@ -2052,7 +2052,7 @@ ctf_setmodel (ctf_dict_t *fp, int model)
 	}
     }
 
-  return (ctf_set_errno (fp, EINVAL));
+  return (ctf_set_errno_signed (fp, EINVAL));
 }
 
 /* Return the data model constant for the CTF dict.  */
diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
index ba830a2b095..e861ca0fcaf 100644
--- a/libctf/ctf-serialize.c
+++ b/libctf/ctf-serialize.c
@@ -123,7 +123,7 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 
       if ((linker_known = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
 					      NULL, NULL)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_errno_signed (fp, ENOMEM));
 
       while ((err = ctf_dynhash_cnext (symfp->ctf_dynsyms, &i,
 				       &name, &ctf_sym)) == 0)
@@ -147,7 +147,7 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 	  if (ctf_dynhash_cinsert (linker_known, name, ctf_sym) < 0)
 	    {
 	      ctf_dynhash_destroy (linker_known);
-	      return (ctf_set_errno (fp, ENOMEM));
+	      return (ctf_set_errno_signed (fp, ENOMEM));
 	    }
 	}
       if (err != ECTF_NEXT_END)
@@ -155,7 +155,7 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols during "
 				  "serialization"));
 	  ctf_dynhash_destroy (linker_known);
-	  return (ctf_set_errno (fp, err));
+	  return (ctf_set_errno_signed (fp, err));
 	}
     }
 
@@ -219,7 +219,7 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
       ctf_err_warn (fp, 0, err, _("iterating over CTF symtypetab during "
 				  "serialization"));
       ctf_dynhash_destroy (linker_known);
-      return (ctf_set_errno (fp, err));
+      return (ctf_set_errno_signed (fp, err));
     }
 
   if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
@@ -236,7 +236,7 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols "
 				      "during CTF serialization"));
 	  ctf_dynhash_destroy (linker_known);
-	  return (ctf_set_errno (fp, err));
+	  return (ctf_set_errno_signed (fp, err));
 	}
     }
 
@@ -709,7 +709,7 @@ ctf_emit_symtypetab_sects (ctf_dict_t *fp, emit_symtypetab_state_t *s,
   return 0;
 
  oom:
-  ctf_set_errno (fp, EAGAIN);
+  ctf_set_errno_signed (fp, EAGAIN);
   goto err;
 symerr:
   ctf_err_warn (fp, 0, err, _("error serializing symtypetabs"));
@@ -970,7 +970,7 @@ ctf_serialize (ctf_dict_t *fp)
   memset (&symstate, 0, sizeof (emit_symtypetab_state_t));
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_errno_signed (fp, ECTF_RDONLY));
 
   /* Update required?  */
   if (!(fp->ctf_flags & LCTF_DIRTY))
@@ -1026,7 +1026,7 @@ ctf_serialize (ctf_dict_t *fp)
   buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
 
   if ((buf = malloc (buf_size)) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+    return (ctf_set_errno_signed (fp, EAGAIN));
 
   memcpy (buf, &hdr, sizeof (ctf_header_t));
   t = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_objtoff;
@@ -1106,7 +1106,7 @@ ctf_serialize (ctf_dict_t *fp)
 				       1, &err)) == NULL)
     {
       free (buf);
-      return (ctf_set_errno (fp, err));
+      return (ctf_set_errno_signed (fp, err));
     }
 
   (void) ctf_setmodel (nfp, ctf_getmodel (fp));
@@ -1221,7 +1221,7 @@ ctf_serialize (ctf_dict_t *fp)
 
 oom:
   free (buf);
-  return (ctf_set_errno (fp, EAGAIN));
+  return (ctf_set_errno_signed (fp, EAGAIN));
 err:
   free (buf);
   return -1;					/* errno is set for us.  */
@@ -1248,7 +1248,7 @@ ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
   while (resid != 0)
     {
       if ((len = gzwrite (fd, buf, resid)) <= 0)
-	return (ctf_set_errno (fp, errno));
+	return (ctf_set_errno_signed (fp, errno));
       resid -= len;
       buf += len;
     }
@@ -1258,7 +1258,7 @@ ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
   while (resid != 0)
     {
       if ((len = gzwrite (fd, buf, resid)) <= 0)
-	return (ctf_set_errno (fp, errno));
+	return (ctf_set_errno_signed (fp, errno));
       resid -= len;
       buf += len;
     }
@@ -1378,7 +1378,7 @@ ctf_compress_write (ctf_dict_t *fp, int fd)
     {
       if ((len = write (fd, bp, buf_len)) < 0)
 	{
-	  err = ctf_set_errno (fp, errno);
+	  err = ctf_set_errno_signed (fp, errno);
 	  ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
 	  goto ret;
 	}
@@ -1412,7 +1412,7 @@ ctf_write (ctf_dict_t *fp, int fd)
     {
       if ((len = write (fd, bp, buf_len)) < 0)
 	{
-	  err = ctf_set_errno (fp, errno);
+	  err = ctf_set_errno_signed (fp, errno);
 	  ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
 	  goto ret;
 	}
diff --git a/libctf/ctf-string.c b/libctf/ctf-string.c
index 911e94700f1..6cb994e0302 100644
--- a/libctf/ctf-string.c
+++ b/libctf/ctf-string.c
@@ -298,7 +298,7 @@ ctf_str_move_pending (ctf_dict_t *fp, uint32_t *new_ref, ptrdiff_t bytes)
     return 0;
 
   if (ctf_dynset_insert (fp->ctf_str_pending_ref, (void *) new_ref) < 0)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_errno_signed (fp, ENOMEM));
 
   ctf_dynset_remove (fp->ctf_str_pending_ref,
 		     (void *) ((signed char *) new_ref - bytes));
@@ -327,7 +327,7 @@ ctf_str_add_external (ctf_dict_t *fp, const char *str, uint32_t offset)
 						 NULL, NULL);
   if (!fp->ctf_syn_ext_strtab)
     {
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_errno_signed (fp, ENOMEM);
       return 0;
     }
 
@@ -338,7 +338,7 @@ ctf_str_add_external (ctf_dict_t *fp, const char *str, uint32_t offset)
     {
       /* No need to bother freeing the syn_ext_strtab: it will get freed at
 	 ctf_str_write_strtab time if unreferenced.  */
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_errno_signed (fp, ENOMEM);
       return 0;
     }
 
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index c20ff825d9a..d94188bbc37 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -119,7 +119,7 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 	return -1;			/* errno is set for us.  */
 
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (ofp, ENOMEM);
+	return ctf_set_errno_signed (ofp, ENOMEM);
       i->cu.ctn_fp = ofp;
       i->ctn_tp = tp;
 
@@ -129,7 +129,7 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
       if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
 	{
 	  ctf_next_destroy (i);
-	  return (ctf_set_errno (ofp, ECTF_NOTSOU));
+	  return (ctf_set_errno_signed (ofp, ECTF_NOTSOU));
 	}
 
       if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
@@ -150,14 +150,14 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
     }
 
   if ((void (*) (void)) ctf_member_next != i->ctn_iter_fun)
-    return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN));
+    return (ctf_set_errno_signed (ofp, ECTF_NEXT_WRONGFUN));
 
   if (ofp != i->cu.ctn_fp)
-    return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFP));
+    return (ctf_set_errno_signed (ofp, ECTF_NEXT_WRONGFP));
 
   /* Resolve to the native dict of this type.  */
   if ((fp = ctf_get_dict (ofp, type)) == NULL)
-    return (ctf_set_errno (ofp, ECTF_NOPARENT));
+    return (ctf_set_errno_signed (ofp, ECTF_NOPARENT));
 
   max_vlen = LCTF_INFO_VLEN (fp, i->ctn_tp->ctt_info);
 
@@ -177,7 +177,7 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 
       if (ctf_struct_member (fp, &memb, i->ctn_tp, i->u.ctn_vlen, i->ctn_size,
 			     i->ctn_n) < 0)
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+        return (ctf_set_errno_signed (ofp, ctf_errno (fp)));
 
       membname = ctf_strptr (fp, memb.ctlm_name);
 
@@ -216,12 +216,12 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 	  ctf_next_destroy (i);
 	  *it = NULL;
 	  i->ctn_type = 0;
-	  ctf_set_errno (ofp, ctf_errno (fp));
+	  ctf_set_errno_signed (ofp, ctf_errno (fp));
 	  return ret;
 	}
 
       if (!ctf_assert (fp, (i->ctn_next == NULL)))
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+        return (ctf_set_errno_signed (ofp, ctf_errno (fp)));
 
       i->ctn_type = 0;
       /* This sub-struct has ended: on to the next real member.  */
@@ -233,7 +233,7 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
  end_iter:
   ctf_next_destroy (i);
   *it = NULL;
-  return ctf_set_errno (ofp, ECTF_NEXT_END);
+  return ctf_set_errno_signed (ofp, ECTF_NEXT_END);
 }
 
 /* Iterate over the members of an ENUM.  We pass the string name and associated
@@ -861,7 +861,7 @@ ctf_type_lname (ctf_dict_t *fp, ctf_id_t type, char *buf, size_t len)
   free (str);
 
   if (slen >= len)
-    (void) ctf_set_errno (fp, ECTF_NAMELEN);
+    (void) ctf_set_errno_signed (fp, ECTF_NAMELEN);
 
   return slen;
 }
@@ -956,7 +956,7 @@ ctf_type_size (ctf_dict_t *fp, ctf_id_t type)
 
     case CTF_K_FORWARD:
       /* Forwards do not have a meaningful size.  */
-      return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
+      return (ctf_set_errno_signed (ofp, ECTF_INCOMPLETE));
 
     default: /* including slices of enums, etc */
       return (ctf_get_ctt_size (fp, tp, NULL, NULL));
@@ -1039,7 +1039,7 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
 
     case CTF_K_FORWARD:
       /* Forwards do not have a meaningful alignment.  */
-      return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
+      return (ctf_set_errno_signed (ofp, ECTF_INCOMPLETE));
 
     default:  /* including slices of enums, etc */
       return (ctf_get_ctt_size (fp, tp, NULL, NULL));
@@ -1235,7 +1235,7 @@ ctf_type_encoding (ctf_dict_t *fp, ctf_id_t type, ctf_encoding_t *ep)
 	break;
       }
     default:
-      return (ctf_set_errno (ofp, ECTF_NOTINTFP));
+      return (ctf_set_errno_signed (ofp, ECTF_NOTINTFP));
     }
 
   return 0;
@@ -1370,7 +1370,7 @@ ctf_member_count (ctf_dict_t *fp, ctf_id_t type)
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION && kind != CTF_K_ENUM)
-    return (ctf_set_errno (ofp, ECTF_NOTSUE));
+    return (ctf_set_errno_signed (ofp, ECTF_NOTSUE));
 
   return LCTF_INFO_VLEN (fp, tp->ctt_info);
 }
@@ -1398,7 +1398,7 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
-    return (ctf_set_errno (ofp, ECTF_NOTSOU));
+    return (ctf_set_errno_signed (ofp, ECTF_NOTSOU));
 
   n = LCTF_INFO_VLEN (fp, tp->ctt_info);
   if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
@@ -1418,7 +1418,7 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
       const char *membname;
 
       if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0)
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+        return (ctf_set_errno_signed (ofp, ctf_errno (fp)));
 
       membname = ctf_strptr (fp, memb.ctlm_name);
 
@@ -1439,7 +1439,7 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
 	}
     }
 
-  return (ctf_set_errno (ofp, ECTF_NOMEMBNAM));
+  return (ctf_set_errno_signed (ofp, ECTF_NOMEMBNAM));
 }
 
 /* Return the array type, index, and size information for the specified ARRAY.  */
@@ -1457,7 +1457,7 @@ ctf_array_info (ctf_dict_t *fp, ctf_id_t type, ctf_arinfo_t *arp)
     return -1;			/* errno is set for us.  */
 
   if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ARRAY)
-    return (ctf_set_errno (ofp, ECTF_NOTARRAY));
+    return (ctf_set_errno_signed (ofp, ECTF_NOTARRAY));
 
   if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
     ap = (const ctf_array_t *) dtd->dtd_vlen;
@@ -1536,7 +1536,7 @@ ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp)
 
   if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM)
     {
-      (void) ctf_set_errno (ofp, ECTF_NOTENUM);
+      (void) ctf_set_errno_signed (ofp, ECTF_NOTENUM);
       return -1;
     }
 
@@ -1557,7 +1557,7 @@ ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp)
 	}
     }
 
-  ctf_set_errno (ofp, ECTF_NOENUMNAM);
+  ctf_set_errno_signed (ofp, ECTF_NOENUMNAM);
   return -1;
 }
 
@@ -1584,7 +1584,7 @@ ctf_func_type_info (ctf_dict_t *fp, ctf_id_t type, ctf_funcinfo_t *fip)
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
   if (kind != CTF_K_FUNCTION)
-    return (ctf_set_errno (ofp, ECTF_NOTFUNC));
+    return (ctf_set_errno_signed (ofp, ECTF_NOTFUNC));
 
   fip->ctc_return = tp->ctt_type;
   fip->ctc_flags = 0;
@@ -1697,7 +1697,7 @@ ctf_type_rvisit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func,
       ctf_lmember_t memb;
 
       if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0)
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+        return (ctf_set_errno_signed (ofp, ctf_errno (fp)));
 
       if ((rc = ctf_type_rvisit (fp, memb.ctlm_type,
 				 func, arg, ctf_strptr (fp, memb.ctlm_name),
diff --git a/libctf/ctf-util.c b/libctf/ctf-util.c
index 9f83ab9ab0b..022ce785f95 100644
--- a/libctf/ctf-util.c
+++ b/libctf/ctf-util.c
@@ -265,6 +265,18 @@ ctf_set_errno (ctf_dict_t *fp, int err)
   return CTF_ERR;
 }
 
+/* Store the specified error code into the CTF dict, and then return -1
+   (CTF_ERR) for the benefit of the caller. */
+
+int
+ctf_set_errno_signed (ctf_dict_t *fp, int err)
+{
+  fp->ctf_errno = err;
+  /* Don't rely on CTF_ERR here as it will not properly sign extend on 64-bit
+     Windows ABI.  */
+  return -1;
+}
+
 /* Create a ctf_next_t.  */
 
 ctf_next_t *
-- 
2.25.1


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

* Re: [PATCH v3] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-09-13  9:57               ` [PATCH v3] " Torbjörn SVENSSON
@ 2023-09-13 18:37                 ` Nick Alcock
  2023-09-13 20:20                   ` Torbjorn SVENSSON
  0 siblings, 1 reply; 41+ messages in thread
From: Nick Alcock @ 2023-09-13 18:37 UTC (permalink / raw)
  To: Torbjörn SVENSSON; +Cc: binutils, amodra, nick.alcock, Yvan ROUX

On 13 Sep 2023, Torbjörn SVENSSON verbalised:

> v1 -> v2:
> Changed all functions with signed interger return type to return -1 based on
> comment from Alan.
>
> v2 -> v3:
> Added ctf_set_errno_signed function to return a signed -1 value based on
> comment from Nick.
>
> Ok for trunk?

If this touches exactly those functions that return int, and fixes the
reported bug, it's good as far as I'm concerned, except for a couple of
possible comment improvements:

> +/* Store the specified error code into the CTF dict, and then return -1
> +   (CTF_ERR) for the benefit of the caller. */

It's not CTF_ERR in this case, it's just -1. Perhaps:

/* Store the specified error code into the CTF dict, and then return -1
   for the benefit of the caller, which is expected to return int,
   as opposed to ctf_id_t. */

> +int
> +ctf_set_errno_signed (ctf_dict_t *fp, int err)
> +{
> +  fp->ctf_errno = err;
> +  /* Don't rely on CTF_ERR here as it will not properly sign extend on 64-bit
> +     Windows ABI.  */
> +  return -1;
> +}

... that Windows is not really the problem here. It's more

/* Don't rely on CTF_ERR here; it is a ctf_id_t (unsigned long), and
   it will be truncated to a non--1 value on platforms on which int
   and unsigned long are different sizes.  */

perhaps? (At least, I think that's what's going on.)

This probably needs testing on a wide variety of platforms with
different type sizes. I'll add throwing this through my entire test
matrix to my todo list, and fix any bugs observed: but the basic idea
looks sound to me.

-- 
NULL && (void)

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

* Re: [PATCH v3] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-09-13 18:37                 ` Nick Alcock
@ 2023-09-13 20:20                   ` Torbjorn SVENSSON
  2023-09-20 17:44                     ` Torbjorn SVENSSON
  2023-09-26 14:51                     ` Nick Alcock
  0 siblings, 2 replies; 41+ messages in thread
From: Torbjorn SVENSSON @ 2023-09-13 20:20 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils, amodra, Yvan ROUX



On 2023-09-13 20:37, Nick Alcock wrote:
> On 13 Sep 2023, Torbjörn SVENSSON verbalised:
> 
>> v1 -> v2:
>> Changed all functions with signed interger return type to return -1 based on
>> comment from Alan.
>>
>> v2 -> v3:
>> Added ctf_set_errno_signed function to return a signed -1 value based on
>> comment from Nick.
>>
>> Ok for trunk?
> 
> If this touches exactly those functions that return int, and fixes the
> reported bug, it's good as far as I'm concerned, except for a couple of
> possible comment improvements:

I've verified the calls by building binutils (with the configure flags 
mentioned in my last mail) with CFLAGS="-Wsign-conversion -Wconversion" 
and looking for any warnings related to ctf_set_errno. After applying 
this patch, there were no warnings left.

>> +/* Store the specified error code into the CTF dict, and then return -1
>> +   (CTF_ERR) for the benefit of the caller. */
> 
> It's not CTF_ERR in this case, it's just -1. Perhaps:

True, but why is then ctf_set_errno returning CTF_ERR?
I somehow want to make it obvious that it's not wrong and that it should 
*never* be CTF_ERR in the signed function or the problem would reappear.

The other possibility is to do the inverse, meaning that the 
ctf_set_errno function is returning an integer (-1) and that there is a 
function ctf_set_errno_unsigned that is calling the ctf_set_errno 
function but casting the returned value to unsigned long (or ctf_id_t). 
I personally think this solution is a bit more clean as -1 is the error 
value from all functions, just a matter if it's signed or unsigned.

I.e:

int
ctf_set_errno (ctf_dict_t *fp, int err)
{
   fp->ctf_errno = err;
   return -1;
}

unsigned long
ctf_set_errno_unsigned (ctf_dict_t *fp, int err)
{
   return (unsigned long)ctf_set_errno (fp, err);
}

I suppose the ctf_set_errno_unsigned could even be a macro in the 
ctf-impl.h header file.



> /* Store the specified error code into the CTF dict, and then return -1
>     for the benefit of the caller, which is expected to return int,
>     as opposed to ctf_id_t. */
> 

Ok!

>> +int
>> +ctf_set_errno_signed (ctf_dict_t *fp, int err)
>> +{
>> +  fp->ctf_errno = err;
>> +  /* Don't rely on CTF_ERR here as it will not properly sign extend on 64-bit
>> +     Windows ABI.  */
>> +  return -1;
>> +}
> 
> ... that Windows is not really the problem here. It's more
> 
> /* Don't rely on CTF_ERR here; it is a ctf_id_t (unsigned long), and
>     it will be truncated to a non--1 value on platforms on which int
>     and unsigned long are different sizes.  */
> 
> perhaps? (At least, I think that's what's going on.)

The problem happens when the signed integral type is wider than unsigned 
long.

  /* Don't rely on CTF_ERR here; it is a ctf_id_t (unsigned long), and
      it will be extended to a non--1 value on platforms on which int
      is larger than unsigned long are different sizes.  */

> 
> This probably needs testing on a wide variety of platforms with
> different type sizes. I'll add throwing this through my entire test
> matrix to my todo list, and fix any bugs observed: but the basic idea
> looks sound to me.

Do you want to run this full matrix before or after submitting the patch?
If it's before; when do you think you will have time to do that?


Let me know how you want to proceed.

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

* Re: [PATCH v3] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-09-13 20:20                   ` Torbjorn SVENSSON
@ 2023-09-20 17:44                     ` Torbjorn SVENSSON
  2023-09-26 14:51                     ` Nick Alcock
  1 sibling, 0 replies; 41+ messages in thread
From: Torbjorn SVENSSON @ 2023-09-20 17:44 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils, amodra, Yvan ROUX

Ping?

On 2023-09-13 22:20, Torbjorn SVENSSON wrote:
> 
> 
> On 2023-09-13 20:37, Nick Alcock wrote:
>> On 13 Sep 2023, Torbjörn SVENSSON verbalised:
>>
>>> v1 -> v2:
>>> Changed all functions with signed interger return type to return -1 
>>> based on
>>> comment from Alan.
>>>
>>> v2 -> v3:
>>> Added ctf_set_errno_signed function to return a signed -1 value based on
>>> comment from Nick.
>>>
>>> Ok for trunk?
>>
>> If this touches exactly those functions that return int, and fixes the
>> reported bug, it's good as far as I'm concerned, except for a couple of
>> possible comment improvements:
> 
> I've verified the calls by building binutils (with the configure flags 
> mentioned in my last mail) with CFLAGS="-Wsign-conversion -Wconversion" 
> and looking for any warnings related to ctf_set_errno. After applying 
> this patch, there were no warnings left.
> 
>>> +/* Store the specified error code into the CTF dict, and then return -1
>>> +   (CTF_ERR) for the benefit of the caller. */
>>
>> It's not CTF_ERR in this case, it's just -1. Perhaps:
> 
> True, but why is then ctf_set_errno returning CTF_ERR?
> I somehow want to make it obvious that it's not wrong and that it should 
> *never* be CTF_ERR in the signed function or the problem would reappear.
> 
> The other possibility is to do the inverse, meaning that the 
> ctf_set_errno function is returning an integer (-1) and that there is a 
> function ctf_set_errno_unsigned that is calling the ctf_set_errno 
> function but casting the returned value to unsigned long (or ctf_id_t). 
> I personally think this solution is a bit more clean as -1 is the error 
> value from all functions, just a matter if it's signed or unsigned.
> 
> I.e:
> 
> int
> ctf_set_errno (ctf_dict_t *fp, int err)
> {
>    fp->ctf_errno = err;
>    return -1;
> }
> 
> unsigned long
> ctf_set_errno_unsigned (ctf_dict_t *fp, int err)
> {
>    return (unsigned long)ctf_set_errno (fp, err);
> }
> 
> I suppose the ctf_set_errno_unsigned could even be a macro in the 
> ctf-impl.h header file.
> 
> 
> 
>> /* Store the specified error code into the CTF dict, and then return -1
>>     for the benefit of the caller, which is expected to return int,
>>     as opposed to ctf_id_t. */
>>
> 
> Ok!
> 
>>> +int
>>> +ctf_set_errno_signed (ctf_dict_t *fp, int err)
>>> +{
>>> +  fp->ctf_errno = err;
>>> +  /* Don't rely on CTF_ERR here as it will not properly sign extend 
>>> on 64-bit
>>> +     Windows ABI.  */
>>> +  return -1;
>>> +}
>>
>> ... that Windows is not really the problem here. It's more
>>
>> /* Don't rely on CTF_ERR here; it is a ctf_id_t (unsigned long), and
>>     it will be truncated to a non--1 value on platforms on which int
>>     and unsigned long are different sizes.  */
>>
>> perhaps? (At least, I think that's what's going on.)
> 
> The problem happens when the signed integral type is wider than unsigned 
> long.
> 
>   /* Don't rely on CTF_ERR here; it is a ctf_id_t (unsigned long), and
>       it will be extended to a non--1 value on platforms on which int
>       is larger than unsigned long are different sizes.  */
> 
>>
>> This probably needs testing on a wide variety of platforms with
>> different type sizes. I'll add throwing this through my entire test
>> matrix to my todo list, and fix any bugs observed: but the basic idea
>> looks sound to me.
> 
> Do you want to run this full matrix before or after submitting the patch?
> If it's before; when do you think you will have time to do that?
> 
> 
> Let me know how you want to proceed.

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

* Re: [PATCH v3] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-09-13 20:20                   ` Torbjorn SVENSSON
  2023-09-20 17:44                     ` Torbjorn SVENSSON
@ 2023-09-26 14:51                     ` Nick Alcock
  2023-09-26 17:28                       ` [PATCH v4] " Torbjörn SVENSSON
  2023-09-26 17:49                       ` [PATCH v3] " Torbjorn SVENSSON
  1 sibling, 2 replies; 41+ messages in thread
From: Nick Alcock @ 2023-09-26 14:51 UTC (permalink / raw)
  To: Torbjorn SVENSSON; +Cc: binutils, amodra, Yvan ROUX

On 13 Sep 2023, Torbjorn SVENSSON outgrape:

> On 2023-09-13 20:37, Nick Alcock wrote:
>> On 13 Sep 2023, Torbjörn SVENSSON verbalised:
>> 
>>> v1 -> v2:
>>> Changed all functions with signed interger return type to return -1 based on
>>> comment from Alan.
>>>
>>> v2 -> v3:
>>> Added ctf_set_errno_signed function to return a signed -1 value based on
>>> comment from Nick.
>>>
>>> Ok for trunk?
>> If this touches exactly those functions that return int, and fixes the
>> reported bug, it's good as far as I'm concerned, except for a couple of
>> possible comment improvements:
>
> I've verified the calls by building binutils (with the configure flags mentioned in my last mail) with CFLAGS="-Wsign-conversion
> -Wconversion" and looking for any warnings related to ctf_set_errno. After applying this patch, there were no warnings left.

Oh right, that should work (given a platform on which this goes wrong in
the first place).

I should add -Wconversion to my test flags...

>>> +/* Store the specified error code into the CTF dict, and then return -1
>>> +   (CTF_ERR) for the benefit of the caller. */
>> It's not CTF_ERR in this case, it's just -1. Perhaps:
>
> True, but why is then ctf_set_errno returning CTF_ERR?

Simply because I foolishly assumed that CTF_ERR would always end up
== -1 even when passed through a function returning int. This is, uh,
not true.

I do wish that C was defined such that we had one consistent type we
could compare with for errors and not have to worry, but we don't:
functions returning a ctf_id_t return CTF_ERR on error, functions
returning an int return -1 on error and that's just the way it is :(
(This was always true, even in the Solaris era, but when ctf_id_t was an
int this was less visible than it is now.)

> I somehow want to make it obvious that it's not wrong and that it
> should *never* be CTF_ERR in the signed function or the problem would
> reappear.

Yeah.

> The other possibility is to do the inverse, meaning that the
> ctf_set_errno function is returning an integer (-1) and that there is
> a function ctf_set_errno_unsigned that is calling the ctf_set_errno
> function but casting the returned value to unsigned long (or

... and then all the ctf_id_t-returning functions call that?

> ctf_id_t). I personally think this solution is a bit more clean as -1
> is the error value from all functions, just a matter if it's signed or
> unsigned.

Honestly I suspect all we need is a better name:

ctf_set_int_errno(...);
ctf_set_type_errno(...)

and then use one or the other, consistently. (Neither needs to call the
other: they're only two lines long!)

> I suppose the ctf_set_errno_unsigned could even be a macro in the ctf-impl.h header file.

I'd make both of them inline functions personally (I bet it would reduce
code size!)

>>> +int
>>> +ctf_set_errno_signed (ctf_dict_t *fp, int err)
>>> +{
>>> +  fp->ctf_errno = err;
>>> +  /* Don't rely on CTF_ERR here as it will not properly sign extend on 64-bit
>>> +     Windows ABI.  */
>>> +  return -1;
>>> +}
>> ... that Windows is not really the problem here. It's more
>> /* Don't rely on CTF_ERR here; it is a ctf_id_t (unsigned long), and
>>     it will be truncated to a non--1 value on platforms on which int
>>     and unsigned long are different sizes.  */
>> perhaps? (At least, I think that's what's going on.)
>
> The problem happens when the signed integral type is wider than unsigned long.

... sizeof(signed int) > sizeof(unsigned long int)?! Is that even
possible? I would have assumed from the C type hierarchy and the integer
conversion rank rules would have required that unsigned long int was at
least as big as any non-long integral type, but I don't see anywhere
it's required in the standard, dammit...

>> This probably needs testing on a wide variety of platforms with
>> different type sizes. I'll add throwing this through my entire test
>> matrix to my todo list, and fix any bugs observed: but the basic idea
>> looks sound to me.
>
> Do you want to run this full matrix before or after submitting the patch?
> If it's before; when do you think you will have time to do that?
>
> Let me know how you want to proceed.

OK, I'm back from various conferences so I can throw tests past this at
any time, it's largely automated. So once I stop faffing about and
changing my mind and we converge on something I'll throw it past every
test I've got. (It takes a day or so.)

-- 
NULL && (void)

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

* [PATCH v4] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-09-26 14:51                     ` Nick Alcock
@ 2023-09-26 17:28                       ` Torbjörn SVENSSON
  2023-09-26 17:49                       ` [PATCH v3] " Torbjorn SVENSSON
  1 sibling, 0 replies; 41+ messages in thread
From: Torbjörn SVENSSON @ 2023-09-26 17:28 UTC (permalink / raw)
  To: binutils; +Cc: nick.alcock, amodra, Torbjörn SVENSSON, Yvan ROUX

v1 -> v2:
Changed all functions with signed interger return type to return -1 based on
comment from Alan.

v2 -> v3:
Added ctf_set_errno_signed function to return a signed -1 value based on
comment from Nick.

v3 -> v4:
- Moved ctf_set_errno_signed function to ctf-inlines.h, renamed it to
ctf_set_int_errno and converted it to an inline function.
- Moved ctf_set_errno function to ctf-inlines.h, renamed it to
ctf_set_type_errno, changed return type to ctf_id_t and converted it to an
inline function.
- Updated the changelog entry in the commit message. Is this list really
required? I don't think it give much information in this patch and 'git log'
have mixed commits (some have the entry while others don't).


@Nick: Can you please try this is in your test bench and let me know if it's
ok for trunk?

---

The function ctf_member_next should return (ssize_t)-1 on
error. As the function ctf_set_errno returns (ctf_id_t)-1L and that is
then cast to "unsigned long" as it's the return type of the function,
it's not compatible and causes the value 0xffffffff to be returned on
64-bit Windows builds. As a result, the check for a negative value in
ctf_dedup_rhash_type will never be true and a resulting infinit loop is
created.

This was found testing an arm-none-eabi toolchain built with
x86_64-w64-mingw32. If the same source tree is built with
i686-w64-mingw32, everything appears to be working correctly.

libctf/
	PR libctf/30836
        * ctf-inlines.h (ctf_set_int_errno): New function.
        (ctf_set_type_errno) Likewise.
	(ctf_assert_internal): Call ctf_set_type_errno.
        * ctf-impl.h (ctf_set_errno): Removed function.
        * ctf-util.c (ctf_set_errno): Likewise.
        * ctf-create.c (ctf_add_enumerator): Call ctf_set_int_errno.
        (ctf_add_funcobjt_sym): Likewise.
        (ctf_add_member_encoded): Likewise.
        (ctf_add_member_offset): Likewise.
        (ctf_add_variable): Likewise.
        (ctf_grow_ptrtab): Likewise.
        (ctf_grow_vlen): Likewise.
        (ctf_rollback): Likewise.
        (ctf_set_array): Likewise.
        (ctf_update): Likewise.
	(ctf_add_generic): Call ctf_set_type_errno.
	(ctf_add_encoded): Likewise.
	(ctf_add_reftype): Likewise.
	(ctf_add_slice): Likewise.
	(ctf_add_array): Likewise.
	(ctf_add_function): Likewise.
	(ctf_add_struct_sized): Likewise.
	(ctf_add_union_sized): Likewise.
	(ctf_add_enum): Likewise.
	(ctf_add_enum_encoded): Likewise.
	(ctf_add_forward): Likewise.
	(ctf_add_unknown): Likewise.
	(ctf_add_typedef): Likewise.
	(ctf_add_type_internal): Likewise.
	(ctf_add_type): Likewise.
        * ctf-dedup.c (ctf_dedup_atoms_init): Call ctf_set_int_errno.
        (ctf_dedup_conflictify_unshared): Likewise.
        (ctf_dedup_detect_name_ambiguity): Likewise.
        (ctf_dedup_emit_struct_members): Likewise.
        (ctf_dedup_emit_type): Likewise.
        (ctf_dedup_hash_kind): Likewise.
        (ctf_dedup_init): Likewise.
        (ctf_dedup_mark_conflicting_hash): Likewise.
        (ctf_dedup_multiple_input_dicts): Likewise.
        (ctf_dedup_populate_mappings): Likewise.
        (ctf_dedup_record_origin): Likewise.
        (ctf_dedup_rwalk_output_mapping): Likewise.
        (ctf_dedup_walk_output_mapping): Likewise.
	(id_to_packed_id): Call ctf_set_type_errno.
	(intern): Likewise.
	(ctf_decorate_type_name): Likewise.
	(ctf_dedup_rhash_type): Likewise.
	(ctf_dedup_hash_type): Likewise.
	(ctf_dedup_maybe_synthesize_forward): Likewise.
	(ctf_dedup_id_to_target): Likewise.
	(ctf_dedup_emit): Likewise.
	(ctf_dedup_type_mapping): Likewise.
        * ctf-dump.c (ctf_dump_append): Call ctf_set_int_errno.
        (ctf_dump_header): Likewise.
        (ctf_dump_header_sectfield): Likewise.
        (ctf_dump_header_strfield): Likewise.
        (ctf_dump_label): Likewise.
        (ctf_dump_member): Likewise.
        (ctf_dump_str): Likewise.
        (ctf_dump_type): Likewise.
        (ctf_dump_var): Likewise.
	(ctf_dump_format_type): Call ctf_set_type_errno.
	(ctf_dump): Likewise.
        * ctf-labels.c (ctf_label_info): Call ctf_set_int_errno.
        (ctf_label_iter): Likewise.
	(ctf_label_topmost): Call ctf_set_type_errno.
	(ctf_label_info): Likewise.
        * ctf-link.c (ctf_link_add_ctf_internal): Call ctf_set_int_errno.
        (ctf_link_add_cu_mapping): Likewise.
        (ctf_link_add): Likewise.
        (ctf_link_deduplicating_one_symtypetab): Likewise.
        (ctf_link_deduplicating_per_cu): Likewise.
        (ctf_link_deduplicating_variables): Likewise.
        (ctf_link): Likewise.
        (ctf_link_one_variable): Likewise.
	(ctf_create_per_cu): Call ctf_set_type_errno.
	(ctf_link_deduplicating_open_inputs): Likewise.
	(ctf_link_deduplicating): Likewise.
	(ctf_accumulate_archive_names): Likewise.
	(ctf_link_write): Likewise.
        * ctf-lookup.c (ctf_func_args): Call ctf_set_int_errno.
        (ctf_func_info): Likewise.
        (grow_pptrtab): Likewise.
	(ctf_lookup_by_name_internal): Call ctf_set_type_errno.
	(ctf_lookup_by_id): Likewise.
	(ctf_lookup_variable): Likewise.
	(ctf_symidx_sort): Likewise.
	(ctf_lookup_symbol_name): Likewise.
	(ctf_lookup_symbol_idx): Likewise.
	(ctf_symbol_next): Likewise.
	(ctf_try_lookup_indexed): Likewise.
	(ctf_lookup_by_sym_or_name): Likewise.
	(ctf_func_args): Likewise.
        * ctf-open.c (ctf_cuname_set): Call ctf_set_int_errno.
        (ctf_import): Likewise.
        (ctf_parent_name_set): Likewise.
        (ctf_setmodel): Likewise.
	(ctf_setmodel): Call ctf_set_type_errno.
        * ctf-serialize.c (ctf_gzwrite): Call ctf_set_int_errno.
        (ctf_serialize): Likewise.
        (symtypetab_density): Likewise.
	(ctf_write_mem): Call ctf_set_type_errno.
	(ctf_write): Likewise.
        * ctf-string.c (ctf_str_move_pending): Call ctf_set_int_errno.
	(ctf_str_add_ref_internal): Call ctf_set_type_errno.
	(ctf_str_add_external): Likewise.
	* ctf-subr.c (ctf_errwarning_next): Call ctf_set_type_errno.
	(ctf_assert_fail_internal): Likewise.
        * ctf-types.c (ctf_array_info): Call ctf_set_int_errno.
        (ctf_func_type_info): Likewise.
        (ctf_member_count): Likewise.
        (ctf_member_info): Likewise.
        (ctf_member_next): Likewise.
        (ctf_type_align): Likewise.
        (ctf_type_encoding): Likewise.
        (ctf_type_rvisit): Likewise.
        (ctf_type_size): Likewise.
	(ctf_enum_next): Call ctf_set_type_errno.
	(ctf_type_next): Likewise.
	(ctf_variable_next): Likewise.
	(ctf_type_resolve): Likewise.
	(ctf_type_resolve_unsliced): Likewise.
	(ctf_type_aname): Likewise.
	(ctf_type_reference): Likewise.
	(ctf_type_pointer): Likewise.
	(ctf_enum_name): Likewise.
	(ctf_type_rvisit): Likewise.

Signed-off-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
Co-Authored-By: Yvan ROUX <yvan.roux@foss.st.com>
---
 libctf/ctf-create.c    | 148 ++++++++++++++++++++---------------------
 libctf/ctf-dedup.c     | 102 ++++++++++++++--------------
 libctf/ctf-dump.c      |  42 ++++++------
 libctf/ctf-impl.h      |   1 -
 libctf/ctf-inlines.h   |  17 +++++
 libctf/ctf-labels.c    |  10 +--
 libctf/ctf-link.c      |  96 +++++++++++++-------------
 libctf/ctf-lookup.c    |  60 ++++++++---------
 libctf/ctf-open.c      |  16 ++---
 libctf/ctf-serialize.c |  34 +++++-----
 libctf/ctf-string.c    |   8 +--
 libctf/ctf-subr.c      |  10 +--
 libctf/ctf-types.c     | 108 +++++++++++++++---------------
 libctf/ctf-util.c      |  10 ---
 14 files changed, 334 insertions(+), 328 deletions(-)

diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 6b342dc64a2..46a85e1342d 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -60,7 +60,7 @@ ctf_grow_ptrtab (ctf_dict_t *fp)
 
       if ((new_ptrtab = realloc (fp->ctf_ptrtab,
 				 new_ptrtab_len * sizeof (uint32_t))) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_int_errno (fp, ENOMEM));
 
       fp->ctf_ptrtab = new_ptrtab;
       memset (fp->ctf_ptrtab + fp->ctf_ptrtab_len, 0,
@@ -87,7 +87,7 @@ ctf_grow_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vlen)
 				dtd->dtd_vlen_alloc * 2)) == NULL)
     {
       dtd->dtd_vlen = old;
-      return (ctf_set_errno (fp, ENOMEM));
+      return (ctf_set_int_errno (fp, ENOMEM));
     }
   memset (dtd->dtd_vlen + dtd->dtd_vlen_alloc, 0, dtd->dtd_vlen_alloc);
   dtd->dtd_vlen_alloc *= 2;
@@ -197,7 +197,7 @@ int
 ctf_update (ctf_dict_t *fp)
 {
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_int_errno (fp, ECTF_RDONLY));
 
   fp->ctf_dtoldid = fp->ctf_typemax;
   return 0;
@@ -226,7 +226,7 @@ ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
   if (ctf_dynhash_insert (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type,
 			  dtd) < 0)
     {
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_int_errno (fp, ENOMEM);
       return -1;
     }
 
@@ -239,7 +239,7 @@ ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
 	{
 	  ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t)
 			      dtd->dtd_type);
-	  ctf_set_errno (fp, ENOMEM);
+	  ctf_set_int_errno (fp, ENOMEM);
 	  return -1;
 	}
     }
@@ -330,7 +330,7 @@ ctf_dvd_insert (ctf_dict_t *fp, ctf_dvdef_t *dvd)
 {
   if (ctf_dynhash_insert (fp->ctf_dvhash, dvd->dvd_name, dvd) < 0)
     {
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_int_errno (fp, ENOMEM);
       return -1;
     }
   ctf_list_append (&fp->ctf_dvdefs, dvd);
@@ -391,10 +391,10 @@ ctf_rollback (ctf_dict_t *fp, ctf_snapshot_id_t id)
   ctf_dvdef_t *dvd, *nvd;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_int_errno (fp, ECTF_RDONLY));
 
   if (fp->ctf_snapshot_lu >= id.snapshot_id)
-    return (ctf_set_errno (fp, ECTF_OVERROLLBACK));
+    return (ctf_set_int_errno (fp, ECTF_OVERROLLBACK));
 
   for (dtd = ctf_list_next (&fp->ctf_dtdefs); dtd != NULL; dtd = ntd)
     {
@@ -453,23 +453,23 @@ ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
   ctf_id_t type;
 
   if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_type_errno (fp, EINVAL));
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_type_errno (fp, ECTF_RDONLY));
 
   if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) >= CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, ECTF_FULL));
+    return (ctf_set_type_errno (fp, ECTF_FULL));
 
   if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) == (CTF_MAX_PTYPE - 1))
-    return (ctf_set_errno (fp, ECTF_FULL));
+    return (ctf_set_type_errno (fp, ECTF_FULL));
 
   /* Make sure ptrtab always grows to be big enough for all types.  */
   if (ctf_grow_ptrtab (fp) < 0)
       return CTF_ERR;				/* errno is set for us. */
 
   if ((dtd = calloc (1, sizeof (ctf_dtdef_t))) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+    return (ctf_set_type_errno (fp, EAGAIN));
 
   dtd->dtd_vlen_alloc = vlen;
   if (vlen > 0)
@@ -499,7 +499,7 @@ ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
   return type;
 
  oom:
-  ctf_set_errno (fp, EAGAIN);
+  ctf_set_type_errno (fp, EAGAIN);
  err:
   free (dtd->dtd_vlen);
   free (dtd);
@@ -532,10 +532,10 @@ ctf_add_encoded (ctf_dict_t *fp, uint32_t flag,
   uint32_t encoding;
 
   if (ep == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_type_errno (fp, EINVAL));
 
   if (name == NULL || name[0] == '\0')
-    return (ctf_set_errno (fp, ECTF_NONAME));
+    return (ctf_set_type_errno (fp, ECTF_NONAME));
 
   if (!ctf_assert (fp, kind == CTF_K_INTEGER || kind == CTF_K_FLOAT))
     return -1;					/* errno is set for us.  */
@@ -570,7 +570,7 @@ ctf_add_reftype (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref, uint32_t kind)
   int child = fp->ctf_flags & LCTF_CHILD;
 
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_type_errno (fp, EINVAL));
 
   if (ref != 0 && ctf_lookup_by_id (&tmp, ref) == NULL)
     return CTF_ERR;		/* errno is set for us.  */
@@ -613,13 +613,13 @@ ctf_add_slice (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref,
   ctf_dict_t *tmp = fp;
 
   if (ep == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_type_errno (fp, EINVAL));
 
   if ((ep->cte_bits > 255) || (ep->cte_offset > 255))
-    return (ctf_set_errno (fp, ECTF_SLICEOVERFLOW));
+    return (ctf_set_type_errno (fp, ECTF_SLICEOVERFLOW));
 
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_type_errno (fp, EINVAL));
 
   if (ref != 0 && ((tp = ctf_lookup_by_id (&tmp, ref)) == NULL))
     return CTF_ERR;		/* errno is set for us.  */
@@ -634,7 +634,7 @@ ctf_add_slice (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref,
   if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) &&
       (kind != CTF_K_ENUM)
       && (ref != 0))
-    return (ctf_set_errno (fp, ECTF_NOTINTFP));
+    return (ctf_set_type_errno (fp, ECTF_NOTINTFP));
 
   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_SLICE,
 			       sizeof (ctf_slice_t), &dtd)) == CTF_ERR)
@@ -682,7 +682,7 @@ ctf_add_array (ctf_dict_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
   ctf_dict_t *tmp = fp;
 
   if (arp == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_type_errno (fp, EINVAL));
 
   if (arp->ctr_contents != 0
       && ctf_lookup_by_id (&tmp, arp->ctr_contents) == NULL)
@@ -697,7 +697,7 @@ ctf_add_array (ctf_dict_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
       ctf_err_warn (fp, 1, ECTF_INCOMPLETE,
 		    _("ctf_add_array: index type %lx is incomplete"),
 		    arp->ctr_contents);
-      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+      return (ctf_set_type_errno (fp, ECTF_INCOMPLETE));
     }
 
   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_ARRAY,
@@ -723,11 +723,11 @@ ctf_set_array (ctf_dict_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
   ctf_array_t *vlen;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_int_errno (fp, ECTF_RDONLY));
 
   if (dtd == NULL
       || LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info) != CTF_K_ARRAY)
-    return (ctf_set_errno (fp, ECTF_BADID));
+    return (ctf_set_int_errno (fp, ECTF_BADID));
 
   vlen = (ctf_array_t *) dtd->dtd_vlen;
   fp->ctf_flags |= LCTF_DIRTY;
@@ -751,11 +751,11 @@ ctf_add_function (ctf_dict_t *fp, uint32_t flag,
   size_t i;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_type_errno (fp, ECTF_RDONLY));
 
   if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0
       || (ctc->ctc_argc != 0 && argv == NULL))
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_type_errno (fp, EINVAL));
 
   vlen = ctc->ctc_argc;
   if (ctc->ctc_flags & CTF_FUNC_VARARG)
@@ -766,7 +766,7 @@ ctf_add_function (ctf_dict_t *fp, uint32_t flag,
     return CTF_ERR;				/* errno is set for us.  */
 
   if (vlen > CTF_MAX_VLEN)
-    return (ctf_set_errno (fp, EOVERFLOW));
+    return (ctf_set_type_errno (fp, EOVERFLOW));
 
   /* One word extra allocated for padding for 4-byte alignment if need be.
      Not reflected in vlen: we don't want to copy anything into it, and
@@ -818,7 +818,7 @@ ctf_add_struct_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (dtd->dtd_vlen_alloc == 0)
     {
       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_type_errno (fp, ENOMEM));
       dtd->dtd_vlen_alloc = initial_vlen;
     }
 
@@ -858,7 +858,7 @@ ctf_add_union_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (dtd->dtd_vlen_alloc == 0)
     {
       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_type_errno (fp, ENOMEM));
       dtd->dtd_vlen_alloc = initial_vlen;
     }
 
@@ -897,7 +897,7 @@ ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
   if (dtd->dtd_vlen_alloc == 0)
     {
       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_type_errno (fp, ENOMEM));
       dtd->dtd_vlen_alloc = initial_vlen;
     }
 
@@ -925,7 +925,7 @@ ctf_add_enum_encoded (ctf_dict_t *fp, uint32_t flag, const char *name,
     {
       if ((ctf_type_kind (fp, type) != CTF_K_FORWARD) &&
 	  (ctf_type_kind_unsliced (fp, type) != CTF_K_ENUM))
-	return (ctf_set_errno (fp, ECTF_NOTINTFP));
+	return (ctf_set_type_errno (fp, ECTF_NOTINTFP));
     }
   else if ((type = ctf_add_enum (fp, flag, name)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
@@ -943,10 +943,10 @@ ctf_add_forward (ctf_dict_t *fp, uint32_t flag, const char *name,
   ctf_id_t type = 0;
 
   if (!ctf_forwardable_kind (kind))
-    return (ctf_set_errno (fp, ECTF_NOTSUE));
+    return (ctf_set_type_errno (fp, ECTF_NOTSUE));
 
   if (name == NULL || name[0] == '\0')
-    return (ctf_set_errno (fp, ECTF_NONAME));
+    return (ctf_set_type_errno (fp, ECTF_NONAME));
 
   /* If the type is already defined or exists as a forward tag, just
      return the ctf_id_t of the existing definition.  */
@@ -985,7 +985,7 @@ ctf_add_unknown (ctf_dict_t *fp, uint32_t flag, const char *name)
 			_("ctf_add_unknown: cannot add unknown type "
 			  "named %s: type of this name already defined"),
 			name ? name : _("(unnamed type)"));
-	  return (ctf_set_errno (fp, ECTF_CONFLICT));
+	  return (ctf_set_type_errno (fp, ECTF_CONFLICT));
 	}
     }
 
@@ -1007,10 +1007,10 @@ ctf_add_typedef (ctf_dict_t *fp, uint32_t flag, const char *name,
   ctf_dict_t *tmp = fp;
 
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_type_errno (fp, EINVAL));
 
   if (name == NULL || name[0] == '\0')
-    return (ctf_set_errno (fp, ECTF_NONAME));
+    return (ctf_set_type_errno (fp, ECTF_NONAME));
 
   if (ref != 0 && ctf_lookup_by_id (&tmp, ref) == NULL)
     return CTF_ERR;		/* errno is set for us.  */
@@ -1055,23 +1055,23 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
   uint32_t kind, vlen, root;
 
   if (name == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_int_errno (fp, EINVAL));
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_int_errno (fp, ECTF_RDONLY));
 
   if (dtd == NULL)
-    return (ctf_set_errno (fp, ECTF_BADID));
+    return (ctf_set_int_errno (fp, ECTF_BADID));
 
   kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
   root = LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info);
   vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
 
   if (kind != CTF_K_ENUM)
-    return (ctf_set_errno (fp, ECTF_NOTENUM));
+    return (ctf_set_int_errno (fp, ECTF_NOTENUM));
 
   if (vlen == CTF_MAX_VLEN)
-    return (ctf_set_errno (fp, ECTF_DTFULL));
+    return (ctf_set_int_errno (fp, ECTF_DTFULL));
 
   old_vlen = dtd->dtd_vlen;
   if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0)
@@ -1090,7 +1090,7 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
 
   for (i = 0; i < vlen; i++)
     if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
-      return (ctf_set_errno (fp, ECTF_DUPLICATE));
+      return (ctf_set_int_errno (fp, ECTF_DUPLICATE));
 
   en[i].cte_name = ctf_str_add_pending (fp, name, &en[i].cte_name);
   en[i].cte_value = value;
@@ -1119,10 +1119,10 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   ctf_lmember_t *memb;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_int_errno (fp, ECTF_RDONLY));
 
   if (dtd == NULL)
-    return (ctf_set_errno (fp, ECTF_BADID));
+    return (ctf_set_int_errno (fp, ECTF_BADID));
 
   if (name != NULL && name[0] == '\0')
     name = NULL;
@@ -1132,10 +1132,10 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
 
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
-    return (ctf_set_errno (fp, ECTF_NOTSOU));
+    return (ctf_set_int_errno (fp, ECTF_NOTSOU));
 
   if (vlen == CTF_MAX_VLEN)
-    return (ctf_set_errno (fp, ECTF_DTFULL));
+    return (ctf_set_int_errno (fp, ECTF_DTFULL));
 
   old_vlen = dtd->dtd_vlen;
   if (ctf_grow_vlen (fp, dtd, sizeof (ctf_lmember_t) * (vlen + 1)) < 0)
@@ -1156,7 +1156,7 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
     {
       for (i = 0; i < vlen; i++)
 	if (strcmp (ctf_strptr (fp, memb[i].ctlm_name), name) == 0)
-	  return (ctf_set_errno (fp, ECTF_DUPLICATE));
+	  return (ctf_set_int_errno (fp, ECTF_DUPLICATE));
     }
 
   if ((msize = ctf_type_size (fp, type)) < 0 ||
@@ -1174,7 +1174,7 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
       msize = 0;
       malign = 0;
       if (ctf_errno (fp) == ECTF_NONREPRESENTABLE)
-	ctf_set_errno (fp, 0);
+	ctf_set_int_errno (fp, 0);
       else if (ctf_errno (fp) == ECTF_INCOMPLETE)
 	is_incomplete = 1;
       else
@@ -1212,7 +1212,7 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
 			      "incomplete type %lx to struct %lx without "
 			      "specifying explicit offset\n"),
 			    name ? name : _("(unnamed member)"), type, souid);
-	      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+	      return (ctf_set_int_errno (fp, ECTF_INCOMPLETE));
 	    }
 
 	  if (ctf_type_encoding (fp, ltype, &linfo) == 0)
@@ -1285,7 +1285,7 @@ ctf_add_member_encoded (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   int otype = type;
 
   if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) && (kind != CTF_K_ENUM))
-    return (ctf_set_errno (fp, ECTF_NOTINTFP));
+    return (ctf_set_int_errno (fp, ECTF_NOTINTFP));
 
   if ((type = ctf_add_slice (fp, CTF_ADD_NONROOT, otype, &encoding)) == CTF_ERR)
     return -1;			/* errno is set for us.  */
@@ -1307,10 +1307,10 @@ ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
   ctf_dict_t *tmp = fp;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_int_errno (fp, ECTF_RDONLY));
 
   if (ctf_dvd_lookup (fp, name) != NULL)
-    return (ctf_set_errno (fp, ECTF_DUPLICATE));
+    return (ctf_set_int_errno (fp, ECTF_DUPLICATE));
 
   if (ctf_lookup_by_id (&tmp, ref) == NULL)
     return -1;			/* errno is set for us.  */
@@ -1321,12 +1321,12 @@ ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
     return -1;
 
   if ((dvd = malloc (sizeof (ctf_dvdef_t))) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+    return (ctf_set_int_errno (fp, EAGAIN));
 
   if (name != NULL && (dvd->dvd_name = strdup (name)) == NULL)
     {
       free (dvd);
-      return (ctf_set_errno (fp, EAGAIN));
+      return (ctf_set_int_errno (fp, EAGAIN));
     }
   dvd->dvd_type = ref;
   dvd->dvd_snapshots = fp->ctf_snapshots;
@@ -1350,25 +1350,25 @@ ctf_add_funcobjt_sym (ctf_dict_t *fp, int is_function, const char *name, ctf_id_
   ctf_dynhash_t *h = is_function ? fp->ctf_funchash : fp->ctf_objthash;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_int_errno (fp, ECTF_RDONLY));
 
   if (ctf_dynhash_lookup (fp->ctf_objthash, name) != NULL ||
       ctf_dynhash_lookup (fp->ctf_funchash, name) != NULL)
-    return (ctf_set_errno (fp, ECTF_DUPLICATE));
+    return (ctf_set_int_errno (fp, ECTF_DUPLICATE));
 
   if (ctf_lookup_by_id (&tmp, id) == NULL)
     return -1;                                  /* errno is set for us.  */
 
   if (is_function && ctf_type_kind (fp, id) != CTF_K_FUNCTION)
-    return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    return (ctf_set_int_errno (fp, ECTF_NOTFUNC));
 
   if ((dupname = strdup (name)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_int_errno (fp, ENOMEM));
 
   if (ctf_dynhash_insert (h, dupname, (void *) (uintptr_t) id) < 0)
     {
       free (dupname);
-      return (ctf_set_errno (fp, ENOMEM));
+      return (ctf_set_int_errno (fp, ENOMEM));
     }
   return 0;
 }
@@ -1575,14 +1575,14 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
   ctf_id_t orig_src_type = src_type;
 
   if (!(dst_fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (dst_fp, ECTF_RDONLY));
+    return (ctf_set_type_errno (dst_fp, ECTF_RDONLY));
 
   if ((src_tp = ctf_lookup_by_id (&src_fp, src_type)) == NULL)
-    return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+    return (ctf_set_type_errno (dst_fp, ctf_errno (src_fp)));
 
   if ((ctf_type_resolve (src_fp, src_type) == CTF_ERR)
       && (ctf_errno (src_fp) == ECTF_NONREPRESENTABLE))
-    return (ctf_set_errno (dst_fp, ECTF_NONREPRESENTABLE));
+    return (ctf_set_type_errno (dst_fp, ECTF_NONREPRESENTABLE));
 
   name = ctf_strptr (src_fp, src_tp->ctt_name);
   kind = LCTF_INFO_KIND (src_fp, src_tp->ctt_info);
@@ -1661,7 +1661,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 			_("ctf_add_type: conflict for type %s: "
 			  "kinds differ, new: %i; old (ID %lx): %i"),
 			name, kind, dst_type, dst_kind);
-	  return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	  return (ctf_set_type_errno (dst_fp, ECTF_CONFLICT));
 	}
     }
 
@@ -1672,7 +1672,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
   if (kind == CTF_K_INTEGER || kind == CTF_K_FLOAT || kind == CTF_K_SLICE)
     {
       if (ctf_type_encoding (src_fp, src_type, &src_en) != 0)
-	return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+	return (ctf_set_type_errno (dst_fp, ctf_errno (src_fp)));
 
       if (dst_type != CTF_ERR)
 	{
@@ -1702,7 +1702,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 		}
 	      else
 		  {
-		    return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		    return (ctf_set_type_errno (dst_fp, ECTF_CONFLICT));
 		  }
 	    }
 	  else
@@ -1740,7 +1740,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 
   if (ctf_dynhash_insert (proc_tracking_fp->ctf_add_processing,
 			  (void *) (uintptr_t) src_type, (void *) 1) < 0)
-    return ctf_set_errno (dst_fp, ENOMEM);
+    return ctf_set_type_errno (dst_fp, ENOMEM);
 
   switch (kind)
     {
@@ -1785,7 +1785,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 
     case CTF_K_ARRAY:
       if (ctf_array_info (src_fp, src_type, &src_ar) != 0)
-	return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+	return (ctf_set_type_errno (dst_fp, ctf_errno (src_fp)));
 
       src_ar.ctr_contents =
 	ctf_add_type_internal (dst_fp, src_fp, src_ar.ctr_contents,
@@ -1812,7 +1812,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 			    src_ar.ctr_index, src_ar.ctr_nelems,
 			    dst_ar.ctr_contents, dst_ar.ctr_index,
 			    dst_ar.ctr_nelems);
-	      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	      return (ctf_set_type_errno (dst_fp, ECTF_CONFLICT));
 	    }
 	}
       else
@@ -1859,7 +1859,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 				"size differs, old %li, new %li"), name,
 			      dst_type, (long) ctf_type_size (src_fp, src_type),
 			      (long) ctf_type_size (dst_fp, dst_type));
-		return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		return (ctf_set_type_errno (dst_fp, ECTF_CONFLICT));
 	      }
 
 	    if (ctf_member_iter (src_fp, src_type, membcmp, &dst))
@@ -1867,7 +1867,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 		ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
 			      _("conflict for type %s against ID %lx: members "
 				"differ, see above"), name, dst_type);
-		return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		return (ctf_set_type_errno (dst_fp, ECTF_CONFLICT));
 	      }
 
 	    break;
@@ -1925,7 +1925,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 	      ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
 			    _("conflict for enum %s against ID %lx: members "
 			      "differ, see above"), name, dst_type);
-	      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	      return (ctf_set_type_errno (dst_fp, ECTF_CONFLICT));
 	    }
 	}
       else
@@ -1964,7 +1964,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
       break;
 
     default:
-      return (ctf_set_errno (dst_fp, ECTF_CORRUPT));
+      return (ctf_set_type_errno (dst_fp, ECTF_CORRUPT));
     }
 
   if (dst_type != CTF_ERR)
@@ -1985,7 +1985,7 @@ ctf_add_type (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type)
   /* We store the hash on the source, because it contains only source type IDs:
      but callers will invariably expect errors to appear on the dest.  */
   if (!src_fp->ctf_add_processing)
-    return (ctf_set_errno (dst_fp, ENOMEM));
+    return (ctf_set_type_errno (dst_fp, ENOMEM));
 
   id = ctf_add_type_internal (dst_fp, src_fp, src_type, src_fp);
   ctf_dynhash_empty (src_fp->ctf_add_processing);
diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c
index 5fdddfd0b54..96d2ff29535 100644
--- a/libctf/ctf-dedup.c
+++ b/libctf/ctf-dedup.c
@@ -321,7 +321,7 @@ id_to_packed_id (ctf_dict_t *fp, int input_num, ctf_id_t type)
 
  oom:
   free (dynkey);
-  ctf_set_errno (fp, ENOMEM);
+  ctf_set_type_errno (fp, ENOMEM);
   return NULL;
 }
 
@@ -378,7 +378,7 @@ ctf_dedup_atoms_init (ctf_dict_t *fp)
       if ((fp->ctf_dedup_atoms_alloc
 	   = ctf_dynset_create (htab_hash_string, htab_eq_string,
 				free)) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	return ctf_set_int_errno (fp, ENOMEM);
     }
   fp->ctf_dedup_atoms = fp->ctf_dedup_atoms_alloc;
   return 0;
@@ -398,7 +398,7 @@ intern (ctf_dict_t *fp, char *atom)
     {
       if (ctf_dynset_insert (fp->ctf_dedup_atoms, atom) < 0)
 	{
-	  ctf_set_errno (fp, ENOMEM);
+	  ctf_set_type_errno (fp, ENOMEM);
 	  return NULL;
 	}
       foo = atom;
@@ -461,7 +461,7 @@ ctf_decorate_type_name (ctf_dict_t *fp, const char *name, int kind)
   return ret;
 
  oom:
-  ctf_set_errno (fp, ENOMEM);
+  ctf_set_type_errno (fp, ENOMEM);
   return NULL;
 }
 
@@ -543,7 +543,7 @@ ctf_dedup_record_origin (ctf_dict_t *fp, int input_num, const char *decorated,
 
   if (populate_origin)
     if (ctf_dynhash_cinsert (d->cd_struct_origin, decorated, origin) < 0)
-      return ctf_set_errno (fp, errno);
+      return ctf_set_int_errno (fp, errno);
   return 0;
 }
 
@@ -981,7 +981,7 @@ ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs,
 		input_num, gettext (whaterr), type, kind);
   return NULL;
  oom:
-  ctf_set_errno (fp, errno);
+  ctf_set_type_errno (fp, errno);
   ctf_err_warn (fp, 0, 0, _("%s (%i): %s: during type hashing for type %lx, "
 			    "kind %i"), ctf_link_input_name (input),
 		input_num, gettext (whaterr), type, kind);
@@ -1051,7 +1051,7 @@ ctf_dedup_hash_type (ctf_dict_t *fp, ctf_dict_t *input,
 
   if ((tp = ctf_lookup_by_id (&input, type)) == NULL)
     {
-      ctf_set_errno (fp, ctf_errno (input));
+      ctf_set_type_errno (fp, ctf_errno (input));
       ctf_err_warn (fp, 0, 0, _("%s (%i): lookup failure for type %lx: "
 				"flags %x"), ctf_link_input_name (input),
 		    input_num, type, flags);
@@ -1140,7 +1140,7 @@ ctf_dedup_hash_type (ctf_dict_t *fp, ctf_dict_t *input,
   return hval;
 
  oom:
-  ctf_set_errno (fp, errno);
+  ctf_set_type_errno (fp, errno);
  err:
   ctf_err_warn (fp, 0, 0, _("%s (%i): %s: during type hashing, "
 			    "type %lx, kind %i"),
@@ -1185,7 +1185,7 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
     }
   else
     if (ctf_dynhash_cinsert (d->cd_output_mapping_guard, id, hval) < 0)
-      return ctf_set_errno (fp, errno);
+      return ctf_set_int_errno (fp, errno);
 #endif
 
   /* Record the type in the output mapping: if this is the first time this type
@@ -1197,17 +1197,17 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
 				      hval)) == NULL)
     {
       if (ctf_dynhash_cinsert (d->cd_output_first_gid, hval, id) < 0)
-	return ctf_set_errno (fp, errno);
+	return ctf_set_int_errno (fp, errno);
 
       if ((type_ids = ctf_dynset_create (htab_hash_pointer,
 					 htab_eq_pointer,
 					 NULL)) == NULL)
-	return ctf_set_errno (fp, errno);
+	return ctf_set_int_errno (fp, errno);
       if (ctf_dynhash_insert (d->cd_output_mapping, (void *) hval,
 			      type_ids) < 0)
 	{
 	  ctf_dynset_destroy (type_ids);
-	  return ctf_set_errno (fp, errno);
+	  return ctf_set_int_errno (fp, errno);
 	}
     }
 #ifdef ENABLE_LIBCTF_HASH_DEBUGGING
@@ -1248,7 +1248,7 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
 	    }
 	}
       if (err != ECTF_NEXT_END)
-	return ctf_set_errno (fp, err);
+	return ctf_set_int_errno (fp, err);
     }
 #endif
 
@@ -1256,7 +1256,7 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
      don't waste time reinserting the same keys in that case.  */
   if (!ctf_dynset_exists (type_ids, id, NULL)
       && ctf_dynset_insert (type_ids, id) < 0)
-    return ctf_set_errno (fp, errno);
+    return ctf_set_int_errno (fp, errno);
 
   /* The rest only needs to happen for types with names.  */
   if (!decorated_name)
@@ -1273,12 +1273,12 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
       if ((name_counts = ctf_dynhash_create (ctf_hash_string,
 					     ctf_hash_eq_string,
 					     NULL, NULL)) == NULL)
-	  return ctf_set_errno (fp, errno);
+	  return ctf_set_int_errno (fp, errno);
       if (ctf_dynhash_cinsert (d->cd_name_counts, decorated_name,
 			       name_counts) < 0)
 	{
 	  ctf_dynhash_destroy (name_counts);
-	  return ctf_set_errno (fp, errno);
+	  return ctf_set_int_errno (fp, errno);
 	}
     }
 
@@ -1287,7 +1287,7 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
 
   if (ctf_dynhash_cinsert (name_counts, hval,
 			   (const void *) (uintptr_t) (count + 1)) < 0)
-    return ctf_set_errno (fp, errno);
+    return ctf_set_int_errno (fp, errno);
 
   return 0;
 }
@@ -1318,7 +1318,7 @@ ctf_dedup_mark_conflicting_hash (ctf_dict_t *fp, const char *hval)
   if (ctf_dynset_cinsert (d->cd_conflicting_types, hval) < 0)
     {
       ctf_dprintf ("Out of memory marking %s as conflicted\n", hval);
-      ctf_set_errno (fp, errno);
+      ctf_set_int_errno (fp, errno);
       return -1;
     }
 
@@ -1340,7 +1340,7 @@ ctf_dedup_mark_conflicting_hash (ctf_dict_t *fp, const char *hval)
 	}
     }
   if (err != ECTF_NEXT_END)
-    return ctf_set_errno (fp, err);
+    return ctf_set_int_errno (fp, err);
 
   return 0;
 }
@@ -1366,7 +1366,7 @@ ctf_dedup_hash_kind (ctf_dict_t *fp, ctf_dict_t **inputs, const char *hash)
   if (!type_ids)
     {
       ctf_dprintf ("Looked up type kind by nonexistent hash %s.\n", hash);
-      return ctf_set_errno (fp, ECTF_INTERNAL);
+      return ctf_set_int_errno (fp, ECTF_INTERNAL);
     }
   id = ctf_dynset_lookup_any (type_ids);
   if (!ctf_assert (fp, id))
@@ -1585,7 +1585,7 @@ ctf_dedup_detect_name_ambiguity (ctf_dict_t *fp, ctf_dict_t **inputs)
 
  iterr:
   ctf_err_warn (fp, 0, err, _("iteration failed: %s"), gettext (whaterr));
-  return ctf_set_errno (fp, err);
+  return ctf_set_int_errno (fp, err);
 
  assert_err:
   ctf_next_destroy (i);
@@ -1683,7 +1683,7 @@ ctf_dedup_init (ctf_dict_t *fp)
  oom:
   ctf_err_warn (fp, 0, ENOMEM, _("ctf_dedup_init: cannot initialize: "
 				 "out of memory"));
-  return ctf_set_errno (fp, ENOMEM);
+  return ctf_set_int_errno (fp, ENOMEM);
 }
 
 /* No ctf_dedup calls are allowed after this call other than starting a new
@@ -1784,7 +1784,7 @@ ctf_dedup_multiple_input_dicts (ctf_dict_t *output, ctf_dict_t **inputs,
     {
       ctf_err_warn (output, 0, err, _("iteration error "
 				      "propagating conflictedness"));
-      return ctf_set_errno (output, err);
+      return ctf_set_int_errno (output, err);
     }
 
   if (multiple)
@@ -1872,14 +1872,14 @@ ctf_dedup_conflictify_unshared (ctf_dict_t *output, ctf_dict_t **inputs)
   return 0;
 
  err_no:
-  ctf_set_errno (output, errno);
+  ctf_set_int_errno (output, errno);
  err:
   err = ctf_errno (output);
   ctf_next_destroy (i);
  iterr:
   ctf_dynset_destroy (to_mark);
   ctf_err_warn (output, 0, err, _("conflictifying unshared types"));
-  return ctf_set_errno (output, err);
+  return ctf_set_int_errno (output, err);
 }
 
 /* The core deduplicator.  Populate cd_output_mapping in the output ctf_dedup
@@ -1913,7 +1913,7 @@ ctf_dedup (ctf_dict_t *output, ctf_dict_t **inputs, uint32_t ninputs,
       if (ctf_dynhash_insert (d->cd_input_nums, inputs[i],
 			      (void *) (uintptr_t) i) < 0)
 	{
-	  ctf_set_errno (output, errno);
+	  ctf_set_int_errno (output, errno);
 	  ctf_err_warn (output, 0, errno, _("ctf_dedup: cannot initialize: %s\n"),
 			ctf_errmsg (errno));
 	  goto err;
@@ -1950,7 +1950,7 @@ ctf_dedup (ctf_dict_t *output, ctf_dict_t **inputs, uint32_t ninputs,
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
 	{
-	  ctf_set_errno (output, ctf_errno (inputs[i]));
+	  ctf_set_int_errno (output, ctf_errno (inputs[i]));
 	  ctf_err_warn (output, 0, 0, _("iteration failure "
 					"computing type hashes"));
 	  goto err;
@@ -2176,7 +2176,7 @@ ctf_dedup_rwalk_one_output_mapping (ctf_dict_t *output,
 		    type_id, depth, arg);
 
  err_msg:
-  ctf_set_errno (output, ctf_errno (fp));
+  ctf_set_int_errno (output, ctf_errno (fp));
   ctf_err_warn (output, 0, 0, _("%s in input file %s at type ID %lx"),
 		gettext (whaterr), ctf_link_input_name (fp), type);
  err:
@@ -2219,7 +2219,7 @@ ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
     {
       ctf_err_warn (output, 0, ECTF_INTERNAL,
 		    _("looked up type kind by nonexistent hash %s"), hval);
-      return ctf_set_errno (output, ECTF_INTERNAL);
+      return ctf_set_int_errno (output, ECTF_INTERNAL);
     }
 
   /* Have we seen this type before?  */
@@ -2237,7 +2237,7 @@ ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
 	{
 	  ctf_err_warn (output, 0, ENOMEM,
 			_("out of memory tracking already-visited types"));
-	  return ctf_set_errno (output, ENOMEM);
+	  return ctf_set_int_errno (output, ENOMEM);
 	}
     }
 
@@ -2274,7 +2274,7 @@ ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
   if (err != ECTF_NEXT_END)
     {
       ctf_err_warn (output, 0, err, _("cannot walk conflicted type"));
-      return ctf_set_errno (output, err);
+      return ctf_set_int_errno (output, err);
     }
 
   return 0;
@@ -2376,7 +2376,7 @@ ctf_dedup_walk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
   if ((already_visited = ctf_dynset_create (htab_hash_string,
 					    htab_eq_string,
 					    NULL)) == NULL)
-    return ctf_set_errno (output, ENOMEM);
+    return ctf_set_int_errno (output, ENOMEM);
 
   sort_arg.inputs = inputs;
   sort_arg.ninputs = ninputs;
@@ -2400,7 +2400,7 @@ ctf_dedup_walk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
   if (err != ECTF_NEXT_END)
     {
       ctf_err_warn (output, 0, err, _("cannot recurse over output mapping"));
-      ctf_set_errno (output, err);
+      ctf_set_int_errno (output, err);
       goto err;
     }
   ctf_dynset_destroy (already_visited);
@@ -2452,7 +2452,7 @@ ctf_dedup_maybe_synthesize_forward (ctf_dict_t *output, ctf_dict_t *target,
       if ((emitted_forward = ctf_add_forward (target, CTF_ADD_ROOT, name,
 					      fwdkind)) == CTF_ERR)
 	{
-	  ctf_set_errno (output, ctf_errno (target));
+	  ctf_set_type_errno (output, ctf_errno (target));
 	  return CTF_ERR;
 	}
 
@@ -2460,7 +2460,7 @@ ctf_dedup_maybe_synthesize_forward (ctf_dict_t *output, ctf_dict_t *target,
 			       decorated, (void *) (uintptr_t)
 			       emitted_forward) < 0)
 	{
-	  ctf_set_errno (output, ENOMEM);
+	  ctf_set_type_errno (output, ENOMEM);
 	  return CTF_ERR;
 	}
     }
@@ -2550,7 +2550,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
     case 0: /* No forward needed.  */
       break;
     case -1:
-      ctf_set_errno (err_fp, ctf_errno (output));
+      ctf_set_type_errno (err_fp, ctf_errno (output));
       ctf_err_warn (err_fp, 0, 0, _("cannot add synthetic forward for type "
 				    "%i/%lx"), input_num, id);
       return -1;
@@ -2582,7 +2582,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
 	  ctf_err_warn (err_fp, 0, ctf_errno (output),
 			_("cannot add synthetic forward for type %i/%lx"),
 			input_num, id);
-	  return ctf_set_errno (err_fp, ctf_errno (output));
+	  return ctf_set_type_errno (err_fp, ctf_errno (output));
 	default:
 	  return emitted_forward;
 	}
@@ -2664,7 +2664,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
 	      ctf_err_warn (output, 0, err,
 			    _("cannot create per-CU CTF archive for CU %s"),
 			    ctf_link_input_name (input));
-	      return ctf_set_errno (output, err);
+	      return ctf_set_int_errno (output, err);
 	    }
 
 	  ctf_import_unref (target, output);
@@ -2687,7 +2687,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
       ctf_err_warn (output, 0, ctf_errno (input),
 		    _("%s: lookup failure for type %lx"),
 		    ctf_link_input_name (real_input), type);
-      return ctf_set_errno (output, ctf_errno (input));
+      return ctf_set_int_errno (output, ctf_errno (input));
     }
 
   name = ctf_strraw (real_input, tp->ctt_name);
@@ -2765,7 +2765,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
 			      ctf_link_input_name (input), input_num, name,
 			      type);
 		ctf_next_destroy (i);
-		return ctf_set_errno (output, ctf_errno (target));
+		return ctf_set_int_errno (output, ctf_errno (target));
 	      }
 	  }
 	if (ctf_errno (input) != ECTF_NEXT_END)
@@ -2860,7 +2860,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
 
 	if ((args = calloc (fi.ctc_argc, sizeof (ctf_id_t))) == NULL)
 	  {
-	    ctf_set_errno (input, ENOMEM);
+	    ctf_set_int_errno (input, ENOMEM);
 	    goto err_input;
 	  }
 
@@ -2912,7 +2912,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
 	/* Record the need to emit the members of this structure later.  */
 	if (ctf_dynhash_insert (d->cd_emission_struct_members, id, out_id) < 0)
 	  {
-	    ctf_set_errno (target, errno);
+	    ctf_set_int_errno (target, errno);
 	    goto err_target;
 	  }
 	break;
@@ -2921,7 +2921,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
       ctf_err_warn (output, 0, ECTF_CORRUPT, _("%s: unknown type kind for "
 					       "input type %lx"),
 		    ctf_link_input_name (input), type);
-      return ctf_set_errno (output, ECTF_CORRUPT);
+      return ctf_set_int_errno (output, ECTF_CORRUPT);
     }
 
   if (!emission_hashed
@@ -2931,7 +2931,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
     {
       ctf_err_warn (output, 0, ENOMEM, _("out of memory tracking deduplicated "
 					 "global type IDs"));
-	return ctf_set_errno (output, ENOMEM);
+	return ctf_set_int_errno (output, ENOMEM);
     }
 
   if (!emission_hashed && new_type != 0)
@@ -2944,21 +2944,21 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
  oom_hash:
   ctf_err_warn (output, 0, ENOMEM, _("out of memory creating emission-tracking "
 				     "hashes"));
-  return ctf_set_errno (output, ENOMEM);
+  return ctf_set_int_errno (output, ENOMEM);
 
  err_input:
   ctf_err_warn (output, 0, ctf_errno (input),
 		_("%s (%i): while emitting deduplicated %s, error getting "
 		  "input type %lx"), ctf_link_input_name (input),
 		input_num, errtype, type);
-  return ctf_set_errno (output, ctf_errno (input));
+  return ctf_set_int_errno (output, ctf_errno (input));
  err_target:
   ctf_err_warn (output, 0, ctf_errno (target),
 		_("%s (%i): while emitting deduplicated %s, error emitting "
 		  "target type from input type %lx"),
 		ctf_link_input_name (input), input_num,
 		errtype, type);
-  return ctf_set_errno (output, ctf_errno (target));
+  return ctf_set_int_errno (output, ctf_errno (target));
 }
 
 /* Traverse the cd_emission_struct_members and emit the members of all
@@ -3051,11 +3051,11 @@ ctf_dedup_emit_struct_members (ctf_dict_t *output, ctf_dict_t **inputs,
   ctf_err_warn (output, 0, ctf_errno (err_fp),
 		_("%s (%i): error emitting members for structure type %lx"),
 		ctf_link_input_name (input_fp), input_num, err_type);
-  return ctf_set_errno (output, ctf_errno (err_fp));
+  return ctf_set_int_errno (output, ctf_errno (err_fp));
  iterr:
   ctf_err_warn (output, 0, err, _("iteration failure emitting "
 				  "structure members"));
-  return ctf_set_errno (output, err);
+  return ctf_set_int_errno (output, err);
 }
 
 /* Emit deduplicated types into the outputs.  The shared type repository is
@@ -3101,7 +3101,7 @@ ctf_dedup_emit (ctf_dict_t *output, ctf_dict_t **inputs, uint32_t ninputs,
     {
       ctf_err_warn (output, 0, ENOMEM,
 		    _("out of memory allocating link outputs array"));
-      ctf_set_errno (output, ENOMEM);
+      ctf_set_type_errno (output, ENOMEM);
       return NULL;
     }
   *noutputs = num_outputs;
@@ -3152,7 +3152,7 @@ ctf_dedup_type_mapping (ctf_dict_t *fp, ctf_dict_t *src_fp, ctf_id_t src_type)
     output = fp->ctf_parent;
   else
     {
-      ctf_set_errno (fp, ECTF_INTERNAL);
+      ctf_set_type_errno (fp, ECTF_INTERNAL);
       ctf_err_warn (fp, 0, ECTF_INTERNAL,
 		    _("dict %p passed to ctf_dedup_type_mapping is not a "
 		      "deduplicated output"), (void *) fp);
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index 686951a9869..dfb2d671a95 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -56,7 +56,7 @@ ctf_dump_append (ctf_dump_state_t *state, char *str)
   ctf_dump_item_t *cdi;
 
   if ((cdi = malloc (sizeof (struct ctf_dump_item))) == NULL)
-    return (ctf_set_errno (state->cds_fp, ENOMEM));
+    return (ctf_set_int_errno (state->cds_fp, ENOMEM));
 
   cdi->cdi_item = str;
   ctf_list_append (&state->cds_items, cdi);
@@ -93,7 +93,7 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
   ctf_id_t new_id;
   char *str = NULL, *bit = NULL, *buf = NULL;
 
-  ctf_set_errno (fp, 0);
+  ctf_set_type_errno (fp, 0);
   new_id = id;
   do
     {
@@ -117,7 +117,7 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
 	{
 	  if (id == 0 || ctf_errno (fp) == ECTF_NONREPRESENTABLE)
 	    {
-	      ctf_set_errno (fp, ECTF_NONREPRESENTABLE);
+	      ctf_set_type_errno (fp, ECTF_NONREPRESENTABLE);
 	      str = str_append (str, " (type not represented in CTF)");
 	      return str;
 	    }
@@ -237,7 +237,7 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
   return str;
 
  oom:
-  ctf_set_errno (fp, errno);
+  ctf_set_type_errno (fp, errno);
  err:
   ctf_err_warn (fp, 1, 0, _("cannot format name dumping type 0x%lx"), id);
   free (buf);
@@ -261,7 +261,7 @@ ctf_dump_header_strfield (ctf_dict_t *fp, ctf_dump_state_t *state,
   return 0;
 
  err:
-  return (ctf_set_errno (fp, errno));
+  return (ctf_set_int_errno (fp, errno));
 }
 
 /* Dump one section-offset field from the file header into the cds_items.  */
@@ -281,7 +281,7 @@ ctf_dump_header_sectfield (ctf_dict_t *fp, ctf_dump_state_t *state,
   return 0;
 
  err:
-  return (ctf_set_errno (fp, errno));
+  return (ctf_set_int_errno (fp, errno));
 }
 
 /* Dump the file header into the cds_items.  */
@@ -398,7 +398,7 @@ ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
   return 0;
  err:
   free (flagstr);
-  return (ctf_set_errno (fp, errno));
+  return (ctf_set_int_errno (fp, errno));
 }
 
 /* Dump a single label into the cds_items.  */
@@ -412,7 +412,7 @@ ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
   ctf_dump_state_t *state = arg;
 
   if (asprintf (&str, "%s -> ", name) < 0)
-    return (ctf_set_errno (state->cds_fp, errno));
+    return (ctf_set_int_errno (state->cds_fp, errno));
 
   if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type,
 				       CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
@@ -471,7 +471,7 @@ ctf_dump_objts (ctf_dict_t *fp, ctf_dump_state_t *state, int functions)
       continue;
 
     oom:
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_int_errno (fp, ENOMEM);
       ctf_next_destroy (i);
       return -1;
     }
@@ -487,7 +487,7 @@ ctf_dump_var (const char *name, ctf_id_t type, void *arg)
   ctf_dump_state_t *state = arg;
 
   if (asprintf (&str, "%s -> ", name) < 0)
-    return (ctf_set_errno (state->cds_fp, errno));
+    return (ctf_set_int_errno (state->cds_fp, errno));
 
   if ((typestr = ctf_dump_format_type (state->cds_fp, type,
 				       CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
@@ -540,7 +540,7 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
  oom:
   free (typestr);
   free (bit);
-  return (ctf_set_errno (state->cdm_fp, errno));
+  return (ctf_set_int_errno (state->cdm_fp, errno));
 }
 
 /* Report the number of digits in the hexadecimal representation of a type
@@ -569,7 +569,7 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
 
   /* Indent neatly.  */
   if (asprintf (&indent, "    %*s", type_hex_digits (id), "") < 0)
-    return (ctf_set_errno (state->cds_fp, ENOMEM));
+    return (ctf_set_int_errno (state->cds_fp, ENOMEM));
 
   /* Dump the type itself.  */
   if ((str = ctf_dump_format_type (state->cds_fp, id,
@@ -654,7 +654,7 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
  oom:
   free (indent);
   free (str);
-  return ctf_set_errno (state->cds_fp, ENOMEM);
+  return ctf_set_int_errno (state->cds_fp, ENOMEM);
 }
 
 /* Dump the string table into the cds_items.  */
@@ -671,7 +671,7 @@ ctf_dump_str (ctf_dict_t *fp, ctf_dump_state_t *state)
       if (asprintf (&str, "0x%lx: %s",
 		    (unsigned long) (s - fp->ctf_str[CTF_STRTAB_0].cts_strs),
 		    s) < 0)
-	return (ctf_set_errno (fp, errno));
+	return (ctf_set_int_errno (fp, errno));
       ctf_dump_append (state, str);
       s += strlen (s) + 1;
     }
@@ -707,7 +707,7 @@ ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
 
       if ((*statep = malloc (sizeof (struct ctf_dump_state))) == NULL)
 	{
-	  ctf_set_errno (fp, ENOMEM);
+	  ctf_set_type_errno (fp, ENOMEM);
 	  goto end;
 	}
       state = *statep;
@@ -726,7 +726,7 @@ ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
 	    {
 	      if (ctf_errno (fp) != ECTF_NOLABELDATA)
 		goto end;		/* errno is set for us.  */
-	      ctf_set_errno (fp, 0);
+	      ctf_set_type_errno (fp, 0);
 	    }
 	  break;
 	case CTF_SECT_OBJT:
@@ -749,7 +749,7 @@ ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
 	  ctf_dump_str (fp, state);
 	  break;
 	default:
-	  ctf_set_errno (fp, ECTF_DUMPSECTUNKNOWN);
+	  ctf_set_type_errno (fp, ECTF_DUMPSECTUNKNOWN);
 	  goto end;
 	}
     }
@@ -759,7 +759,7 @@ ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
 
       if (state->cds_sect != sect)
 	{
-	  ctf_set_errno (fp, ECTF_DUMPSECTCHANGED);
+	  ctf_set_type_errno (fp, ECTF_DUMPSECTCHANGED);
 	  goto end;
 	}
     }
@@ -813,18 +813,18 @@ ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
       str = strdup (state->cds_current->cdi_item);
       if (!str)
 	{
-	  ctf_set_errno (fp, ENOMEM);
+	  ctf_set_type_errno (fp, ENOMEM);
 	  return str;
 	}
     }
 
-  ctf_set_errno (fp, 0);
+  ctf_set_type_errno (fp, 0);
   return str;
 
  end:
   ctf_dump_free (state);
   free (state);
-  ctf_set_errno (fp, 0);
+  ctf_set_type_errno (fp, 0);
   *statep = NULL;
   return NULL;
 }
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index da687762c89..77d74ef0ea9 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -741,7 +741,6 @@ extern struct ctf_archive *ctf_arc_open_internal (const char *, int *);
 extern void ctf_arc_close_internal (struct ctf_archive *);
 extern const ctf_preamble_t *ctf_arc_bufpreamble (const ctf_sect_t *);
 extern void *ctf_set_open_errno (int *, int);
-extern unsigned long ctf_set_errno (ctf_dict_t *, int);
 extern void ctf_flip_header (ctf_header_t *);
 extern int ctf_flip (ctf_dict_t *, ctf_header_t *, unsigned char *, int);
 
diff --git a/libctf/ctf-inlines.h b/libctf/ctf-inlines.h
index 6bda68d68e6..fb6e884a0a7 100644
--- a/libctf/ctf-inlines.h
+++ b/libctf/ctf-inlines.h
@@ -90,6 +90,23 @@ ctf_assert_internal (ctf_dict_t *fp, const char *file, size_t line,
   return expr;
 }
 
+static inline int
+ctf_set_int_errno (ctf_dict_t *fp, int err)
+{
+  fp->ctf_errno = err;
+  /* Don't rely on CTF_ERR here as it will not properly sign extend on 64-bit
+     Windows ABI.  */
+  return -1;
+}
+
+static inline ctf_id_t
+ctf_set_type_errno (ctf_dict_t *fp, int err)
+{
+  fp->ctf_errno = err;
+  return CTF_ERR;
+}
+
+
 #ifdef	__cplusplus
 }
 #endif
diff --git a/libctf/ctf-labels.c b/libctf/ctf-labels.c
index 16b111b14df..125d392395e 100644
--- a/libctf/ctf-labels.c
+++ b/libctf/ctf-labels.c
@@ -48,12 +48,12 @@ ctf_label_topmost (ctf_dict_t *fp)
 
   if (num_labels == 0)
     {
-      (void) ctf_set_errno (fp, ECTF_NOLABELDATA);
+      (void) ctf_set_type_errno (fp, ECTF_NOLABELDATA);
       return NULL;
     }
 
   if ((s = ctf_strraw (fp, (ctlp + num_labels - 1)->ctl_label)) == NULL)
-    (void) ctf_set_errno (fp, ECTF_CORRUPT);
+    (void) ctf_set_type_errno (fp, ECTF_CORRUPT);
 
   return s;
 }
@@ -74,7 +74,7 @@ ctf_label_iter (ctf_dict_t *fp, ctf_label_f *func, void *arg)
     return -1;			/* errno is set for us.  */
 
   if (num_labels == 0)
-    return (ctf_set_errno (fp, ECTF_NOLABELDATA));
+    return (ctf_set_int_errno (fp, ECTF_NOLABELDATA));
 
   for (i = 0; i < num_labels; i++, ctlp++)
     {
@@ -84,7 +84,7 @@ ctf_label_iter (ctf_dict_t *fp, ctf_label_f *func, void *arg)
 	  ctf_err_warn (fp, 0, ECTF_CORRUPT,
 			"failed to decode label %u with type %u",
 			ctlp->ctl_label, ctlp->ctl_type);
-	  return (ctf_set_errno (fp, ECTF_CORRUPT));
+	  return (ctf_set_int_errno (fp, ECTF_CORRUPT));
 	}
 
       linfo.ctb_type = ctlp->ctl_type;
@@ -134,7 +134,7 @@ ctf_label_info (ctf_dict_t *fp, const char *lname, ctf_lblinfo_t *linfo)
     return rc;
 
   if (rc != 1)
-    return (ctf_set_errno (fp, ECTF_NOLABEL));
+    return (ctf_set_int_errno (fp, ECTF_NOLABEL));
 
   return 0;
 }
diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c
index 9babec2aa37..8f6f77e547e 100644
--- a/libctf/ctf-link.c
+++ b/libctf/ctf-link.c
@@ -142,7 +142,7 @@ ctf_link_add_ctf_internal (ctf_dict_t *fp, ctf_archive_t *ctf,
  oom1:
   free (filename);
  oom:
-  return ctf_set_errno (fp, ENOMEM);
+  return ctf_set_int_errno (fp, ENOMEM);
 }
 
 /* Add a file, memory buffer, or unopened file (by name) to a link.
@@ -173,12 +173,12 @@ ctf_link_add (ctf_dict_t *fp, ctf_archive_t *ctf, const char *name,
 	      void *buf _libctf_unused_, size_t n _libctf_unused_)
 {
   if (buf)
-    return (ctf_set_errno (fp, ECTF_NOTYET));
+    return (ctf_set_int_errno (fp, ECTF_NOTYET));
 
   if (!((ctf && name && !buf)
 	|| (name && !buf && !ctf)
 	|| (buf && name && !ctf)))
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_int_errno (fp, EINVAL));
 
   /* We can only lazily open files if libctf.so is in use rather than
      libctf-nobfd.so.  This is a little tricky: in shared libraries, we can use
@@ -187,21 +187,21 @@ ctf_link_add (ctf_dict_t *fp, ctf_archive_t *ctf, const char *name,
 
 #if defined (PIC)
   if (!buf && !ctf && name && !ctf_open)
-    return (ctf_set_errno (fp, ECTF_NEEDSBFD));
+    return (ctf_set_int_errno (fp, ECTF_NEEDSBFD));
 #elif NOBFD
   if (!buf && !ctf && name)
-    return (ctf_set_errno (fp, ECTF_NEEDSBFD));
+    return (ctf_set_int_errno (fp, ECTF_NEEDSBFD));
 #endif
 
   if (fp->ctf_link_outputs)
-    return (ctf_set_errno (fp, ECTF_LINKADDEDLATE));
+    return (ctf_set_int_errno (fp, ECTF_LINKADDEDLATE));
   if (fp->ctf_link_inputs == NULL)
     fp->ctf_link_inputs = ctf_dynhash_create (ctf_hash_string,
 					      ctf_hash_eq_string, free,
 					      ctf_link_input_close);
 
   if (fp->ctf_link_inputs == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_int_errno (fp, ENOMEM));
 
   return ctf_link_add_ctf_internal (fp, ctf, NULL, name);
 }
@@ -243,7 +243,7 @@ ctf_link_lazy_open (ctf_dict_t *fp, ctf_link_input_t *input)
 #else
   ctf_err_warn (fp, 0, ECTF_NEEDSBFD, _("cannot open %s lazily"),
 		input->clin_filename);
-  ctf_set_errno (fp, ECTF_NEEDSBFD);
+  ctf_set_int_errno (fp, ECTF_NEEDSBFD);
   return -1;
 #endif
 
@@ -257,7 +257,7 @@ ctf_link_lazy_open (ctf_dict_t *fp, ctf_link_input_t *input)
 
       ctf_err_warn (fp, 0, err, _("opening CTF %s failed"),
 		    input->clin_filename);
-      ctf_set_errno (fp, err);
+      ctf_set_int_errno (fp, err);
       return -1;
     }
 
@@ -334,7 +334,7 @@ ctf_create_per_cu (ctf_dict_t *fp, ctf_dict_t *input, const char *cu_name)
 	{
 	  ctf_err_warn (fp, 0, err, _("cannot create per-CU CTF archive for "
 				      "input CU %s"), cu_name);
-	  ctf_set_errno (fp, err);
+	  ctf_set_type_errno (fp, err);
 	  return NULL;
 	}
 
@@ -357,7 +357,7 @@ ctf_create_per_cu (ctf_dict_t *fp, ctf_dict_t *input, const char *cu_name)
  oom:
   free (dynname);
   ctf_dict_close (cu_fp);
-  ctf_set_errno (fp, ENOMEM);
+  ctf_set_type_errno (fp, ENOMEM);
   return NULL;
 }
 
@@ -378,7 +378,7 @@ ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
 
   /* Mappings cannot be set up if per-CU output dicts already exist.  */
   if (fp->ctf_link_outputs && ctf_dynhash_elements (fp->ctf_link_outputs) != 0)
-      return (ctf_set_errno (fp, ECTF_LINKADDEDLATE));
+      return (ctf_set_int_errno (fp, ECTF_LINKADDEDLATE));
 
   if (fp->ctf_link_in_cu_mapping == NULL)
     fp->ctf_link_in_cu_mapping = ctf_dynhash_create (ctf_hash_string,
@@ -407,7 +407,7 @@ ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
 
   if ((err = ctf_dynhash_insert (fp->ctf_link_in_cu_mapping, f, t)) < 0)
     {
-      ctf_set_errno (fp, err);
+      ctf_set_int_errno (fp, err);
       goto oom_noerrno;
     }
 
@@ -426,7 +426,7 @@ ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
 				     t, one_out)) < 0)
 	{
 	  ctf_dynhash_destroy (one_out);
-	  ctf_set_errno (fp, err);
+	  ctf_set_int_errno (fp, err);
 	  goto oom_noerrno;
 	}
     }
@@ -438,14 +438,14 @@ ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
 
   if (ctf_dynhash_insert (one_out, f, NULL) < 0)
     {
-      ctf_set_errno (fp, err);
+      ctf_set_int_errno (fp, err);
       goto oom_noerrno;
     }
 
   return 0;
 
  oom:
-  ctf_set_errno (fp, errno);
+  ctf_set_int_errno (fp, errno);
  oom_noerrno:
   free (f);
   free (t);
@@ -582,7 +582,7 @@ ctf_link_one_variable (ctf_dict_t *fp, ctf_dict_t *in_fp, const char *name,
 
   if (check_variable (name, per_cu_out_fp, dst_type, &dvd))
     if (ctf_add_variable (per_cu_out_fp, name, dst_type) < 0)
-      return (ctf_set_errno (fp, ctf_errno (per_cu_out_fp)));
+      return (ctf_set_int_errno (fp, ctf_errno (per_cu_out_fp)));
   return 0;
 }
 
@@ -680,7 +680,7 @@ ctf_link_deduplicating_count_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names,
     {
       ctf_err_warn (fp, 0, err, _("iteration error counting deduplicating "
 				  "CTF link inputs"));
-      ctf_set_errno (fp, err);
+      ctf_set_int_errno (fp, err);
       return -1;
     }
 
@@ -783,7 +783,7 @@ ctf_link_deduplicating_open_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names,
 	  if (err != ECTF_NOMEMBNAM)
 	    {
 	      ctf_next_destroy (i);
-	      ctf_set_errno (fp, err);
+	      ctf_set_type_errno (fp, err);
 	      goto err;
 	    }
 	}
@@ -835,7 +835,7 @@ ctf_link_deduplicating_open_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names,
   err = ENOMEM;
 
  iterr:
-  ctf_set_errno (fp, err);
+  ctf_set_type_errno (fp, err);
 
  err:
   free (dedup_inputs);
@@ -877,7 +877,7 @@ ctf_link_deduplicating_close_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names,
 	{
 	  ctf_err_warn (fp, 0, err, _("iteration error in deduplicating link "
 				      "input freeing"));
-	  ctf_set_errno (fp, err);
+	  ctf_set_int_errno (fp, err);
 	}
     }
   else
@@ -915,7 +915,7 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
 	    }
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
-	return ctf_set_errno (fp, ctf_errno (inputs[i]));
+	return ctf_set_int_errno (fp, ctf_errno (inputs[i]));
 
       /* Next the symbols.  We integrate data symbols even though the compiler
 	 is currently doing the same, to allow the compiler to stop in
@@ -930,7 +930,7 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
 	    }
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
-	return ctf_set_errno (fp, ctf_errno (inputs[i]));
+	return ctf_set_int_errno (fp, ctf_errno (inputs[i]));
 
       /* Finally the function symbols.  */
 
@@ -943,7 +943,7 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
 	    }
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
-	return ctf_set_errno (fp, ctf_errno (inputs[i]));
+	return ctf_set_int_errno (fp, ctf_errno (inputs[i]));
     }
   return 0;
 }
@@ -1070,12 +1070,12 @@ ctf_link_deduplicating_one_symtypetab (ctf_dict_t *fp, ctf_dict_t *input,
 			_("symbol %s in input file %s found conflicting "
 			  "even when trying in per-CU dict."), name,
 			ctf_unnamed_cuname (input));
-	  return (ctf_set_errno (fp, ECTF_DUPLICATE));
+	  return (ctf_set_int_errno (fp, ECTF_DUPLICATE));
 	}
     }
   if (ctf_errno (input) != ECTF_NEXT_END)
     {
-      ctf_set_errno (fp, ctf_errno (input));
+      ctf_set_int_errno (fp, ctf_errno (input));
       ctf_err_warn (fp, 0, ctf_errno (input),
 		    functions ? _("iterating over function symbols") :
 		    _("iterating over data symbols"));
@@ -1147,7 +1147,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
 	{
 	  ctf_err_warn (fp, 0, EFBIG, _("too many inputs in deduplicating "
 					"link: %li"), (long int) ninputs);
-	  ctf_set_errno (fp, EFBIG);
+	  ctf_set_int_errno (fp, EFBIG);
 	  goto err_open_inputs;
 	}
 
@@ -1172,7 +1172,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
 	      ctf_err_warn (fp, 0, err, _("cannot open archive %s in "
 					  "CU-mapped CTF link"),
 			    only_input->clin_filename);
-	      ctf_set_errno (fp, err);
+	      ctf_set_int_errno (fp, err);
 	      goto err_open_inputs;
 	    }
 	  ctf_next_destroy (ai);
@@ -1218,7 +1218,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
 	  ctf_err_warn (fp, 0, err, _("cannot create per-CU CTF archive "
 				      "for %s"),
 			out_name);
-	  ctf_set_errno (fp, err);
+	  ctf_set_int_errno (fp, err);
 	  goto err_inputs;
 	}
 
@@ -1233,7 +1233,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
 
       if (ctf_dedup (out, inputs, ninputs, parents, 1) < 0)
 	{
-	  ctf_set_errno (fp, ctf_errno (out));
+	  ctf_set_int_errno (fp, ctf_errno (out));
 	  ctf_err_warn (fp, 0, 0, _("CU-mapped deduplication failed for %s"),
 			out_name);
 	  goto err_inputs;
@@ -1242,7 +1242,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
       if ((outputs = ctf_dedup_emit (out, inputs, ninputs, parents,
 				     &noutputs, 1)) == NULL)
 	{
-	  ctf_set_errno (fp, ctf_errno (out));
+	  ctf_set_int_errno (fp, ctf_errno (out));
 	  ctf_err_warn (fp, 0, 0, _("CU-mapped deduplicating link type emission "
 				     "failed for %s"), out_name);
 	  goto err_inputs;
@@ -1258,7 +1258,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
       if (!(fp->ctf_link_flags & CTF_LINK_OMIT_VARIABLES_SECTION)
 	  && ctf_link_deduplicating_variables (out, inputs, ninputs, 1) < 0)
 	{
-	  ctf_set_errno (fp, ctf_errno (out));
+	  ctf_set_int_errno (fp, ctf_errno (out));
 	  ctf_err_warn (fp, 0, 0, _("CU-mapped deduplicating link variable "
 				    "emission failed for %s"), out_name);
 	  goto err_inputs_outputs;
@@ -1291,7 +1291,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
       if ((in_arc = ctf_new_archive_internal (0, 0, NULL, outputs[0], NULL,
 					      NULL, &err)) == NULL)
 	{
-	  ctf_set_errno (fp, err);
+	  ctf_set_int_errno (fp, err);
 	  goto err_outputs;
 	}
 
@@ -1330,7 +1330,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
     {
       ctf_err_warn (fp, 0, err, _("iteration error in CU-mapped deduplicating "
 				  "link"));
-      return ctf_set_errno (fp, err);
+      return ctf_set_int_errno (fp, err);
     }
 
   return 0;
@@ -1355,7 +1355,7 @@ ctf_link_empty_outputs (ctf_dict_t *fp)
     {
       fp->ctf_flags &= ~LCTF_LINKING;
       ctf_err_warn (fp, 1, err, _("iteration error removing old outputs"));
-      ctf_set_errno (fp, err);
+      ctf_set_int_errno (fp, err);
       return -1;
     }
   return 0;
@@ -1433,7 +1433,7 @@ ctf_link_deduplicating (ctf_dict_t *fp)
       continue;
 
     oom_one_output:
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_type_errno (fp, ENOMEM);
       ctf_err_warn (fp, 0, 0, _("out of memory allocating link outputs"));
       free (dynname);
 
@@ -1465,7 +1465,7 @@ ctf_link_deduplicating (ctf_dict_t *fp)
     return;					/* errno is set for us.  */
 
   ninputs = 0;					/* Prevent double-close.  */
-  ctf_set_errno (fp, 0);
+  ctf_set_type_errno (fp, 0);
 
   /* Fall through.  */
 
@@ -1503,7 +1503,7 @@ ctf_link (ctf_dict_t *fp, int flags)
 					       ctf_dict_close);
 
   if (fp->ctf_link_outputs == NULL)
-    return ctf_set_errno (fp, ENOMEM);
+    return ctf_set_int_errno (fp, ENOMEM);
 
   fp->ctf_flags |= LCTF_LINKING;
   ctf_link_deduplicating (fp);
@@ -1536,7 +1536,7 @@ ctf_link (ctf_dict_t *fp, int flags)
 	{
 	  fp->ctf_flags &= ~LCTF_LINKING;
 	  ctf_err_warn (fp, 1, err, _("iteration error creating empty CUs"));
-	  ctf_set_errno (fp, err);
+	  ctf_set_int_errno (fp, err);
 	  return -1;
 	}
     }
@@ -1593,7 +1593,7 @@ ctf_link_add_strtab (ctf_dict_t *fp, ctf_link_strtab_string_f *add_string,
     }
 
   if (err)
-    ctf_set_errno (fp, err);
+    ctf_set_int_errno (fp, err);
 
   return -err;
 }
@@ -1635,7 +1635,7 @@ ctf_link_add_linker_symbol (ctf_dict_t *fp, ctf_link_sym_t *sym)
  oom:
   ctf_dynhash_destroy (fp->ctf_dynsyms);
   fp->ctf_dynsyms = NULL;
-  ctf_set_errno (fp, ENOMEM);
+  ctf_set_int_errno (fp, ENOMEM);
   return -ENOMEM;
 }
 
@@ -1658,7 +1658,7 @@ ctf_link_shuffle_syms (ctf_dict_t *fp)
 					    NULL, free);
       if (!fp->ctf_dynsyms)
 	{
-	  ctf_set_errno (fp, ENOMEM);
+	  ctf_set_int_errno (fp, ENOMEM);
 	  return -ENOMEM;
 	}
     }
@@ -1758,7 +1758,7 @@ ctf_link_shuffle_syms (ctf_dict_t *fp)
   free (fp->ctf_dynsymidx);
   fp->ctf_dynsymidx = NULL;
   fp->ctf_dynsymmax = 0;
-  ctf_set_errno (fp, err);
+  ctf_set_int_errno (fp, err);
   return -err;
 }
 
@@ -1785,14 +1785,14 @@ ctf_accumulate_archive_names (void *key, void *value, void *arg_)
   if ((names = realloc (arg->names, sizeof (char *) * ++(arg->i))) == NULL)
     {
       (arg->i)--;
-      ctf_set_errno (arg->fp, ENOMEM);
+      ctf_set_type_errno (arg->fp, ENOMEM);
       return;
     }
 
   if ((files = realloc (arg->files, sizeof (ctf_dict_t *) * arg->i)) == NULL)
     {
       (arg->i)--;
-      ctf_set_errno (arg->fp, ENOMEM);
+      ctf_set_type_errno (arg->fp, ENOMEM);
       return;
     }
 
@@ -1815,7 +1815,7 @@ ctf_accumulate_archive_names (void *key, void *value, void *arg_)
 				  sizeof (char *) * ++(arg->ndynames))) == NULL)
 	    {
 	      (arg->ndynames)--;
-	      ctf_set_errno (arg->fp, ENOMEM);
+	      ctf_set_type_errno (arg->fp, ENOMEM);
 	      return;
 	    }
 	    arg->dynames = dynames;
@@ -1986,7 +1986,7 @@ ctf_link_write (ctf_dict_t *fp, size_t *size, size_t threshold)
 			       threshold)) < 0)
     {
       errloc = "archive writing";
-      ctf_set_errno (fp, err);
+      ctf_set_type_errno (fp, err);
       goto err;
     }
 
@@ -2036,7 +2036,7 @@ ctf_link_write (ctf_dict_t *fp, size_t *size, size_t threshold)
   return buf;
 
  err_no:
-  ctf_set_errno (fp, errno);
+  ctf_set_type_errno (fp, errno);
 
   /* Turn off the is-linking flag on all the dicts in this link.  */
   for (i = 0; i < arg.i; i++)
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index c65849118cb..6ff9138de63 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -30,7 +30,7 @@ grow_pptrtab (ctf_dict_t *fp, size_t new_len)
 
   if ((new_pptrtab = realloc (fp->ctf_pptrtab, sizeof (uint32_t)
 			      * new_len)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_int_errno (fp, ENOMEM));
 
   fp->ctf_pptrtab = new_pptrtab;
 
@@ -143,7 +143,7 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
   ctf_id_t ntype, ptype;
 
   if (name == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_type_errno (fp, EINVAL));
 
   for (p = name, end = name + strlen (name); *p != '\0'; p = q)
     {
@@ -274,7 +274,7 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
 		  fp->ctf_tmp_typeslice = xstrndup (p, (size_t) (q - p));
 		  if (fp->ctf_tmp_typeslice == NULL)
 		    {
-		      ctf_set_errno (fp, ENOMEM);
+		      ctf_set_type_errno (fp, ENOMEM);
 		      return CTF_ERR;
 		    }
 		}
@@ -292,12 +292,12 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
     }
 
   if (*p != '\0' || type == 0)
-    return (ctf_set_errno (fp, ECTF_SYNTAX));
+    return (ctf_set_type_errno (fp, ECTF_SYNTAX));
 
   return type;
 
  notype:
-  ctf_set_errno (fp, ECTF_NOTYPE);
+  ctf_set_type_errno (fp, ECTF_NOTYPE);
   if (fp->ctf_parent != NULL)
     {
       /* Need to look up in the parent, from the child's perspective.
@@ -312,7 +312,7 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
       if ((ptype = ctf_lookup_by_name_internal (fp->ctf_parent, fp,
 						name)) != CTF_ERR)
 	return ptype;
-      return (ctf_set_errno (fp, ctf_errno (fp->ctf_parent)));
+      return (ctf_set_type_errno (fp, ctf_errno (fp->ctf_parent)));
     }
 
   return CTF_ERR;
@@ -336,7 +336,7 @@ ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
 
   if ((fp = ctf_get_dict (fp, type)) == NULL)
     {
-      (void) ctf_set_errno (*fpp, ECTF_NOPARENT);
+      (void) ctf_set_type_errno (*fpp, ECTF_NOPARENT);
       return NULL;
     }
 
@@ -351,7 +351,7 @@ ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
 	  *fpp = fp;
 	  return &dtd->dtd_data;
 	}
-      (void) ctf_set_errno (*fpp, ECTF_BADID);
+      (void) ctf_set_type_errno (*fpp, ECTF_BADID);
       return NULL;
     }
 
@@ -364,7 +364,7 @@ ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
       return (LCTF_INDEX_TO_TYPEPTR (fp, idx));
     }
 
-  (void) ctf_set_errno (*fpp, ECTF_BADID);
+  (void) ctf_set_type_errno (*fpp, ECTF_BADID);
   return NULL;
 }
 
@@ -407,10 +407,10 @@ ctf_lookup_variable (ctf_dict_t *fp, const char *name)
 
           if ((ptype = ctf_lookup_variable (fp->ctf_parent, name)) != CTF_ERR)
             return ptype;
-          return (ctf_set_errno (fp, ctf_errno (fp->ctf_parent)));
+          return (ctf_set_type_errno (fp, ctf_errno (fp->ctf_parent)));
         }
 
-      return (ctf_set_errno (fp, ECTF_NOTYPEDAT));
+      return (ctf_set_type_errno (fp, ECTF_NOTYPEDAT));
     }
 
   return ent->ctv_type;
@@ -447,7 +447,7 @@ ctf_symidx_sort (ctf_dict_t *fp, uint32_t *idx, size_t *nidx,
 
   if ((sorted = malloc (len)) == NULL)
     {
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_type_errno (fp, ENOMEM);
       return NULL;
     }
 
@@ -512,7 +512,7 @@ ctf_lookup_symbol_name (ctf_dict_t *fp, unsigned long symidx)
       }
       break;
     default:
-      ctf_set_errno (fp, ECTF_SYMTAB);
+      ctf_set_type_errno (fp, ECTF_SYMTAB);
       return _CTF_NULLSTR;
     }
 
@@ -526,12 +526,12 @@ ctf_lookup_symbol_name (ctf_dict_t *fp, unsigned long symidx)
       const char *ret;
       ret = ctf_lookup_symbol_name (fp->ctf_parent, symidx);
       if (ret == NULL)
-	ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
+	ctf_set_type_errno (fp, ctf_errno (fp->ctf_parent));
       return ret;
     }
   else
     {
-      ctf_set_errno (fp, err);
+      ctf_set_type_errno (fp, err);
       return _CTF_NULLSTR;
     }
 }
@@ -621,7 +621,7 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
 	  }
 	  break;
 	default:
-	  ctf_set_errno (fp, ECTF_SYMTAB);
+	  ctf_set_type_errno (fp, ECTF_SYMTAB);
 	  return (unsigned long) -1;
 	}
     }
@@ -639,16 +639,16 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
           != (unsigned long) -1)
         return psym;
 
-      ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
+      ctf_set_type_errno (fp, ctf_errno (fp->ctf_parent));
       return (unsigned long) -1;
     }
   else
     {
-      ctf_set_errno (fp, err);
+      ctf_set_type_errno (fp, err);
       return (unsigned long) -1;
     }
 oom:
-  ctf_set_errno (fp, ENOMEM);
+  ctf_set_type_errno (fp, ENOMEM);
   ctf_err_warn (fp, 0, ENOMEM, _("cannot allocate memory for symbol "
 				 "lookup hashtab"));
   return (unsigned long) -1;
@@ -673,7 +673,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	return ctf_set_type_errno (fp, ENOMEM);
 
       i->cu.ctn_fp = fp;
       i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next;
@@ -682,10 +682,10 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
     }
 
   if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
+    return (ctf_set_type_errno (fp, ECTF_NEXT_WRONGFUN));
 
   if (fp != i->cu.ctn_fp)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
+    return (ctf_set_type_errno (fp, ECTF_NEXT_WRONGFP));
 
   /* We intentionally use raw access, not ctf_lookup_by_symbol, to avoid
      incurring additional sorting cost for unsorted symtypetabs coming from the
@@ -701,7 +701,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
       if (!dynh)
 	{
 	  ctf_next_destroy (i);
-	  return (ctf_set_errno (fp, ECTF_NEXT_END));
+	  return (ctf_set_type_errno (fp, ECTF_NEXT_END));
 	}
 
       err = ctf_dynhash_next (dynh, &i->ctn_next, &dyn_name, &dyn_value);
@@ -710,7 +710,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
 	{
 	  ctf_next_destroy (i);
 	  *it = NULL;
-	  return ctf_set_errno (fp, err);
+	  return ctf_set_type_errno (fp, err);
 	}
 
       *name = dyn_name;
@@ -786,7 +786,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
  end:
   ctf_next_destroy (i);
   *it = NULL;
-  return (ctf_set_errno (fp, ECTF_NEXT_END));
+  return (ctf_set_type_errno (fp, ECTF_NEXT_END));
 }
 
 /* A bsearch function for function and object index names.  */
@@ -878,7 +878,7 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 
   /* Should be impossible, but be paranoid.  */
   if ((idx - sxlate) > (ptrdiff_t) nidx)
-    return (ctf_set_errno (fp, ECTF_CORRUPT));
+    return (ctf_set_type_errno (fp, ECTF_CORRUPT));
 
   ctf_dprintf ("Symbol %lx (%s) is of type %x\n", symidx, symname,
 	       symtypetab[*idx]);
@@ -1010,11 +1010,11 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
       ctf_id_t ret = ctf_lookup_by_sym_or_name (fp->ctf_parent, symidx,
 						symname);
       if (ret == CTF_ERR)
-	ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
+	ctf_set_type_errno (fp, ctf_errno (fp->ctf_parent));
       return ret;
     }
   else
-    return (ctf_set_errno (fp, err));
+    return (ctf_set_type_errno (fp, err));
 }
 
 /* Given a symbol table index, return the type of the function or data object
@@ -1046,7 +1046,7 @@ ctf_func_info (ctf_dict_t *fp, unsigned long symidx, ctf_funcinfo_t *fip)
     return -1;					/* errno is set for us.  */
 
   if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
-    return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    return (ctf_set_int_errno (fp, ECTF_NOTFUNC));
 
   return ctf_func_type_info (fp, type, fip);
 }
@@ -1064,7 +1064,7 @@ ctf_func_args (ctf_dict_t *fp, unsigned long symidx, uint32_t argc,
     return -1;					/* errno is set for us.  */
 
   if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
-    return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    return (ctf_set_int_errno (fp, ECTF_NOTFUNC));
 
   return ctf_func_type_args (fp, type, argc, argv);
 }
diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c
index 35f635b6559..fa020a10424 100644
--- a/libctf/ctf-open.c
+++ b/libctf/ctf-open.c
@@ -159,7 +159,7 @@ get_vbytes_common (ctf_dict_t *fp, unsigned short kind,
     case CTF_K_RESTRICT:
       return 0;
     default:
-      ctf_set_errno (fp, ECTF_CORRUPT);
+      ctf_set_int_errno (fp, ECTF_CORRUPT);
       ctf_err_warn (fp, 0, 0, _("detected invalid CTF kind: %x"), kind);
       return -1;
     }
@@ -1935,7 +1935,7 @@ ctf_parent_name_set (ctf_dict_t *fp, const char *name)
     free (fp->ctf_dynparname);
 
   if ((fp->ctf_dynparname = strdup (name)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_int_errno (fp, ENOMEM));
   fp->ctf_parname = fp->ctf_dynparname;
   return 0;
 }
@@ -1956,7 +1956,7 @@ ctf_cuname_set (ctf_dict_t *fp, const char *name)
     free (fp->ctf_dyncuname);
 
   if ((fp->ctf_dyncuname = strdup (name)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_int_errno (fp, ENOMEM));
   fp->ctf_cuname = fp->ctf_dyncuname;
   return 0;
 }
@@ -1969,10 +1969,10 @@ int
 ctf_import (ctf_dict_t *fp, ctf_dict_t *pfp)
 {
   if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_int_errno (fp, EINVAL));
 
   if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel)
-    return (ctf_set_errno (fp, ECTF_DMODEL));
+    return (ctf_set_int_errno (fp, ECTF_DMODEL));
 
   if (fp->ctf_parent && !fp->ctf_parent_unreffed)
     ctf_dict_close (fp->ctf_parent);
@@ -2008,10 +2008,10 @@ int
 ctf_import_unref (ctf_dict_t *fp, ctf_dict_t *pfp)
 {
   if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_int_errno (fp, EINVAL));
 
   if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel)
-    return (ctf_set_errno (fp, ECTF_DMODEL));
+    return (ctf_set_int_errno (fp, ECTF_DMODEL));
 
   if (fp->ctf_parent && !fp->ctf_parent_unreffed)
     ctf_dict_close (fp->ctf_parent);
@@ -2052,7 +2052,7 @@ ctf_setmodel (ctf_dict_t *fp, int model)
 	}
     }
 
-  return (ctf_set_errno (fp, EINVAL));
+  return (ctf_set_int_errno (fp, EINVAL));
 }
 
 /* Return the data model constant for the CTF dict.  */
diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
index ba830a2b095..4f410ebbeab 100644
--- a/libctf/ctf-serialize.c
+++ b/libctf/ctf-serialize.c
@@ -123,7 +123,7 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 
       if ((linker_known = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
 					      NULL, NULL)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_int_errno (fp, ENOMEM));
 
       while ((err = ctf_dynhash_cnext (symfp->ctf_dynsyms, &i,
 				       &name, &ctf_sym)) == 0)
@@ -147,7 +147,7 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 	  if (ctf_dynhash_cinsert (linker_known, name, ctf_sym) < 0)
 	    {
 	      ctf_dynhash_destroy (linker_known);
-	      return (ctf_set_errno (fp, ENOMEM));
+	      return (ctf_set_int_errno (fp, ENOMEM));
 	    }
 	}
       if (err != ECTF_NEXT_END)
@@ -155,7 +155,7 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols during "
 				  "serialization"));
 	  ctf_dynhash_destroy (linker_known);
-	  return (ctf_set_errno (fp, err));
+	  return (ctf_set_int_errno (fp, err));
 	}
     }
 
@@ -219,7 +219,7 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
       ctf_err_warn (fp, 0, err, _("iterating over CTF symtypetab during "
 				  "serialization"));
       ctf_dynhash_destroy (linker_known);
-      return (ctf_set_errno (fp, err));
+      return (ctf_set_int_errno (fp, err));
     }
 
   if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
@@ -236,7 +236,7 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols "
 				      "during CTF serialization"));
 	  ctf_dynhash_destroy (linker_known);
-	  return (ctf_set_errno (fp, err));
+	  return (ctf_set_int_errno (fp, err));
 	}
     }
 
@@ -709,7 +709,7 @@ ctf_emit_symtypetab_sects (ctf_dict_t *fp, emit_symtypetab_state_t *s,
   return 0;
 
  oom:
-  ctf_set_errno (fp, EAGAIN);
+  ctf_set_int_errno (fp, EAGAIN);
   goto err;
 symerr:
   ctf_err_warn (fp, 0, err, _("error serializing symtypetabs"));
@@ -970,7 +970,7 @@ ctf_serialize (ctf_dict_t *fp)
   memset (&symstate, 0, sizeof (emit_symtypetab_state_t));
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_int_errno (fp, ECTF_RDONLY));
 
   /* Update required?  */
   if (!(fp->ctf_flags & LCTF_DIRTY))
@@ -1026,7 +1026,7 @@ ctf_serialize (ctf_dict_t *fp)
   buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
 
   if ((buf = malloc (buf_size)) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+    return (ctf_set_int_errno (fp, EAGAIN));
 
   memcpy (buf, &hdr, sizeof (ctf_header_t));
   t = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_objtoff;
@@ -1106,7 +1106,7 @@ ctf_serialize (ctf_dict_t *fp)
 				       1, &err)) == NULL)
     {
       free (buf);
-      return (ctf_set_errno (fp, err));
+      return (ctf_set_int_errno (fp, err));
     }
 
   (void) ctf_setmodel (nfp, ctf_getmodel (fp));
@@ -1221,7 +1221,7 @@ ctf_serialize (ctf_dict_t *fp)
 
 oom:
   free (buf);
-  return (ctf_set_errno (fp, EAGAIN));
+  return (ctf_set_int_errno (fp, EAGAIN));
 err:
   free (buf);
   return -1;					/* errno is set for us.  */
@@ -1248,7 +1248,7 @@ ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
   while (resid != 0)
     {
       if ((len = gzwrite (fd, buf, resid)) <= 0)
-	return (ctf_set_errno (fp, errno));
+	return (ctf_set_int_errno (fp, errno));
       resid -= len;
       buf += len;
     }
@@ -1258,7 +1258,7 @@ ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
   while (resid != 0)
     {
       if ((len = gzwrite (fd, buf, resid)) <= 0)
-	return (ctf_set_errno (fp, errno));
+	return (ctf_set_int_errno (fp, errno));
       resid -= len;
       buf += len;
     }
@@ -1294,7 +1294,7 @@ ctf_write_mem (ctf_dict_t *fp, size_t *size, size_t threshold)
   if ((buf = malloc (compress_len
 		     + sizeof (struct ctf_header))) == NULL)
     {
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_type_errno (fp, ENOMEM);
       ctf_err_warn (fp, 0, 0, _("ctf_write_mem: cannot allocate %li bytes"),
 		    (unsigned long) (compress_len + sizeof (struct ctf_header)));
       return NULL;
@@ -1317,7 +1317,7 @@ ctf_write_mem (ctf_dict_t *fp, size_t *size, size_t threshold)
     {
       if ((flipped = malloc (fp->ctf_size)) == NULL)
 	{
-	  ctf_set_errno (fp, ENOMEM);
+	  ctf_set_type_errno (fp, ENOMEM);
 	  ctf_err_warn (fp, 0, 0, _("ctf_write_mem: cannot allocate %li bytes"),
 			(unsigned long) (fp->ctf_size + sizeof (struct ctf_header)));
 	  return NULL;
@@ -1343,7 +1343,7 @@ ctf_write_mem (ctf_dict_t *fp, size_t *size, size_t threshold)
       if ((rc = compress (bp, (uLongf *) &compress_len,
 			  src, fp->ctf_size)) != Z_OK)
 	{
-	  ctf_set_errno (fp, ECTF_COMPRESS);
+	  ctf_set_type_errno (fp, ECTF_COMPRESS);
 	  ctf_err_warn (fp, 0, 0, _("zlib deflate err: %s"), zError (rc));
 	  free (buf);
 	  return NULL;
@@ -1378,7 +1378,7 @@ ctf_compress_write (ctf_dict_t *fp, int fd)
     {
       if ((len = write (fd, bp, buf_len)) < 0)
 	{
-	  err = ctf_set_errno (fp, errno);
+	  err = ctf_set_int_errno (fp, errno);
 	  ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
 	  goto ret;
 	}
@@ -1412,7 +1412,7 @@ ctf_write (ctf_dict_t *fp, int fd)
     {
       if ((len = write (fd, bp, buf_len)) < 0)
 	{
-	  err = ctf_set_errno (fp, errno);
+	  err = ctf_set_int_errno (fp, errno);
 	  ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
 	  goto ret;
 	}
diff --git a/libctf/ctf-string.c b/libctf/ctf-string.c
index 911e94700f1..06de3fb4732 100644
--- a/libctf/ctf-string.c
+++ b/libctf/ctf-string.c
@@ -229,7 +229,7 @@ ctf_str_add_ref_internal (ctf_dict_t *fp, const char *str,
   free (atom);
   free (aref);
   free (newstr);
-  ctf_set_errno (fp, ENOMEM);
+  ctf_set_type_errno (fp, ENOMEM);
   return NULL;
 }
 
@@ -298,7 +298,7 @@ ctf_str_move_pending (ctf_dict_t *fp, uint32_t *new_ref, ptrdiff_t bytes)
     return 0;
 
   if (ctf_dynset_insert (fp->ctf_str_pending_ref, (void *) new_ref) < 0)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_int_errno (fp, ENOMEM));
 
   ctf_dynset_remove (fp->ctf_str_pending_ref,
 		     (void *) ((signed char *) new_ref - bytes));
@@ -327,7 +327,7 @@ ctf_str_add_external (ctf_dict_t *fp, const char *str, uint32_t offset)
 						 NULL, NULL);
   if (!fp->ctf_syn_ext_strtab)
     {
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_int_errno (fp, ENOMEM);
       return 0;
     }
 
@@ -338,7 +338,7 @@ ctf_str_add_external (ctf_dict_t *fp, const char *str, uint32_t offset)
     {
       /* No need to bother freeing the syn_ext_strtab: it will get freed at
 	 ctf_str_write_strtab time if unreferenced.  */
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_int_errno (fp, ENOMEM);
       return 0;
     }
 
diff --git a/libctf/ctf-subr.c b/libctf/ctf-subr.c
index f4118328a83..55c2ed3bf6d 100644
--- a/libctf/ctf-subr.c
+++ b/libctf/ctf-subr.c
@@ -288,7 +288,7 @@ ctf_errwarning_next (ctf_dict_t *fp, ctf_next_t **it, int *is_warning,
 	  if (errp)
 	    *errp = ENOMEM;
 	  else if (fp)
-	    ctf_set_errno (fp, ENOMEM);
+	    ctf_set_type_errno (fp, ENOMEM);
 	  return NULL;
 	}
 
@@ -302,7 +302,7 @@ ctf_errwarning_next (ctf_dict_t *fp, ctf_next_t **it, int *is_warning,
       if (errp)
 	*errp = ECTF_NEXT_WRONGFUN;
       else if (fp)
-	ctf_set_errno (fp, ECTF_NEXT_WRONGFUN);
+	ctf_set_type_errno (fp, ECTF_NEXT_WRONGFUN);
       return NULL;
     }
 
@@ -311,7 +311,7 @@ ctf_errwarning_next (ctf_dict_t *fp, ctf_next_t **it, int *is_warning,
       if (errp)
 	*errp = ECTF_NEXT_WRONGFP;
       else if (fp)
-	ctf_set_errno (fp, ECTF_NEXT_WRONGFP);
+	ctf_set_type_errno (fp, ECTF_NEXT_WRONGFP);
       return NULL;
     }
 
@@ -324,7 +324,7 @@ ctf_errwarning_next (ctf_dict_t *fp, ctf_next_t **it, int *is_warning,
       if (errp)
 	*errp = ECTF_NEXT_END;
       else if (fp)
-	ctf_set_errno (fp, ECTF_NEXT_END);
+	ctf_set_type_errno (fp, ECTF_NEXT_END);
       return NULL;
     }
 
@@ -342,5 +342,5 @@ ctf_assert_fail_internal (ctf_dict_t *fp, const char *file, size_t line,
 {
   ctf_err_warn (fp, 0, ECTF_INTERNAL, _("%s: %lu: libctf assertion failed: %s"),
 		file, (long unsigned int) line, exprstr);
-  ctf_set_errno (fp, ECTF_INTERNAL);
+  ctf_set_type_errno (fp, ECTF_INTERNAL);
 }
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index c20ff825d9a..85f6a7c529f 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -119,7 +119,7 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 	return -1;			/* errno is set for us.  */
 
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (ofp, ENOMEM);
+	return ctf_set_int_errno (ofp, ENOMEM);
       i->cu.ctn_fp = ofp;
       i->ctn_tp = tp;
 
@@ -129,7 +129,7 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
       if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
 	{
 	  ctf_next_destroy (i);
-	  return (ctf_set_errno (ofp, ECTF_NOTSOU));
+	  return (ctf_set_int_errno (ofp, ECTF_NOTSOU));
 	}
 
       if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
@@ -150,14 +150,14 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
     }
 
   if ((void (*) (void)) ctf_member_next != i->ctn_iter_fun)
-    return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN));
+    return (ctf_set_int_errno (ofp, ECTF_NEXT_WRONGFUN));
 
   if (ofp != i->cu.ctn_fp)
-    return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFP));
+    return (ctf_set_int_errno (ofp, ECTF_NEXT_WRONGFP));
 
   /* Resolve to the native dict of this type.  */
   if ((fp = ctf_get_dict (ofp, type)) == NULL)
-    return (ctf_set_errno (ofp, ECTF_NOPARENT));
+    return (ctf_set_int_errno (ofp, ECTF_NOPARENT));
 
   max_vlen = LCTF_INFO_VLEN (fp, i->ctn_tp->ctt_info);
 
@@ -177,7 +177,7 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 
       if (ctf_struct_member (fp, &memb, i->ctn_tp, i->u.ctn_vlen, i->ctn_size,
 			     i->ctn_n) < 0)
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+        return (ctf_set_int_errno (ofp, ctf_errno (fp)));
 
       membname = ctf_strptr (fp, memb.ctlm_name);
 
@@ -216,12 +216,12 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 	  ctf_next_destroy (i);
 	  *it = NULL;
 	  i->ctn_type = 0;
-	  ctf_set_errno (ofp, ctf_errno (fp));
+	  ctf_set_int_errno (ofp, ctf_errno (fp));
 	  return ret;
 	}
 
       if (!ctf_assert (fp, (i->ctn_next == NULL)))
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+        return (ctf_set_int_errno (ofp, ctf_errno (fp)));
 
       i->ctn_type = 0;
       /* This sub-struct has ended: on to the next real member.  */
@@ -233,7 +233,7 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
  end_iter:
   ctf_next_destroy (i);
   *it = NULL;
-  return ctf_set_errno (ofp, ECTF_NEXT_END);
+  return ctf_set_int_errno (ofp, ECTF_NEXT_END);
 }
 
 /* Iterate over the members of an ENUM.  We pass the string name and associated
@@ -287,7 +287,7 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 
       if ((i = ctf_next_create ()) == NULL)
 	{
-	  ctf_set_errno (ofp, ENOMEM);
+	  ctf_set_type_errno (ofp, ENOMEM);
 	  return NULL;
 	}
       i->cu.ctn_fp = ofp;
@@ -299,7 +299,7 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
       if (kind != CTF_K_ENUM)
 	{
 	  ctf_next_destroy (i);
-	  ctf_set_errno (ofp, ECTF_NOTENUM);
+	  ctf_set_type_errno (ofp, ECTF_NOTENUM);
 	  return NULL;
 	}
 
@@ -318,20 +318,20 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 
   if ((void (*) (void)) ctf_enum_next != i->ctn_iter_fun)
     {
-      ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN);
+      ctf_set_type_errno (ofp, ECTF_NEXT_WRONGFUN);
       return NULL;
     }
 
   if (ofp != i->cu.ctn_fp)
     {
-      ctf_set_errno (ofp, ECTF_NEXT_WRONGFP);
+      ctf_set_type_errno (ofp, ECTF_NEXT_WRONGFP);
       return NULL;
     }
 
   /* Resolve to the native dict of this type.  */
   if ((fp = ctf_get_dict (ofp, type)) == NULL)
     {
-      ctf_set_errno (ofp, ECTF_NOPARENT);
+      ctf_set_type_errno (ofp, ECTF_NOPARENT);
       return NULL;
     }
 
@@ -349,7 +349,7 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
  end_iter:
   ctf_next_destroy (i);
   *it = NULL;
-  ctf_set_errno (ofp, ECTF_NEXT_END);
+  ctf_set_type_errno (ofp, ECTF_NEXT_END);
   return NULL;
 }
 
@@ -426,7 +426,7 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	return ctf_set_type_errno (fp, ENOMEM);
 
       i->cu.ctn_fp = fp;
       i->ctn_type = 1;
@@ -435,10 +435,10 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
     }
 
   if ((void (*) (void)) ctf_type_next != i->ctn_iter_fun)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
+    return (ctf_set_type_errno (fp, ECTF_NEXT_WRONGFUN));
 
   if (fp != i->cu.ctn_fp)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
+    return (ctf_set_type_errno (fp, ECTF_NEXT_WRONGFP));
 
   while (i->ctn_type <= fp->ctf_typemax)
     {
@@ -456,7 +456,7 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
     }
   ctf_next_destroy (i);
   *it = NULL;
-  return ctf_set_errno (fp, ECTF_NEXT_END);
+  return ctf_set_type_errno (fp, ECTF_NEXT_END);
 }
 
 /* Iterate over every variable in the given CTF dict, in arbitrary order.
@@ -494,12 +494,12 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
   ctf_next_t *i = *it;
 
   if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parent == NULL))
-    return (ctf_set_errno (fp, ECTF_NOPARENT));
+    return (ctf_set_type_errno (fp, ECTF_NOPARENT));
 
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	return ctf_set_type_errno (fp, ENOMEM);
 
       i->cu.ctn_fp = fp;
       i->ctn_iter_fun = (void (*) (void)) ctf_variable_next;
@@ -509,10 +509,10 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
     }
 
   if ((void (*) (void)) ctf_variable_next != i->ctn_iter_fun)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
+    return (ctf_set_type_errno (fp, ECTF_NEXT_WRONGFUN));
 
   if (fp != i->cu.ctn_fp)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
+    return (ctf_set_type_errno (fp, ECTF_NEXT_WRONGFP));
 
   if (!(fp->ctf_flags & LCTF_RDWR))
     {
@@ -538,7 +538,7 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
  end_iter:
   ctf_next_destroy (i);
   *it = NULL;
-  return ctf_set_errno (fp, ECTF_NEXT_END);
+  return ctf_set_type_errno (fp, ECTF_NEXT_END);
 }
 
 /* Follow a given type through the graph for TYPEDEF, VOLATILE, CONST, and
@@ -560,7 +560,7 @@ ctf_type_resolve (ctf_dict_t *fp, ctf_id_t type)
   const ctf_type_t *tp;
 
   if (type == 0)
-    return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE));
+    return (ctf_set_type_errno (ofp, ECTF_NONREPRESENTABLE));
 
   while ((tp = ctf_lookup_by_id (&fp, type)) != NULL)
     {
@@ -575,18 +575,18 @@ ctf_type_resolve (ctf_dict_t *fp, ctf_id_t type)
 	    {
 	      ctf_err_warn (ofp, 0, ECTF_CORRUPT, _("type %lx cycle detected"),
 			    otype);
-	      return (ctf_set_errno (ofp, ECTF_CORRUPT));
+	      return (ctf_set_type_errno (ofp, ECTF_CORRUPT));
 	    }
 	  prev = type;
 	  type = tp->ctt_type;
 	  break;
 	case CTF_K_UNKNOWN:
-	  return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE));
+	  return (ctf_set_type_errno (ofp, ECTF_NONREPRESENTABLE));
 	default:
 	  return type;
 	}
       if (type == 0)
-	return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE));
+	return (ctf_set_type_errno (ofp, ECTF_NONREPRESENTABLE));
     }
 
   return CTF_ERR;		/* errno is set for us.  */
@@ -612,7 +612,7 @@ ctf_type_resolve_unsliced (ctf_dict_t *fp, ctf_id_t type)
       ctf_id_t ret;
 
       if ((ret = ctf_type_reference (fp, type)) == CTF_ERR)
-	return (ctf_set_errno (ofp, ctf_errno (fp)));
+	return (ctf_set_type_errno (ofp, ctf_errno (fp)));
       return ret;
     }
   return type;
@@ -675,7 +675,7 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
   if (cd.cd_err != 0)
     {
       ctf_decl_fini (&cd);
-      ctf_set_errno (fp, cd.cd_err);
+      ctf_set_type_errno (fp, cd.cd_err);
       return NULL;
     }
 
@@ -720,7 +720,7 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
 
 	      if (name[0] == '\0')
 		{
-		  ctf_set_errno (fp, ECTF_CORRUPT);
+		  ctf_set_type_errno (fp, ECTF_CORRUPT);
 		  ctf_decl_fini (&cd);
 		  return NULL;
 		}
@@ -744,7 +744,7 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
 
 		if ((argv = calloc (fi.ctc_argc, sizeof (ctf_id_t *))) == NULL)
 		  {
-		    ctf_set_errno (rfp, errno);
+		    ctf_set_type_errno (rfp, errno);
 		    goto err;
 		  }
 
@@ -775,7 +775,7 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
 		break;
 
 	      err:
-		ctf_set_errno (fp, ctf_errno (rfp));
+		ctf_set_type_errno (fp, ctf_errno (rfp));
 		free (argv);
 		ctf_decl_fini (&cd);
 		return NULL;
@@ -804,7 +804,7 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
 		    ctf_decl_sprintf (&cd, "enum %s", name);
 		    break;
 		  default:
-		    ctf_set_errno (fp, ECTF_CORRUPT);
+		    ctf_set_type_errno (fp, ECTF_CORRUPT);
 		    ctf_decl_fini (&cd);
 		    return NULL;
 		  }
@@ -836,7 +836,7 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
     }
 
   if (cd.cd_enomem)
-    (void) ctf_set_errno (fp, ENOMEM);
+    (void) ctf_set_type_errno (fp, ENOMEM);
 
   buf = ctf_decl_buf (&cd);
 
@@ -861,7 +861,7 @@ ctf_type_lname (ctf_dict_t *fp, ctf_id_t type, char *buf, size_t len)
   free (str);
 
   if (slen >= len)
-    (void) ctf_set_errno (fp, ECTF_NAMELEN);
+    (void) ctf_set_int_errno (fp, ECTF_NAMELEN);
 
   return slen;
 }
@@ -956,7 +956,7 @@ ctf_type_size (ctf_dict_t *fp, ctf_id_t type)
 
     case CTF_K_FORWARD:
       /* Forwards do not have a meaningful size.  */
-      return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
+      return (ctf_set_int_errno (ofp, ECTF_INCOMPLETE));
 
     default: /* including slices of enums, etc */
       return (ctf_get_ctt_size (fp, tp, NULL, NULL));
@@ -1039,7 +1039,7 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
 
     case CTF_K_FORWARD:
       /* Forwards do not have a meaningful alignment.  */
-      return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
+      return (ctf_set_int_errno (ofp, ECTF_INCOMPLETE));
 
     default:  /* including slices of enums, etc */
       return (ctf_get_ctt_size (fp, tp, NULL, NULL));
@@ -1139,7 +1139,7 @@ ctf_type_reference (ctf_dict_t *fp, ctf_id_t type)
 	return sp->cts_type;
       }
     default:
-      return (ctf_set_errno (ofp, ECTF_NOTREF));
+      return (ctf_set_type_errno (ofp, ECTF_NOTREF));
     }
 }
 
@@ -1164,15 +1164,15 @@ ctf_type_pointer (ctf_dict_t *fp, ctf_id_t type)
     return (LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD)));
 
   if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
-    return (ctf_set_errno (ofp, ECTF_NOTYPE));
+    return (ctf_set_type_errno (ofp, ECTF_NOTYPE));
 
   if (ctf_lookup_by_id (&fp, type) == NULL)
-    return (ctf_set_errno (ofp, ECTF_NOTYPE));
+    return (ctf_set_type_errno (ofp, ECTF_NOTYPE));
 
   if ((ntype = fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, type)]) != 0)
     return (LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD)));
 
-  return (ctf_set_errno (ofp, ECTF_NOTYPE));
+  return (ctf_set_type_errno (ofp, ECTF_NOTYPE));
 }
 
 /* Return the encoding for the specified INTEGER, FLOAT, or ENUM.  */
@@ -1235,7 +1235,7 @@ ctf_type_encoding (ctf_dict_t *fp, ctf_id_t type, ctf_encoding_t *ep)
 	break;
       }
     default:
-      return (ctf_set_errno (ofp, ECTF_NOTINTFP));
+      return (ctf_set_int_errno (ofp, ECTF_NOTINTFP));
     }
 
   return 0;
@@ -1370,7 +1370,7 @@ ctf_member_count (ctf_dict_t *fp, ctf_id_t type)
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION && kind != CTF_K_ENUM)
-    return (ctf_set_errno (ofp, ECTF_NOTSUE));
+    return (ctf_set_int_errno (ofp, ECTF_NOTSUE));
 
   return LCTF_INFO_VLEN (fp, tp->ctt_info);
 }
@@ -1398,7 +1398,7 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
-    return (ctf_set_errno (ofp, ECTF_NOTSOU));
+    return (ctf_set_int_errno (ofp, ECTF_NOTSOU));
 
   n = LCTF_INFO_VLEN (fp, tp->ctt_info);
   if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
@@ -1418,7 +1418,7 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
       const char *membname;
 
       if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0)
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+        return (ctf_set_int_errno (ofp, ctf_errno (fp)));
 
       membname = ctf_strptr (fp, memb.ctlm_name);
 
@@ -1439,7 +1439,7 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
 	}
     }
 
-  return (ctf_set_errno (ofp, ECTF_NOMEMBNAM));
+  return (ctf_set_int_errno (ofp, ECTF_NOMEMBNAM));
 }
 
 /* Return the array type, index, and size information for the specified ARRAY.  */
@@ -1457,7 +1457,7 @@ ctf_array_info (ctf_dict_t *fp, ctf_id_t type, ctf_arinfo_t *arp)
     return -1;			/* errno is set for us.  */
 
   if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ARRAY)
-    return (ctf_set_errno (ofp, ECTF_NOTARRAY));
+    return (ctf_set_int_errno (ofp, ECTF_NOTARRAY));
 
   if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
     ap = (const ctf_array_t *) dtd->dtd_vlen;
@@ -1494,7 +1494,7 @@ ctf_enum_name (ctf_dict_t *fp, ctf_id_t type, int value)
 
   if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM)
     {
-      ctf_set_errno (ofp, ECTF_NOTENUM);
+      ctf_set_type_errno (ofp, ECTF_NOTENUM);
       return NULL;
     }
 
@@ -1511,7 +1511,7 @@ ctf_enum_name (ctf_dict_t *fp, ctf_id_t type, int value)
 	return (ctf_strptr (fp, ep->cte_name));
     }
 
-  ctf_set_errno (ofp, ECTF_NOENUMNAM);
+  ctf_set_type_errno (ofp, ECTF_NOENUMNAM);
   return NULL;
 }
 
@@ -1536,7 +1536,7 @@ ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp)
 
   if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM)
     {
-      (void) ctf_set_errno (ofp, ECTF_NOTENUM);
+      (void) ctf_set_int_errno (ofp, ECTF_NOTENUM);
       return -1;
     }
 
@@ -1557,7 +1557,7 @@ ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp)
 	}
     }
 
-  ctf_set_errno (ofp, ECTF_NOENUMNAM);
+  ctf_set_int_errno (ofp, ECTF_NOENUMNAM);
   return -1;
 }
 
@@ -1584,7 +1584,7 @@ ctf_func_type_info (ctf_dict_t *fp, ctf_id_t type, ctf_funcinfo_t *fip)
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
   if (kind != CTF_K_FUNCTION)
-    return (ctf_set_errno (ofp, ECTF_NOTFUNC));
+    return (ctf_set_int_errno (ofp, ECTF_NOTFUNC));
 
   fip->ctc_return = tp->ctt_type;
   fip->ctc_flags = 0;
@@ -1697,7 +1697,7 @@ ctf_type_rvisit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func,
       ctf_lmember_t memb;
 
       if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0)
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+        return (ctf_set_int_errno (ofp, ctf_errno (fp)));
 
       if ((rc = ctf_type_rvisit (fp, memb.ctlm_type,
 				 func, arg, ctf_strptr (fp, memb.ctlm_name),
diff --git a/libctf/ctf-util.c b/libctf/ctf-util.c
index 9f83ab9ab0b..e0d412df390 100644
--- a/libctf/ctf-util.c
+++ b/libctf/ctf-util.c
@@ -255,16 +255,6 @@ ctf_set_open_errno (int *errp, int error)
   return NULL;
 }
 
-/* Store the specified error code into the CTF dict, and then return CTF_ERR /
-   -1 for the benefit of the caller. */
-
-unsigned long
-ctf_set_errno (ctf_dict_t *fp, int err)
-{
-  fp->ctf_errno = err;
-  return CTF_ERR;
-}
-
 /* Create a ctf_next_t.  */
 
 ctf_next_t *
-- 
2.25.1


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

* Re: [PATCH v3] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-09-26 14:51                     ` Nick Alcock
  2023-09-26 17:28                       ` [PATCH v4] " Torbjörn SVENSSON
@ 2023-09-26 17:49                       ` Torbjorn SVENSSON
  2023-09-28 16:41                         ` Nick Alcock
  1 sibling, 1 reply; 41+ messages in thread
From: Torbjorn SVENSSON @ 2023-09-26 17:49 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils, amodra, Yvan ROUX



On 2023-09-26 16:51, Nick Alcock wrote:
> On 13 Sep 2023, Torbjorn SVENSSON outgrape:
>> On 2023-09-13 20:37, Nick Alcock wrote:
>>> On 13 Sep 2023, Torbjörn SVENSSON verbalised:
> Honestly I suspect all we need is a better name:
> 
> ctf_set_int_errno(...);
> ctf_set_type_errno(...)
> 
> and then use one or the other, consistently. (Neither needs to call the
> other: they're only two lines long!)

Ok. I've updated the patch (V4) to be like you suggested above.
> 
>> I suppose the ctf_set_errno_unsigned could even be a macro in the ctf-impl.h header file.
> 
> I'd make both of them inline functions personally (I bet it would reduce
> code size!)

I do not see any major difference in code size for the ld.exe binary 
after the change.

> 
>>>> +int
>>>> +ctf_set_errno_signed (ctf_dict_t *fp, int err)
>>>> +{
>>>> +  fp->ctf_errno = err;
>>>> +  /* Don't rely on CTF_ERR here as it will not properly sign extend on 64-bit
>>>> +     Windows ABI.  */
>>>> +  return -1;
>>>> +}
>>> ... that Windows is not really the problem here. It's more
>>> /* Don't rely on CTF_ERR here; it is a ctf_id_t (unsigned long), and
>>>      it will be truncated to a non--1 value on platforms on which int
>>>      and unsigned long are different sizes.  */
>>> perhaps? (At least, I think that's what's going on.)
>>
>> The problem happens when the signed integral type is wider than unsigned long.
> 
> ... sizeof(signed int) > sizeof(unsigned long int)?! Is that even
> possible? I would have assumed from the C type hierarchy and the integer
> conversion rank rules would have required that unsigned long int was at
> least as big as any non-long integral type, but I don't see anywhere
> it's required in the standard, dammit...

I don't know about the 'sizeof(signed int) > sizeof(unsigned long int)' 
part, but what I said was _integral type_, not _int_. In the case where 
I saw the problem, it was ssize_t but I'm not sure what that maps to, 
but it's wider than unsigned long int apparently in this case.

>>> This probably needs testing on a wide variety of platforms with
>>> different type sizes. I'll add throwing this through my entire test
>>> matrix to my todo list, and fix any bugs observed: but the basic idea
>>> looks sound to me.
>>
>> Do you want to run this full matrix before or after submitting the patch?
>> If it's before; when do you think you will have time to do that?
>>
>> Let me know how you want to proceed.
> 
> OK, I'm back from various conferences so I can throw tests past this at
> any time, it's largely automated. So once I stop faffing about and
> changing my mind and we converge on something I'll throw it past every
> test I've got. (It takes a day or so.)

If you do not see any problem with the V4 patch, then please go ahead 
and run the tests that you have to get a verdict.

Kind regards,
Torbjörn

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

* Re: [PATCH v3] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-09-26 17:49                       ` [PATCH v3] " Torbjorn SVENSSON
@ 2023-09-28 16:41                         ` Nick Alcock
  2023-09-29 12:11                           ` Torbjorn SVENSSON
  0 siblings, 1 reply; 41+ messages in thread
From: Nick Alcock @ 2023-09-28 16:41 UTC (permalink / raw)
  To: Torbjorn SVENSSON; +Cc: binutils, amodra, Yvan ROUX

On 26 Sep 2023, Torbjorn SVENSSON said:

> On 2023-09-26 16:51, Nick Alcock wrote:
>> On 13 Sep 2023, Torbjorn SVENSSON outgrape:
>>> On 2023-09-13 20:37, Nick Alcock wrote:
>>>> On 13 Sep 2023, Torbjörn SVENSSON verbalised:
>> Honestly I suspect all we need is a better name:
>> ctf_set_int_errno(...);
>> ctf_set_type_errno(...)
>> and then use one or the other, consistently. (Neither needs to call the
>> other: they're only two lines long!)
>
> Ok. I've updated the patch (V4) to be like you suggested above.

Thanks!

>>> I suppose the ctf_set_errno_unsigned could even be a macro in the ctf-impl.h header file.
>> I'd make both of them inline functions personally (I bet it would reduce
>> code size!)
>
> I do not see any major difference in code size for the ld.exe binary after the change.

Oh well, it was just a pious hope really.

>>>>> +int
>>>>> +ctf_set_errno_signed (ctf_dict_t *fp, int err)
>>>>> +{
>>>>> +  fp->ctf_errno = err;
>>>>> +  /* Don't rely on CTF_ERR here as it will not properly sign extend on 64-bit
>>>>> +     Windows ABI.  */
>>>>> +  return -1;
>>>>> +}
>>>> ... that Windows is not really the problem here. It's more
>>>> /* Don't rely on CTF_ERR here; it is a ctf_id_t (unsigned long), and
>>>>      it will be truncated to a non--1 value on platforms on which int
>>>>      and unsigned long are different sizes.  */
>>>> perhaps? (At least, I think that's what's going on.)
>>>
>>> The problem happens when the signed integral type is wider than unsigned long.
>> ... sizeof(signed int) > sizeof(unsigned long int)?! Is that even
>> possible? I would have assumed from the C type hierarchy and the integer
>> conversion rank rules would have required that unsigned long int was at
>> least as big as any non-long integral type, but I don't see anywhere
>> it's required in the standard, dammit...
>
> I don't know about the 'sizeof(signed int) > sizeof(unsigned long
> int)' part, but what I said was _integral type_, not _int_. In the

Ah true. My apologies.

> case where I saw the problem, it was ssize_t but I'm not sure what
> that maps to, but it's wider than unsigned long int apparently in this
> case.

Aha! So this is *not* a problem with functions returning int -- it is
specifically a problem with functions returning *size_t types*.

My apologies, I misunderstood the entire problem.  We probably *do*
still want ctf_set_errno_signed for functions returning int (for clarity
if nothing else), but for ssize_t in particular this won't do: we
probably want a ctf_set_errno_ssize_t or something. The name is awful
but I wasted a day failing to think of a better one :(

There are very few functions returning (s)size_t in libctf:

extern size_t ctf_archive_count (const ctf_archive_t *);
extern ssize_t ctf_type_lname (ctf_dict_t *, ctf_id_t, char *, size_t);
extern ssize_t ctf_type_size (ctf_dict_t *, ctf_id_t);
extern ssize_t ctf_type_align (ctf_dict_t *, ctf_id_t);
extern ssize_t ctf_member_next (ctf_dict_t *, ctf_id_t, ctf_next_t **,
				const char **name, ctf_id_t *membtype,
				int flags);

Of these, ctf_archive_count () cannot fail, so the problem reduces to
ssize_t alone.  These functions should probably

    return (ssize_t) ctf_set_errno_signed (...))

(it's rare enough that a utility functions to do this is probably
unnecessary).

We also have (in ctf_type_lname):

  if (str == NULL)
    return CTF_ERR;			/* errno is set for us.  */

This should probably become a straight -1 (no cast necessary).
ctf_type_size () already gets this right (but needs _ssize_t adjustments
to its ctf_set_errno () calls, as does get_vbytes_common in ctf-open.c).
The same is true of ctf_type_align (), and, of course, ctf_member_next
().

>>>> This probably needs testing on a wide variety of platforms with
>>>> different type sizes. I'll add throwing this through my entire test
>>>> matrix to my todo list, and fix any bugs observed: but the basic idea
>>>> looks sound to me.
>>>
>>> Do you want to run this full matrix before or after submitting the patch?
>>> If it's before; when do you think you will have time to do that?
>>>
>>> Let me know how you want to proceed.
>> OK, I'm back from various conferences so I can throw tests past this at
>> any time, it's largely automated. So once I stop faffing about and
>> changing my mind and we converge on something I'll throw it past every
>> test I've got. (It takes a day or so.)
>
> If you do not see any problem with the V4 patch, then please go ahead
> and run the tests that you have to get a verdict.

... sorry, I'm still flailing at it. Maybe the above is helpful? (It's
only a very small change atop what you've already done, I think.)

-- 
NULL && (void)

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

* Re: [PATCH v3] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-09-28 16:41                         ` Nick Alcock
@ 2023-09-29 12:11                           ` Torbjorn SVENSSON
  2023-10-02 10:57                             ` Nick Alcock
  0 siblings, 1 reply; 41+ messages in thread
From: Torbjorn SVENSSON @ 2023-09-29 12:11 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils, amodra, Yvan ROUX



On 2023-09-28 18:41, Nick Alcock wrote:
> On 26 Sep 2023, Torbjorn SVENSSON said:
> 
>> On 2023-09-26 16:51, Nick Alcock wrote:
>>> On 13 Sep 2023, Torbjorn SVENSSON outgrape:
>>>> On 2023-09-13 20:37, Nick Alcock wrote:
>>>>> On 13 Sep 2023, Torbjörn SVENSSON verbalised:
>>> Honestly I suspect all we need is a better name:
>>> ctf_set_int_errno(...);
>>> ctf_set_type_errno(...)
>>> and then use one or the other, consistently. (Neither needs to call the
>>> other: they're only two lines long!)
>>
>> Ok. I've updated the patch (V4) to be like you suggested above.
> 
> Thanks!
> 
>>>> I suppose the ctf_set_errno_unsigned could even be a macro in the ctf-impl.h header file.
>>> I'd make both of them inline functions personally (I bet it would reduce
>>> code size!)
>>
>> I do not see any major difference in code size for the ld.exe binary after the change.
> 
> Oh well, it was just a pious hope really.
> 
>>>>>> +int
>>>>>> +ctf_set_errno_signed (ctf_dict_t *fp, int err)
>>>>>> +{
>>>>>> +  fp->ctf_errno = err;
>>>>>> +  /* Don't rely on CTF_ERR here as it will not properly sign extend on 64-bit
>>>>>> +     Windows ABI.  */
>>>>>> +  return -1;
>>>>>> +}
>>>>> ... that Windows is not really the problem here. It's more
>>>>> /* Don't rely on CTF_ERR here; it is a ctf_id_t (unsigned long), and
>>>>>       it will be truncated to a non--1 value on platforms on which int
>>>>>       and unsigned long are different sizes.  */
>>>>> perhaps? (At least, I think that's what's going on.)
>>>>
>>>> The problem happens when the signed integral type is wider than unsigned long.
>>> ... sizeof(signed int) > sizeof(unsigned long int)?! Is that even
>>> possible? I would have assumed from the C type hierarchy and the integer
>>> conversion rank rules would have required that unsigned long int was at
>>> least as big as any non-long integral type, but I don't see anywhere
>>> it's required in the standard, dammit...
>>
>> I don't know about the 'sizeof(signed int) > sizeof(unsigned long
>> int)' part, but what I said was _integral type_, not _int_. In the
> 
> Ah true. My apologies.
> 
>> case where I saw the problem, it was ssize_t but I'm not sure what
>> that maps to, but it's wider than unsigned long int apparently in this
>> case.
> 
> Aha! So this is *not* a problem with functions returning int -- it is
> specifically a problem with functions returning *size_t types*.
> 

So, I'm not sure if were are talking past each other, but I don't think 
it's a *size_t type* issue either.

As I see it, there are 3 different scenarios.

1. The function returns a signed integral type, then -1 would be fine. 
Even a simple (int)-1 would work as it would be sign-extended.

2. The function returns an unsigned integral type that is as wide, or 
wider, than unsigned long. In this case, CTF_ERR will be zero extended 
and the value will be UINT_something_MAX (the number of binary ones 
depends on the sizeof(unsigned long)).

3. The function return an unsigned integral type that is narrower than 
unsigned long. In this case, the cast to unsigned long is wider than the 
return type and may overflow(?). Is it safe to return something bigger 
than can be represented in the return type?

I don't know if the third option above is applicable as I have not 
checked the width of the types that is calling the ctf_set_errno() 
function before my patch, but the other 2 are there.

In my mind, I see it as we need 2 different implementations. One that 
returns a simple -1 and another one that casts it for all unsigned 
calls, but maybe I'm oversimplifying this.


To make things easier, I would actually consider just having the assign 
statement and the return statement inlined (without a macro or inline 
function) directly where they are supposed to be.
Would you be open to removing the ctf_set_errno() function completely 
and just expand it to where it's called (almost like my v2 patch, but 
everywhere instead)?
Alternatively, we could start the discussion on adopting the C11 
standard instead, but I fear that this will be a much longer discussion 
than figuring out what the best approach would be for libctf.


> My apologies, I misunderstood the entire problem.  We probably *do*
> still want ctf_set_errno_signed for functions returning int (for clarity
> if nothing else), but for ssize_t in particular this won't do: we
> probably want a ctf_set_errno_ssize_t or something. The name is awful
> but I wasted a day failing to think of a better one :(
> 
> There are very few functions returning (s)size_t in libctf:
> 
> extern size_t ctf_archive_count (const ctf_archive_t *);
> extern ssize_t ctf_type_lname (ctf_dict_t *, ctf_id_t, char *, size_t);
> extern ssize_t ctf_type_size (ctf_dict_t *, ctf_id_t);
> extern ssize_t ctf_type_align (ctf_dict_t *, ctf_id_t);
> extern ssize_t ctf_member_next (ctf_dict_t *, ctf_id_t, ctf_next_t **,
> 				const char **name, ctf_id_t *membtype,
> 				int flags);
> 
> Of these, ctf_archive_count () cannot fail, so the problem reduces to
> ssize_t alone.  These functions should probably
> 
>      return (ssize_t) ctf_set_errno_signed (...))
> 
> (it's rare enough that a utility functions to do this is probably
> unnecessary).
> 
> We also have (in ctf_type_lname):
> 
>    if (str == NULL)
>      return CTF_ERR;			/* errno is set for us.  */
> 
> This should probably become a straight -1 (no cast necessary).

Yes, this is another place where the problem appears.
Looks like the -Wsign-conversion does not warn when it's the return 
statement for the function. Doing a simple grep in the tree reveals 56 
places that needs to be verified.

> ctf_type_size () already gets this right (but needs _ssize_t adjustments
> to its ctf_set_errno () calls, as does get_vbytes_common in ctf-open.c).
> The same is true of ctf_type_align (), and, of course, ctf_member_next
> ().
> 
>>>>> This probably needs testing on a wide variety of platforms with
>>>>> different type sizes. I'll add throwing this through my entire test
>>>>> matrix to my todo list, and fix any bugs observed: but the basic idea
>>>>> looks sound to me.
>>>>
>>>> Do you want to run this full matrix before or after submitting the patch?
>>>> If it's before; when do you think you will have time to do that?
>>>>
>>>> Let me know how you want to proceed.
>>> OK, I'm back from various conferences so I can throw tests past this at
>>> any time, it's largely automated. So once I stop faffing about and
>>> changing my mind and we converge on something I'll throw it past every
>>> test I've got. (It takes a day or so.)
>>
>> If you do not see any problem with the V4 patch, then please go ahead
>> and run the tests that you have to get a verdict.
> 
> ... sorry, I'm still flailing at it. Maybe the above is helpful? (It's
> only a very small change atop what you've already done, I think.)
> 

Let me know how you want to handle this. :)

Kind regards,
Torbjörn


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

* Re: [PATCH v3] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-09-29 12:11                           ` Torbjorn SVENSSON
@ 2023-10-02 10:57                             ` Nick Alcock
  2023-10-03 12:59                               ` Torbjorn SVENSSON
  0 siblings, 1 reply; 41+ messages in thread
From: Nick Alcock @ 2023-10-02 10:57 UTC (permalink / raw)
  To: Torbjorn SVENSSON; +Cc: binutils, amodra, Yvan ROUX

On 29 Sep 2023, Torbjorn SVENSSON verbalised:

> On 2023-09-28 18:41, Nick Alcock wrote:
>> Aha! So this is *not* a problem with functions returning int -- it is
>> specifically a problem with functions returning *size_t types*.
>
> So, I'm not sure if were are talking past each other, but I don't think it's a *size_t type* issue either.
>
> As I see it, there are 3 different scenarios.
>
> 1. The function returns a signed integral type, then -1 would be fine.
> Even a simple (int)-1 would work as it would be sign-extended.

Ack.

> 2. The function returns an unsigned integral type that is as wide, or
> wider, than unsigned long. In this case, CTF_ERR will be zero extended
> and the value will be UINT_something_MAX (the number of binary ones
> depends on the sizeof(unsigned long)).

Ack. This is the problem area, because the interface contract for libctf
specifies (or would if it were written down anywhere) that you can test
all signed returns for error via < 0 and all unsigned ones (like
ctf_id_t) via == CTF_ERR, and CTF_ERR... has a cast in it.

I suppose if we changed CTF_ERR to (uintmax_t)-1 this might work for all
cases, but a) uintmax_t is an annoying sod that doesn't even extend to
the largest possible unsigned integral type on all platforms and b) this
just gives us the same problem from the other side if the unsigned type
is shorter than uintmax_t (which it almost always would be). What would
happen to the (unsigned long)-1 the libctf function returned when it was
promoted? Would it turn into (uintmax_t)-1 consistently, given that the
type has no sign so sign-extension presumably does not apply? I've tried
to figure it out from the standard text and I guess fevers and bacterial
infections are not compatible with reading standardese because I haven't
worked it out yet :P

(or maybe you need to be on more serious drugs than I'm on when reading
it. It might well be that way round!)

> 3. The function return an unsigned integral type that is narrower than
> unsigned long. In this case, the cast to unsigned long is wider than
> the return type and may overflow(?). Is it safe to return something
> bigger than can be represented in the return type?

Are there any of those at all? I don't think so. It's possible in theory
but I don't think we use unsigned int anywhere. I suppose size_t might
be unsigned int on some platforms, and then this problem might arise.

> In my mind, I see it as we need 2 different implementations. One that
> returns a simple -1 and another one that casts it for all unsigned
> calls, but maybe I'm oversimplifying this.

I suppose if it was always done *at the return site* so the compiler
could always see the return type properly, it would always get the cast
right: my worry is the CTF_ERR at the test site, in the user code we
cannot affect (except by changing CTF_ERR).

> To make things easier, I would actually consider just having the
> assign statement and the return statement inlined (without a macro or
> inline function) directly where they are supposed to be.
> 
> Would you be open to removing the ctf_set_errno() function completely
> and just expand it to where it's called (almost like my v2 patch, but
> everywhere instead)?

Well, you could use a macro to make it less gross. All the code
duplication makes me wince a bit.

But more problematic from my perspective is the implications for the
callers. We're trying to get either -1 or (some type)-1 to the callers
so they can error-check it in a consistent and not-too-horrifying
fashion, after all. (We could add a ctf_is_error() function or macro
that does whatever magic is needed if it's too baroque, but that would
be my least favourite option because it looks nothing like a
conditional.)

> Alternatively, we could start the discussion on adopting the C11 standard instead, but I fear that this will be a much longer
> discussion than figuring out what the best approach would be for libctf.

Agreed, or I'd have proposed it already. Toolchain projects like
binutils must be conservative, and there are no doubt lots of archaic
weird but valid targets out there where the bootstrap chain requires
binutils building before GCC and the system compiler is not C11-capable.

>> ... sorry, I'm still flailing at it. Maybe the above is helpful? (It's
>> only a very small change atop what you've already done, I think.)
>
> Let me know how you want to handle this. :)

I think we're still narrowing down the problem, really. -1 is such a
common error return, it's amazing how hard it is to make it work right :)

-- 
NULL && (void)

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

* Re: [PATCH v3] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-10-02 10:57                             ` Nick Alcock
@ 2023-10-03 12:59                               ` Torbjorn SVENSSON
  2023-10-03 20:53                                 ` Nick Alcock
  0 siblings, 1 reply; 41+ messages in thread
From: Torbjorn SVENSSON @ 2023-10-03 12:59 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils, Alan Modra, Yvan Roux

Hello Nick,


On 2023-10-02 12:57, Nick Alcock wrote:
> On 29 Sep 2023, Torbjorn SVENSSON verbalised:
> 
>> On 2023-09-28 18:41, Nick Alcock wrote:
>>> Aha! So this is *not* a problem with functions returning int -- it is
>>> specifically a problem with functions returning *size_t types*.
>>
>> So, I'm not sure if were are talking past each other, but I don't think it's a *size_t type* issue either.
>>
>> As I see it, there are 3 different scenarios.
>>
>> 1. The function returns a signed integral type, then -1 would be fine.
>> Even a simple (int)-1 would work as it would be sign-extended.
> 
> Ack.
> 
>> 2. The function returns an unsigned integral type that is as wide, or
>> wider, than unsigned long. In this case, CTF_ERR will be zero extended
>> and the value will be UINT_something_MAX (the number of binary ones
>> depends on the sizeof(unsigned long)).
> 
> Ack. This is the problem area, because the interface contract for libctf
> specifies (or would if it were written down anywhere) that you can test
> all signed returns for error via < 0 and all unsigned ones (like
> ctf_id_t) via == CTF_ERR, and CTF_ERR... has a cast in it.

I don't think this is true with the current logic in place.
On a signed integral function, it could be either -1 (negative one) or, 
if the data type of the called function is wide enough, CTF_ERR.

> I suppose if we changed CTF_ERR to (uintmax_t)-1 this might work for all
> cases, but a) uintmax_t is an annoying sod that doesn't even extend to
> the largest possible unsigned integral type on all platforms and b) this
> just gives us the same problem from the other side if the unsigned type
> is shorter than uintmax_t (which it almost always would be). What would
> happen to the (unsigned long)-1 the libctf function returned when it was
> promoted? Would it turn into (uintmax_t)-1 consistently, given that the
> type has no sign so sign-extension presumably does not apply? I've tried
> to figure it out from the standard text and I guess fevers and bacterial
> infections are not compatible with reading standardese because I haven't
> worked it out yet :P
> 
> (or maybe you need to be on more serious drugs than I'm on when reading
> it. It might well be that way round!)
> 
>> 3. The function return an unsigned integral type that is narrower than
>> unsigned long. In this case, the cast to unsigned long is wider than
>> the return type and may overflow(?). Is it safe to return something
>> bigger than can be represented in the return type?
> 
> Are there any of those at all? I don't think so. It's possible in theory
> but I don't think we use unsigned int anywhere. I suppose size_t might
> be unsigned int on some platforms, and then this problem might arise.
> 
>> In my mind, I see it as we need 2 different implementations. One that
>> returns a simple -1 and another one that casts it for all unsigned
>> calls, but maybe I'm oversimplifying this.
> 
> I suppose if it was always done *at the return site* so the compiler
> could always see the return type properly, it would always get the cast
> right: my worry is the CTF_ERR at the test site, in the user code we
> cannot affect (except by changing CTF_ERR).

I suppose so, but does it really matter when we cannot do this part? Or 
are you thinking about just having the ctf_set_errno function always 
return -1 (negative one) and let the caller do the automagic conversion? 
If so, I think the idiom with return_value == CTF_ERR is going to fail.

>> To make things easier, I would actually consider just having the
>> assign statement and the return statement inlined (without a macro or
>> inline function) directly where they are supposed to be.
>>
>> Would you be open to removing the ctf_set_errno() function completely
>> and just expand it to where it's called (almost like my v2 patch, but
>> everywhere instead)?
> 
> Well, you could use a macro to make it less gross. All the code
> duplication makes me wince a bit.

How would a macro work for this?

Consider that a function returns a char*, in this case, neither CTF_ERR, 
nor -1 should be returned, but instead NULL. Using a macro would make 
this problematic to differentiate.

A possibility could be to have a macro like:

#define CTF_SET_ERRNO(fp,err) do { fp->ctf_errno = err; } while(0)

but what's the point?
Is it better to write:

if (some_failure_condition)
   {
     CTF_SET_ERRNO(fp, ENOMEM);
     return -1; // or CTF_ERR, NULL, ..., depending on the function
   }

instead of:

if (some_failure_condition)
   {
     fp->ctf_errno = ENOMEM;
     return -1; // or CTF_ERR, NULL, ..., depending on the function
   }


> But more problematic from my perspective is the implications for the
> callers. We're trying to get either -1 or (some type)-1 to the callers
> so they can error-check it in a consistent and not-too-horrifying
> fashion, after all. (We could add a ctf_is_error() function or macro
> that does whatever magic is needed if it's too baroque, but that would
> be my least favourite option because it looks nothing like a
> conditional.)

Adding a ctf_is_error()-function would be one way to go, but it would be 
an API change while all the others I've been talking about is internal 
into the library without actually touching the interface.

>> Alternatively, we could start the discussion on adopting the C11 standard instead, but I fear that this will be a much longer
>> discussion than figuring out what the best approach would be for libctf.
> 
> Agreed, or I'd have proposed it already. Toolchain projects like
> binutils must be conservative, and there are no doubt lots of archaic
> weird but valid targets out there where the bootstrap chain requires
> binutils building before GCC and the system compiler is not C11-capable.
> 
>>> ... sorry, I'm still flailing at it. Maybe the above is helpful? (It's
>>> only a very small change atop what you've already done, I think.)
>>
>> Let me know how you want to handle this. :)
> 
> I think we're still narrowing down the problem, really. -1 is such a
> common error return, it's amazing how hard it is to make it work right :)
> 

So, based on all we have talk about so for, I'm leaning towards just 
having the 2 statements in all places where an error should be returned 
and have the change contained inside the library rather than making 
external changes required.
Then the question is, would the CTF_SET_ERRNO macro have anything to 
add? I.e. should we have it even if it's just setting the field or 
should we set the field directly? Regardless, the return statement needs 
to be kept outside that block.

Please let me know what you think so that we can progress on this topic.
I'm currently blocked by this point for the tool chain that I'm supposed 
to deliver.

Kind regards,
Torbjörn

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

* Re: [PATCH v3] libctf: ctf_member_next needs to return (ssize_t)-1 on error
  2023-10-03 12:59                               ` Torbjorn SVENSSON
@ 2023-10-03 20:53                                 ` Nick Alcock
  2023-10-05  8:39                                   ` [PATCH v5] libctf: Sanitize error types for PR 30836 Torbjörn SVENSSON
  0 siblings, 1 reply; 41+ messages in thread
From: Nick Alcock @ 2023-10-03 20:53 UTC (permalink / raw)
  To: Torbjorn SVENSSON; +Cc: binutils, Alan Modra, Yvan Roux

This is a really fiddly horror show, isn't it...

On 3 Oct 2023, Torbjorn SVENSSON outgrape:

> On 2023-10-02 12:57, Nick Alcock wrote:
>> On 29 Sep 2023, Torbjorn SVENSSON verbalised:
>> 
>>> On 2023-09-28 18:41, Nick Alcock wrote:
>> Ack. This is the problem area, because the interface contract for libctf
>> specifies (or would if it were written down anywhere) that you can test
>> all signed returns for error via < 0 and all unsigned ones (like
>> ctf_id_t) via == CTF_ERR, and CTF_ERR... has a cast in it.
>
> I don't think this is true with the current logic in place.
> On a signed integral function, it could be either -1 (negative one) or, if the data type of the called function is wide enough,
> CTF_ERR.

Oh. That needs fixing then -- there's no other way for the caller to
tell what to test, and honestly even '-1 for signed, CTF_ERR for
unsigned and ctf_id_t, == NULL for pointers' is complex enough that it's
a source of errors all on its own :(

>>> In my mind, I see it as we need 2 different implementations. One that
>>> returns a simple -1 and another one that casts it for all unsigned
>>> calls, but maybe I'm oversimplifying this.
>> I suppose if it was always done *at the return site* so the compiler
>> could always see the return type properly, it would always get the cast
>> right: my worry is the CTF_ERR at the test site, in the user code we
>> cannot affect (except by changing CTF_ERR).
>
> I suppose so, but does it really matter when we cannot do this part?

I was assuming that a *macro*

#define ctf_set_errno(fp, err) do {
    (fp)->ctf_errno = (err);
    return -1;
} while (0);

would return the right thing automatically -- but oh ugh that's a
behaviour change, ctf_set_errno does not do a return currently. That
won't work. Fixing that to get a ctf_set_errno macro to return a
suitable value requires the statement-expression extension which of
course we cannot rely on being present in binutils :( so a
ctf_set_errno macro is untenable. Dammit.

> Or are you thinking about just having the ctf_set_errno function
> always return -1 (negative one) and let the caller do the automagic
> conversion?

I was assuming that the callee would do it.

>             If so, I think the idiom with return_value == CTF_ERR is
> going to fail.

Oh wait, I see -- if some return types are wider than unsigned long,
CTF_ERR is not going to equal -1 for comparisons against that type. Ew.
And of course what that type is is platform-dependent.

Maybe we *can* get away with using uintmax_t in the definition of
CTF_ERR?

>>> To make things easier, I would actually consider just having the
>>> assign statement and the return statement inlined (without a macro or
>>> inline function) directly where they are supposed to be.
>>>
>>> Would you be open to removing the ctf_set_errno() function completely
>>> and just expand it to where it's called (almost like my v2 patch, but
>>> everywhere instead)?
>> Well, you could use a macro to make it less gross. All the code
>> duplication makes me wince a bit.
>
> How would a macro work for this?

Not sure. I'm casting about and not even writing enough test cases I'm
afraid. :(

I disproved the macro in this reply anyway (see above). Sorry, I'm
thinking very slowly right now.

> Consider that a function returns a char*, in this case, neither CTF_ERR, nor -1 should be returned, but instead NULL. Using a macro
> would make this problematic to differentiate.

Ah yes, pointers are the third case. Obviously NULL == error for those.

> A possibility could be to have a macro like:
>
> #define CTF_SET_ERRNO(fp,err) do { fp->ctf_errno = err; } while(0)
>
> but what's the point?
> Is it better to write:
>
> if (some_failure_condition)
>   {
>     CTF_SET_ERRNO(fp, ENOMEM);
>     return -1; // or CTF_ERR, NULL, ..., depending on the function
>   }
>
> instead of:
>
> if (some_failure_condition)
>   {
>     fp->ctf_errno = ENOMEM;
>     return -1; // or CTF_ERR, NULL, ..., depending on the function
>   }

I'd say stick with the fp->ctf_errno assignment, it's far clearer than a
SHOUTY MACRO that just does an assignment. The whole point of
ctf_set_errno() in the first place was to avoid the need for multiple
statements and thus a new block: if we need multiple statements anyway
because of return-type pain like this, we might as well dump the macro.

(assuming this works, because that's a lot of changes to stick you
with.)

>> But more problematic from my perspective is the implications for the
>> callers. We're trying to get either -1 or (some type)-1 to the callers
>> so they can error-check it in a consistent and not-too-horrifying
>> fashion, after all. (We could add a ctf_is_error() function or macro
>> that does whatever magic is needed if it's too baroque, but that would
>> be my least favourite option because it looks nothing like a
>> conditional.)
>
> Adding a ctf_is_error()-function would be one way to go, but it would be an API change while all the others I've been talking about
> is internal into the library without actually touching the interface.

That's exactly my objection too (also, it's clunky as hell). I really do
want to avoid that. My big fear here is that you've found some
fundamental problem with a -1 signed, CTF_ERR unsigned return (we can't
even change the definition of CTF_ERR, because it's baked into callers,
while libctf can change under them.)

>> I think we're still narrowing down the problem, really. -1 is such a
>> common error return, it's amazing how hard it is to make it work right :)
>
> So, based on all we have talk about so for, I'm leaning towards just
> having the 2 statements in all places where an error should be
> returned and have the change contained inside the library rather than
> making external changes required.

I think you're right.

> Then the question is, would the CTF_SET_ERRNO macro have anything to
> add? I.e. should we have it even if it's just setting the field or
> should we set the field directly? Regardless, the return statement
> needs to be kept outside that block.

I'd go for dumping CTF_SET_ERRNO: just switch to a scheme where we set
fp->ctf_errno and do a return. It adds a few more {} blocks but that's
unavoidable in the absence of statement expressions. (And half the
places we care about don't need new blocks anyway.)

> Please let me know what you think so that we can progress on this topic.
> I'm currently blocked by this point for the tool chain that I'm supposed to deliver.

Oh I'm sorry!

-- 
NULL && (void)

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

* [PATCH v5] libctf: Sanitize error types for PR 30836
  2023-10-03 20:53                                 ` Nick Alcock
@ 2023-10-05  8:39                                   ` Torbjörn SVENSSON
  2023-10-09 10:27                                     ` Nick Alcock
  0 siblings, 1 reply; 41+ messages in thread
From: Torbjörn SVENSSON @ 2023-10-05  8:39 UTC (permalink / raw)
  To: binutils, nick.alcock; +Cc: amodra, Torbjörn SVENSSON, Yvan ROUX

v1 -> v2:
Changed all functions with signed interger return type to return -1 based on
comment from Alan.

v2 -> v3:
Added ctf_set_errno_signed function to return a signed -1 value based on
comment from Nick.

v3 -> v4:
- Moved ctf_set_errno_signed function to ctf-inlines.h, renamed it to
ctf_set_int_errno and converted it to an inline function.
- Moved ctf_set_errno function to ctf-inlines.h, renamed it to
ctf_set_type_errno, changed return type to ctf_id_t and converted it to an
inline function.
- Updated the changelog entry in the commit message. Is this list really
required? I don't think it give much information in this patch and 'git log'
have mixed commits (some have the entry while others don't).

v4 -> v5:
Updated in accordance with comments from Nick.
- Changed return type to void for ctf_set_errno.
- Inline the return on every call to ctf_set_errno.
- Merged ctf_set_int_errno and ctf_set_type_errno into ctf_set_errno.
- Droped log entry as it's too many places with this change to make it
  readable.
- Corrected a few places where -1 was returned where it should have been
  CTF_ERR.


@Nick: Can you please try this is in your test bench and let me know if it's
ok for trunk?


--

Made sure there is no implicit conversion between signed and unsigned
return value for functions setting the ctf_errno value.
An example of the problem is that in ctf_member_next, the "offset" value
is either 0L or (ctf_id_t)-1L, but it should have been 0L or -1L.
The issue was discovered while building a 64 bit ld binary to be
executed on the Windows platform.
Example object file that demonstrates the issue is attached in the PR.

Signed-off-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
Co-Authored-By: Yvan ROUX <yvan.roux@foss.st.com>
---
 libctf/ctf-create.c    | 321 ++++++++++++++++++++++++++++++++---------
 libctf/ctf-dedup.c     | 130 ++++++++++++-----
 libctf/ctf-dump.c      |  40 +++--
 libctf/ctf-impl.h      |   1 -
 libctf/ctf-inlines.h   |   6 +
 libctf/ctf-labels.c    |  19 ++-
 libctf/ctf-link.c      |  69 +++++++--
 libctf/ctf-lookup.c    |  94 ++++++++----
 libctf/ctf-open.c      |  33 ++++-
 libctf/ctf-serialize.c |  49 +++++--
 libctf/ctf-string.c    |   5 +-
 libctf/ctf-types.c     | 160 +++++++++++++++-----
 libctf/ctf-util.c      |  10 --
 13 files changed, 696 insertions(+), 241 deletions(-)

diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 6b342dc64a2..b3205cd828d 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -60,7 +60,10 @@ ctf_grow_ptrtab (ctf_dict_t *fp)
 
       if ((new_ptrtab = realloc (fp->ctf_ptrtab,
 				 new_ptrtab_len * sizeof (uint32_t))) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	{
+	  ctf_set_errno (fp, ENOMEM);
+	  return -1;
+	}
 
       fp->ctf_ptrtab = new_ptrtab;
       memset (fp->ctf_ptrtab + fp->ctf_ptrtab_len, 0,
@@ -87,7 +90,8 @@ ctf_grow_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vlen)
 				dtd->dtd_vlen_alloc * 2)) == NULL)
     {
       dtd->dtd_vlen = old;
-      return (ctf_set_errno (fp, ENOMEM));
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
     }
   memset (dtd->dtd_vlen + dtd->dtd_vlen_alloc, 0, dtd->dtd_vlen_alloc);
   dtd->dtd_vlen_alloc *= 2;
@@ -197,7 +201,10 @@ int
 ctf_update (ctf_dict_t *fp)
 {
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return -1;
+    }
 
   fp->ctf_dtoldid = fp->ctf_typemax;
   return 0;
@@ -391,10 +398,16 @@ ctf_rollback (ctf_dict_t *fp, ctf_snapshot_id_t id)
   ctf_dvdef_t *dvd, *nvd;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return -1;
+    }
 
   if (fp->ctf_snapshot_lu >= id.snapshot_id)
-    return (ctf_set_errno (fp, ECTF_OVERROLLBACK));
+    {
+      ctf_set_errno (fp, ECTF_OVERROLLBACK);
+      return -1;
+    }
 
   for (dtd = ctf_list_next (&fp->ctf_dtdefs); dtd != NULL; dtd = ntd)
     {
@@ -453,23 +466,38 @@ ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
   ctf_id_t type;
 
   if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT)
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return CTF_ERR;
+    }
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return CTF_ERR;
+    }
 
   if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) >= CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, ECTF_FULL));
+    {
+      ctf_set_errno (fp, ECTF_FULL);
+      return CTF_ERR;
+    }
 
   if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) == (CTF_MAX_PTYPE - 1))
-    return (ctf_set_errno (fp, ECTF_FULL));
+    {
+      ctf_set_errno (fp, ECTF_FULL);
+      return CTF_ERR;
+    }
 
   /* Make sure ptrtab always grows to be big enough for all types.  */
   if (ctf_grow_ptrtab (fp) < 0)
       return CTF_ERR;				/* errno is set for us. */
 
   if ((dtd = calloc (1, sizeof (ctf_dtdef_t))) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+    {
+      ctf_set_errno (fp, EAGAIN);
+      return CTF_ERR;
+    }
 
   dtd->dtd_vlen_alloc = vlen;
   if (vlen > 0)
@@ -532,13 +560,19 @@ ctf_add_encoded (ctf_dict_t *fp, uint32_t flag,
   uint32_t encoding;
 
   if (ep == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return CTF_ERR;
+    }
 
   if (name == NULL || name[0] == '\0')
-    return (ctf_set_errno (fp, ECTF_NONAME));
+    {
+      ctf_set_errno (fp, ECTF_NONAME);
+      return CTF_ERR;
+    }
 
   if (!ctf_assert (fp, kind == CTF_K_INTEGER || kind == CTF_K_FLOAT))
-    return -1;					/* errno is set for us.  */
+    return CTF_ERR;					/* errno is set for us.  */
 
   if ((type = ctf_add_generic (fp, flag, name, kind, sizeof (uint32_t),
 			       &dtd)) == CTF_ERR)
@@ -570,7 +604,10 @@ ctf_add_reftype (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref, uint32_t kind)
   int child = fp->ctf_flags & LCTF_CHILD;
 
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return CTF_ERR;
+    }
 
   if (ref != 0 && ctf_lookup_by_id (&tmp, ref) == NULL)
     return CTF_ERR;		/* errno is set for us.  */
@@ -613,13 +650,22 @@ ctf_add_slice (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref,
   ctf_dict_t *tmp = fp;
 
   if (ep == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return CTF_ERR;
+    }
 
   if ((ep->cte_bits > 255) || (ep->cte_offset > 255))
-    return (ctf_set_errno (fp, ECTF_SLICEOVERFLOW));
+    {
+      ctf_set_errno (fp, ECTF_SLICEOVERFLOW);
+      return CTF_ERR;
+    }
 
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return CTF_ERR;
+    }
 
   if (ref != 0 && ((tp = ctf_lookup_by_id (&tmp, ref)) == NULL))
     return CTF_ERR;		/* errno is set for us.  */
@@ -634,7 +680,10 @@ ctf_add_slice (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref,
   if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) &&
       (kind != CTF_K_ENUM)
       && (ref != 0))
-    return (ctf_set_errno (fp, ECTF_NOTINTFP));
+    {
+      ctf_set_errno (fp, ECTF_NOTINTFP);
+      return CTF_ERR;
+    }
 
   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_SLICE,
 			       sizeof (ctf_slice_t), &dtd)) == CTF_ERR)
@@ -682,7 +731,10 @@ ctf_add_array (ctf_dict_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
   ctf_dict_t *tmp = fp;
 
   if (arp == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return CTF_ERR;
+    }
 
   if (arp->ctr_contents != 0
       && ctf_lookup_by_id (&tmp, arp->ctr_contents) == NULL)
@@ -697,7 +749,8 @@ ctf_add_array (ctf_dict_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
       ctf_err_warn (fp, 1, ECTF_INCOMPLETE,
 		    _("ctf_add_array: index type %lx is incomplete"),
 		    arp->ctr_contents);
-      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+      ctf_set_errno (fp, ECTF_INCOMPLETE);
+      return CTF_ERR;
     }
 
   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_ARRAY,
@@ -723,11 +776,17 @@ ctf_set_array (ctf_dict_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
   ctf_array_t *vlen;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return -1;
+    }
 
   if (dtd == NULL
       || LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info) != CTF_K_ARRAY)
-    return (ctf_set_errno (fp, ECTF_BADID));
+    {
+      ctf_set_errno (fp, ECTF_BADID);
+      return -1;
+    }
 
   vlen = (ctf_array_t *) dtd->dtd_vlen;
   fp->ctf_flags |= LCTF_DIRTY;
@@ -751,11 +810,17 @@ ctf_add_function (ctf_dict_t *fp, uint32_t flag,
   size_t i;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return CTF_ERR;
+    }
 
   if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0
       || (ctc->ctc_argc != 0 && argv == NULL))
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return CTF_ERR;
+    }
 
   vlen = ctc->ctc_argc;
   if (ctc->ctc_flags & CTF_FUNC_VARARG)
@@ -766,7 +831,10 @@ ctf_add_function (ctf_dict_t *fp, uint32_t flag,
     return CTF_ERR;				/* errno is set for us.  */
 
   if (vlen > CTF_MAX_VLEN)
-    return (ctf_set_errno (fp, EOVERFLOW));
+    {
+      ctf_set_errno (fp, EOVERFLOW);
+      return CTF_ERR;
+    }
 
   /* One word extra allocated for padding for 4-byte alignment if need be.
      Not reflected in vlen: we don't want to copy anything into it, and
@@ -818,7 +886,10 @@ ctf_add_struct_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (dtd->dtd_vlen_alloc == 0)
     {
       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	{
+	  ctf_set_errno (fp, ENOMEM);
+	  return CTF_ERR;
+	}
       dtd->dtd_vlen_alloc = initial_vlen;
     }
 
@@ -858,7 +929,10 @@ ctf_add_union_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (dtd->dtd_vlen_alloc == 0)
     {
       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	{
+	  ctf_set_errno (fp, ENOMEM);
+	  return CTF_ERR;
+	}
       dtd->dtd_vlen_alloc = initial_vlen;
     }
 
@@ -897,7 +971,10 @@ ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
   if (dtd->dtd_vlen_alloc == 0)
     {
       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	{
+	  ctf_set_errno (fp, ENOMEM);
+	  return CTF_ERR;
+	}
       dtd->dtd_vlen_alloc = initial_vlen;
     }
 
@@ -925,7 +1002,10 @@ ctf_add_enum_encoded (ctf_dict_t *fp, uint32_t flag, const char *name,
     {
       if ((ctf_type_kind (fp, type) != CTF_K_FORWARD) &&
 	  (ctf_type_kind_unsliced (fp, type) != CTF_K_ENUM))
-	return (ctf_set_errno (fp, ECTF_NOTINTFP));
+	{
+	  ctf_set_errno (fp, ECTF_NOTINTFP);
+	  return CTF_ERR;
+	}
     }
   else if ((type = ctf_add_enum (fp, flag, name)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
@@ -943,10 +1023,16 @@ ctf_add_forward (ctf_dict_t *fp, uint32_t flag, const char *name,
   ctf_id_t type = 0;
 
   if (!ctf_forwardable_kind (kind))
-    return (ctf_set_errno (fp, ECTF_NOTSUE));
+    {
+      ctf_set_errno (fp, ECTF_NOTSUE);
+      return CTF_ERR;
+    }
 
   if (name == NULL || name[0] == '\0')
-    return (ctf_set_errno (fp, ECTF_NONAME));
+    {
+      ctf_set_errno (fp, ECTF_NONAME);
+      return CTF_ERR;
+    }
 
   /* If the type is already defined or exists as a forward tag, just
      return the ctf_id_t of the existing definition.  */
@@ -985,7 +1071,8 @@ ctf_add_unknown (ctf_dict_t *fp, uint32_t flag, const char *name)
 			_("ctf_add_unknown: cannot add unknown type "
 			  "named %s: type of this name already defined"),
 			name ? name : _("(unnamed type)"));
-	  return (ctf_set_errno (fp, ECTF_CONFLICT));
+	  ctf_set_errno (fp, ECTF_CONFLICT);
+	  return CTF_ERR;
 	}
     }
 
@@ -1007,10 +1094,16 @@ ctf_add_typedef (ctf_dict_t *fp, uint32_t flag, const char *name,
   ctf_dict_t *tmp = fp;
 
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return CTF_ERR;
+    }
 
   if (name == NULL || name[0] == '\0')
-    return (ctf_set_errno (fp, ECTF_NONAME));
+    {
+      ctf_set_errno (fp, ECTF_NONAME);
+      return CTF_ERR;
+    }
 
   if (ref != 0 && ctf_lookup_by_id (&tmp, ref) == NULL)
     return CTF_ERR;		/* errno is set for us.  */
@@ -1055,23 +1148,38 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
   uint32_t kind, vlen, root;
 
   if (name == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return -1;
+    }
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return -1;
+    }
 
   if (dtd == NULL)
-    return (ctf_set_errno (fp, ECTF_BADID));
+    {
+      ctf_set_errno (fp, ECTF_BADID);
+      return -1;
+    }
 
   kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
   root = LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info);
   vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
 
   if (kind != CTF_K_ENUM)
-    return (ctf_set_errno (fp, ECTF_NOTENUM));
+    {
+      ctf_set_errno (fp, ECTF_NOTENUM);
+      return -1;
+    }
 
   if (vlen == CTF_MAX_VLEN)
-    return (ctf_set_errno (fp, ECTF_DTFULL));
+    {
+      ctf_set_errno (fp, ECTF_DTFULL);
+      return -1;
+    }
 
   old_vlen = dtd->dtd_vlen;
   if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0)
@@ -1090,7 +1198,10 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
 
   for (i = 0; i < vlen; i++)
     if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
-      return (ctf_set_errno (fp, ECTF_DUPLICATE));
+      {
+	ctf_set_errno (fp, ECTF_DUPLICATE);
+	return -1;
+      }
 
   en[i].cte_name = ctf_str_add_pending (fp, name, &en[i].cte_name);
   en[i].cte_value = value;
@@ -1119,10 +1230,16 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   ctf_lmember_t *memb;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return -1;
+    }
 
   if (dtd == NULL)
-    return (ctf_set_errno (fp, ECTF_BADID));
+    {
+      ctf_set_errno (fp, ECTF_BADID);
+      return -1;
+    }
 
   if (name != NULL && name[0] == '\0')
     name = NULL;
@@ -1132,10 +1249,16 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
 
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
-    return (ctf_set_errno (fp, ECTF_NOTSOU));
+    {
+      ctf_set_errno (fp, ECTF_NOTSOU);
+      return -1;
+    }
 
   if (vlen == CTF_MAX_VLEN)
-    return (ctf_set_errno (fp, ECTF_DTFULL));
+    {
+      ctf_set_errno (fp, ECTF_DTFULL);
+      return -1;
+    }
 
   old_vlen = dtd->dtd_vlen;
   if (ctf_grow_vlen (fp, dtd, sizeof (ctf_lmember_t) * (vlen + 1)) < 0)
@@ -1156,7 +1279,10 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
     {
       for (i = 0; i < vlen; i++)
 	if (strcmp (ctf_strptr (fp, memb[i].ctlm_name), name) == 0)
-	  return (ctf_set_errno (fp, ECTF_DUPLICATE));
+	  {
+	    ctf_set_errno (fp, ECTF_DUPLICATE);
+	    return -1;
+	  }
     }
 
   if ((msize = ctf_type_size (fp, type)) < 0 ||
@@ -1212,7 +1338,8 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
 			      "incomplete type %lx to struct %lx without "
 			      "specifying explicit offset\n"),
 			    name ? name : _("(unnamed member)"), type, souid);
-	      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+	      ctf_set_errno (fp, ECTF_INCOMPLETE);
+	      return -1;
 	    }
 
 	  if (ctf_type_encoding (fp, ltype, &linfo) == 0)
@@ -1285,7 +1412,10 @@ ctf_add_member_encoded (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   int otype = type;
 
   if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) && (kind != CTF_K_ENUM))
-    return (ctf_set_errno (fp, ECTF_NOTINTFP));
+    {
+      ctf_set_errno (fp, ECTF_NOTINTFP);
+      return -1;
+    }
 
   if ((type = ctf_add_slice (fp, CTF_ADD_NONROOT, otype, &encoding)) == CTF_ERR)
     return -1;			/* errno is set for us.  */
@@ -1307,10 +1437,16 @@ ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
   ctf_dict_t *tmp = fp;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return -1;
+    }
 
   if (ctf_dvd_lookup (fp, name) != NULL)
-    return (ctf_set_errno (fp, ECTF_DUPLICATE));
+    {
+      ctf_set_errno (fp, ECTF_DUPLICATE);
+      return -1;
+    }
 
   if (ctf_lookup_by_id (&tmp, ref) == NULL)
     return -1;			/* errno is set for us.  */
@@ -1321,12 +1457,16 @@ ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
     return -1;
 
   if ((dvd = malloc (sizeof (ctf_dvdef_t))) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+    {
+      ctf_set_errno (fp, EAGAIN);
+      return -1;
+    }
 
   if (name != NULL && (dvd->dvd_name = strdup (name)) == NULL)
     {
       free (dvd);
-      return (ctf_set_errno (fp, EAGAIN));
+      ctf_set_errno (fp, EAGAIN);
+      return -1;
     }
   dvd->dvd_type = ref;
   dvd->dvd_snapshots = fp->ctf_snapshots;
@@ -1350,25 +1490,38 @@ ctf_add_funcobjt_sym (ctf_dict_t *fp, int is_function, const char *name, ctf_id_
   ctf_dynhash_t *h = is_function ? fp->ctf_funchash : fp->ctf_objthash;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return -1;
+    }
 
   if (ctf_dynhash_lookup (fp->ctf_objthash, name) != NULL ||
       ctf_dynhash_lookup (fp->ctf_funchash, name) != NULL)
-    return (ctf_set_errno (fp, ECTF_DUPLICATE));
+    {
+      ctf_set_errno (fp, ECTF_DUPLICATE);
+      return -1;
+    }
 
   if (ctf_lookup_by_id (&tmp, id) == NULL)
     return -1;                                  /* errno is set for us.  */
 
   if (is_function && ctf_type_kind (fp, id) != CTF_K_FUNCTION)
-    return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    {
+      ctf_set_errno (fp, ECTF_NOTFUNC);
+      return -1;
+    }
 
   if ((dupname = strdup (name)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    {
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
+    }
 
   if (ctf_dynhash_insert (h, dupname, (void *) (uintptr_t) id) < 0)
     {
       free (dupname);
-      return (ctf_set_errno (fp, ENOMEM));
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
     }
   return 0;
 }
@@ -1575,14 +1728,23 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
   ctf_id_t orig_src_type = src_type;
 
   if (!(dst_fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (dst_fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (dst_fp, ECTF_RDONLY);
+      return CTF_ERR;
+    }
 
   if ((src_tp = ctf_lookup_by_id (&src_fp, src_type)) == NULL)
-    return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+    {
+      ctf_set_errno (dst_fp, ctf_errno (src_fp));
+      return CTF_ERR;
+    }
 
   if ((ctf_type_resolve (src_fp, src_type) == CTF_ERR)
       && (ctf_errno (src_fp) == ECTF_NONREPRESENTABLE))
-    return (ctf_set_errno (dst_fp, ECTF_NONREPRESENTABLE));
+    {
+      ctf_set_errno (dst_fp, ECTF_NONREPRESENTABLE);
+      return CTF_ERR;
+    }
 
   name = ctf_strptr (src_fp, src_tp->ctt_name);
   kind = LCTF_INFO_KIND (src_fp, src_tp->ctt_info);
@@ -1661,7 +1823,8 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 			_("ctf_add_type: conflict for type %s: "
 			  "kinds differ, new: %i; old (ID %lx): %i"),
 			name, kind, dst_type, dst_kind);
-	  return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	  ctf_set_errno (dst_fp, ECTF_CONFLICT);
+	  return CTF_ERR;
 	}
     }
 
@@ -1672,7 +1835,10 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
   if (kind == CTF_K_INTEGER || kind == CTF_K_FLOAT || kind == CTF_K_SLICE)
     {
       if (ctf_type_encoding (src_fp, src_type, &src_en) != 0)
-	return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+	{
+	  ctf_set_errno (dst_fp, ctf_errno (src_fp));
+	  return CTF_ERR;
+	}
 
       if (dst_type != CTF_ERR)
 	{
@@ -1702,7 +1868,8 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 		}
 	      else
 		  {
-		    return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		    ctf_set_errno (dst_fp, ECTF_CONFLICT);
+		    return CTF_ERR;
 		  }
 	    }
 	  else
@@ -1740,7 +1907,10 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 
   if (ctf_dynhash_insert (proc_tracking_fp->ctf_add_processing,
 			  (void *) (uintptr_t) src_type, (void *) 1) < 0)
-    return ctf_set_errno (dst_fp, ENOMEM);
+    {
+      ctf_set_errno (dst_fp, ENOMEM);
+      return CTF_ERR;
+    }
 
   switch (kind)
     {
@@ -1785,7 +1955,10 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 
     case CTF_K_ARRAY:
       if (ctf_array_info (src_fp, src_type, &src_ar) != 0)
-	return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+	{
+	  ctf_set_errno (dst_fp, ctf_errno (src_fp));
+	  return CTF_ERR;
+	}
 
       src_ar.ctr_contents =
 	ctf_add_type_internal (dst_fp, src_fp, src_ar.ctr_contents,
@@ -1812,7 +1985,8 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 			    src_ar.ctr_index, src_ar.ctr_nelems,
 			    dst_ar.ctr_contents, dst_ar.ctr_index,
 			    dst_ar.ctr_nelems);
-	      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	      ctf_set_errno (dst_fp, ECTF_CONFLICT);
+	      return CTF_ERR;
 	    }
 	}
       else
@@ -1859,7 +2033,8 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 				"size differs, old %li, new %li"), name,
 			      dst_type, (long) ctf_type_size (src_fp, src_type),
 			      (long) ctf_type_size (dst_fp, dst_type));
-		return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		ctf_set_errno (dst_fp, ECTF_CONFLICT);
+		return CTF_ERR;
 	      }
 
 	    if (ctf_member_iter (src_fp, src_type, membcmp, &dst))
@@ -1867,7 +2042,8 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 		ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
 			      _("conflict for type %s against ID %lx: members "
 				"differ, see above"), name, dst_type);
-		return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		ctf_set_errno (dst_fp, ECTF_CONFLICT);
+		return CTF_ERR;
 	      }
 
 	    break;
@@ -1925,7 +2101,8 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 	      ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
 			    _("conflict for enum %s against ID %lx: members "
 			      "differ, see above"), name, dst_type);
-	      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	      ctf_set_errno (dst_fp, ECTF_CONFLICT);
+	      return CTF_ERR;
 	    }
 	}
       else
@@ -1964,7 +2141,8 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
       break;
 
     default:
-      return (ctf_set_errno (dst_fp, ECTF_CORRUPT));
+      ctf_set_errno (dst_fp, ECTF_CORRUPT);
+      return CTF_ERR;
     }
 
   if (dst_type != CTF_ERR)
@@ -1985,7 +2163,10 @@ ctf_add_type (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type)
   /* We store the hash on the source, because it contains only source type IDs:
      but callers will invariably expect errors to appear on the dest.  */
   if (!src_fp->ctf_add_processing)
-    return (ctf_set_errno (dst_fp, ENOMEM));
+    {
+      ctf_set_errno (dst_fp, ENOMEM);
+      return CTF_ERR;
+    }
 
   id = ctf_add_type_internal (dst_fp, src_fp, src_type, src_fp);
   ctf_dynhash_empty (src_fp->ctf_add_processing);
diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c
index 5fdddfd0b54..d4f198ccb21 100644
--- a/libctf/ctf-dedup.c
+++ b/libctf/ctf-dedup.c
@@ -378,7 +378,10 @@ ctf_dedup_atoms_init (ctf_dict_t *fp)
       if ((fp->ctf_dedup_atoms_alloc
 	   = ctf_dynset_create (htab_hash_string, htab_eq_string,
 				free)) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	{
+	  ctf_set_errno (fp, ENOMEM);
+	  return -1;
+	}
     }
   fp->ctf_dedup_atoms = fp->ctf_dedup_atoms_alloc;
   return 0;
@@ -543,7 +546,10 @@ ctf_dedup_record_origin (ctf_dict_t *fp, int input_num, const char *decorated,
 
   if (populate_origin)
     if (ctf_dynhash_cinsert (d->cd_struct_origin, decorated, origin) < 0)
-      return ctf_set_errno (fp, errno);
+      {
+	ctf_set_errno (fp, errno);
+	return -1;
+      }
   return 0;
 }
 
@@ -1185,7 +1191,10 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
     }
   else
     if (ctf_dynhash_cinsert (d->cd_output_mapping_guard, id, hval) < 0)
-      return ctf_set_errno (fp, errno);
+      {
+	ctf_set_errno (fp, errno);
+	return -1;
+      }
 #endif
 
   /* Record the type in the output mapping: if this is the first time this type
@@ -1197,17 +1206,24 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
 				      hval)) == NULL)
     {
       if (ctf_dynhash_cinsert (d->cd_output_first_gid, hval, id) < 0)
-	return ctf_set_errno (fp, errno);
+	{
+	  ctf_set_errno (fp, errno);
+	  return -1;
+	}
 
       if ((type_ids = ctf_dynset_create (htab_hash_pointer,
 					 htab_eq_pointer,
 					 NULL)) == NULL)
-	return ctf_set_errno (fp, errno);
+	{
+	  ctf_set_errno (fp, errno);
+	  return -1;
+	}
       if (ctf_dynhash_insert (d->cd_output_mapping, (void *) hval,
 			      type_ids) < 0)
 	{
 	  ctf_dynset_destroy (type_ids);
-	  return ctf_set_errno (fp, errno);
+	  ctf_set_errno (fp, errno);
+	  return -1;
 	}
     }
 #ifdef ENABLE_LIBCTF_HASH_DEBUGGING
@@ -1248,7 +1264,10 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
 	    }
 	}
       if (err != ECTF_NEXT_END)
-	return ctf_set_errno (fp, err);
+	{
+	  ctf_set_errno (fp, err);
+	  return -1;
+	}
     }
 #endif
 
@@ -1256,7 +1275,10 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
      don't waste time reinserting the same keys in that case.  */
   if (!ctf_dynset_exists (type_ids, id, NULL)
       && ctf_dynset_insert (type_ids, id) < 0)
-    return ctf_set_errno (fp, errno);
+    {
+      ctf_set_errno (fp, errno);
+      return -1;
+    }
 
   /* The rest only needs to happen for types with names.  */
   if (!decorated_name)
@@ -1273,12 +1295,16 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
       if ((name_counts = ctf_dynhash_create (ctf_hash_string,
 					     ctf_hash_eq_string,
 					     NULL, NULL)) == NULL)
-	  return ctf_set_errno (fp, errno);
+	{
+	  ctf_set_errno (fp, errno);
+	  return -1;
+	}
       if (ctf_dynhash_cinsert (d->cd_name_counts, decorated_name,
 			       name_counts) < 0)
 	{
 	  ctf_dynhash_destroy (name_counts);
-	  return ctf_set_errno (fp, errno);
+	  ctf_set_errno (fp, errno);
+	  return -1;
 	}
     }
 
@@ -1287,7 +1313,10 @@ ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
 
   if (ctf_dynhash_cinsert (name_counts, hval,
 			   (const void *) (uintptr_t) (count + 1)) < 0)
-    return ctf_set_errno (fp, errno);
+    {
+      ctf_set_errno (fp, errno);
+      return -1;
+    }
 
   return 0;
 }
@@ -1339,10 +1368,11 @@ ctf_dedup_mark_conflicting_hash (ctf_dict_t *fp, const char *hval)
 	  return -1;				/* errno is set for us.  */
 	}
     }
-  if (err != ECTF_NEXT_END)
-    return ctf_set_errno (fp, err);
+  if (err == ECTF_NEXT_END)
+    return 0;
 
-  return 0;
+  ctf_set_errno (fp, err);
+  return -1;
 }
 
 /* Look up a type kind from the output mapping, given a type hash value.  */
@@ -1366,7 +1396,8 @@ ctf_dedup_hash_kind (ctf_dict_t *fp, ctf_dict_t **inputs, const char *hash)
   if (!type_ids)
     {
       ctf_dprintf ("Looked up type kind by nonexistent hash %s.\n", hash);
-      return ctf_set_errno (fp, ECTF_INTERNAL);
+      ctf_set_errno (fp, ECTF_INTERNAL);
+      return -1;
     }
   id = ctf_dynset_lookup_any (type_ids);
   if (!ctf_assert (fp, id))
@@ -1585,7 +1616,8 @@ ctf_dedup_detect_name_ambiguity (ctf_dict_t *fp, ctf_dict_t **inputs)
 
  iterr:
   ctf_err_warn (fp, 0, err, _("iteration failed: %s"), gettext (whaterr));
-  return ctf_set_errno (fp, err);
+  ctf_set_errno (fp, err);
+  return -1;
 
  assert_err:
   ctf_next_destroy (i);
@@ -1683,7 +1715,8 @@ ctf_dedup_init (ctf_dict_t *fp)
  oom:
   ctf_err_warn (fp, 0, ENOMEM, _("ctf_dedup_init: cannot initialize: "
 				 "out of memory"));
-  return ctf_set_errno (fp, ENOMEM);
+  ctf_set_errno (fp, ENOMEM);
+  return -1;
 }
 
 /* No ctf_dedup calls are allowed after this call other than starting a new
@@ -1784,7 +1817,8 @@ ctf_dedup_multiple_input_dicts (ctf_dict_t *output, ctf_dict_t **inputs,
     {
       ctf_err_warn (output, 0, err, _("iteration error "
 				      "propagating conflictedness"));
-      return ctf_set_errno (output, err);
+      ctf_set_errno (output, err);
+      return -1;
     }
 
   if (multiple)
@@ -1879,7 +1913,8 @@ ctf_dedup_conflictify_unshared (ctf_dict_t *output, ctf_dict_t **inputs)
  iterr:
   ctf_dynset_destroy (to_mark);
   ctf_err_warn (output, 0, err, _("conflictifying unshared types"));
-  return ctf_set_errno (output, err);
+  ctf_set_errno (output, err);
+  return -1;
 }
 
 /* The core deduplicator.  Populate cd_output_mapping in the output ctf_dedup
@@ -2219,7 +2254,8 @@ ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
     {
       ctf_err_warn (output, 0, ECTF_INTERNAL,
 		    _("looked up type kind by nonexistent hash %s"), hval);
-      return ctf_set_errno (output, ECTF_INTERNAL);
+      ctf_set_errno (output, ECTF_INTERNAL);
+      return -1;
     }
 
   /* Have we seen this type before?  */
@@ -2237,7 +2273,8 @@ ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
 	{
 	  ctf_err_warn (output, 0, ENOMEM,
 			_("out of memory tracking already-visited types"));
-	  return ctf_set_errno (output, ENOMEM);
+	  ctf_set_errno (output, ENOMEM);
+	  return -1;
 	}
     }
 
@@ -2274,7 +2311,8 @@ ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
   if (err != ECTF_NEXT_END)
     {
       ctf_err_warn (output, 0, err, _("cannot walk conflicted type"));
-      return ctf_set_errno (output, err);
+      ctf_set_errno (output, err);
+      return -1;
     }
 
   return 0;
@@ -2376,7 +2414,10 @@ ctf_dedup_walk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
   if ((already_visited = ctf_dynset_create (htab_hash_string,
 					    htab_eq_string,
 					    NULL)) == NULL)
-    return ctf_set_errno (output, ENOMEM);
+    {
+      ctf_set_errno (output, ENOMEM);
+      return -1;
+    }
 
   sort_arg.inputs = inputs;
   sort_arg.ninputs = ninputs;
@@ -2525,7 +2566,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
   if ((input->ctf_flags & LCTF_CHILD) && (LCTF_TYPE_ISPARENT (input, id)))
     {
       if (!ctf_assert (output, parents[input_num] <= ninputs))
-	return -1;
+	return CTF_ERR;
       input = inputs[parents[input_num]];
       input_num = parents[input_num];
     }
@@ -2534,7 +2575,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
 			     CTF_DEDUP_GID (output, input_num, id));
 
   if (!ctf_assert (output, hval && td->cd_output_emission_hashes))
-    return -1;
+    return CTF_ERR;
 
   /* If this type is a conflicted tagged structure, union, or forward,
      substitute a synthetic forward instead, emitting it if need be.  Only do
@@ -2553,7 +2594,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
       ctf_set_errno (err_fp, ctf_errno (output));
       ctf_err_warn (err_fp, 0, 0, _("cannot add synthetic forward for type "
 				    "%i/%lx"), input_num, id);
-      return -1;
+      return CTF_ERR;
     default:
       return emitted_forward;
     }
@@ -2568,7 +2609,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
       ctf_dprintf ("Checking shared parent for target\n");
       if (!ctf_assert (output, (target != output)
 		       && (target->ctf_flags & LCTF_CHILD)))
-	return -1;
+	return CTF_ERR;
 
       target_id = ctf_dynhash_lookup (od->cd_output_emission_hashes, hval);
 
@@ -2582,13 +2623,14 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
 	  ctf_err_warn (err_fp, 0, ctf_errno (output),
 			_("cannot add synthetic forward for type %i/%lx"),
 			input_num, id);
-	  return ctf_set_errno (err_fp, ctf_errno (output));
+	  ctf_set_errno (err_fp, ctf_errno (output));
+	  return CTF_ERR;
 	default:
 	  return emitted_forward;
 	}
     }
   if (!ctf_assert (output, target_id))
-    return -1;
+    return CTF_ERR;
   return (ctf_id_t) (uintptr_t) target_id;
 }
 
@@ -2664,7 +2706,8 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
 	      ctf_err_warn (output, 0, err,
 			    _("cannot create per-CU CTF archive for CU %s"),
 			    ctf_link_input_name (input));
-	      return ctf_set_errno (output, err);
+	      ctf_set_errno (output, err);
+	      return -1;
 	    }
 
 	  ctf_import_unref (target, output);
@@ -2687,7 +2730,8 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
       ctf_err_warn (output, 0, ctf_errno (input),
 		    _("%s: lookup failure for type %lx"),
 		    ctf_link_input_name (real_input), type);
-      return ctf_set_errno (output, ctf_errno (input));
+      ctf_set_errno (output, ctf_errno (input));
+      return -1;
     }
 
   name = ctf_strraw (real_input, tp->ctt_name);
@@ -2765,7 +2809,8 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
 			      ctf_link_input_name (input), input_num, name,
 			      type);
 		ctf_next_destroy (i);
-		return ctf_set_errno (output, ctf_errno (target));
+		ctf_set_errno (output, ctf_errno (target));
+		return -1;
 	      }
 	  }
 	if (ctf_errno (input) != ECTF_NEXT_END)
@@ -2921,7 +2966,8 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
       ctf_err_warn (output, 0, ECTF_CORRUPT, _("%s: unknown type kind for "
 					       "input type %lx"),
 		    ctf_link_input_name (input), type);
-      return ctf_set_errno (output, ECTF_CORRUPT);
+      ctf_set_errno (output, ECTF_CORRUPT);
+      return -1;
     }
 
   if (!emission_hashed
@@ -2931,7 +2977,8 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
     {
       ctf_err_warn (output, 0, ENOMEM, _("out of memory tracking deduplicated "
 					 "global type IDs"));
-	return ctf_set_errno (output, ENOMEM);
+      ctf_set_errno (output, ENOMEM);
+      return -1;
     }
 
   if (!emission_hashed && new_type != 0)
@@ -2944,21 +2991,24 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
  oom_hash:
   ctf_err_warn (output, 0, ENOMEM, _("out of memory creating emission-tracking "
 				     "hashes"));
-  return ctf_set_errno (output, ENOMEM);
+  ctf_set_errno (output, ENOMEM);
+  return -1;
 
  err_input:
   ctf_err_warn (output, 0, ctf_errno (input),
 		_("%s (%i): while emitting deduplicated %s, error getting "
 		  "input type %lx"), ctf_link_input_name (input),
 		input_num, errtype, type);
-  return ctf_set_errno (output, ctf_errno (input));
+  ctf_set_errno (output, ctf_errno (input));
+  return -1;
  err_target:
   ctf_err_warn (output, 0, ctf_errno (target),
 		_("%s (%i): while emitting deduplicated %s, error emitting "
 		  "target type from input type %lx"),
 		ctf_link_input_name (input), input_num,
 		errtype, type);
-  return ctf_set_errno (output, ctf_errno (target));
+  ctf_set_errno (output, ctf_errno (target));
+  return -1;
 }
 
 /* Traverse the cd_emission_struct_members and emit the members of all
@@ -3051,11 +3101,13 @@ ctf_dedup_emit_struct_members (ctf_dict_t *output, ctf_dict_t **inputs,
   ctf_err_warn (output, 0, ctf_errno (err_fp),
 		_("%s (%i): error emitting members for structure type %lx"),
 		ctf_link_input_name (input_fp), input_num, err_type);
-  return ctf_set_errno (output, ctf_errno (err_fp));
+  ctf_set_errno (output, ctf_errno (err_fp));
+  return -1;
  iterr:
   ctf_err_warn (output, 0, err, _("iteration failure emitting "
 				  "structure members"));
-  return ctf_set_errno (output, err);
+  ctf_set_errno (output, err);
+  return -1;
 }
 
 /* Emit deduplicated types into the outputs.  The shared type repository is
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index 686951a9869..b5de3c76709 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -56,7 +56,10 @@ ctf_dump_append (ctf_dump_state_t *state, char *str)
   ctf_dump_item_t *cdi;
 
   if ((cdi = malloc (sizeof (struct ctf_dump_item))) == NULL)
-    return (ctf_set_errno (state->cds_fp, ENOMEM));
+    {
+      ctf_set_errno (state->cds_fp, ENOMEM);
+      return -1;
+    }
 
   cdi->cdi_item = str;
   ctf_list_append (&state->cds_items, cdi);
@@ -261,7 +264,8 @@ ctf_dump_header_strfield (ctf_dict_t *fp, ctf_dump_state_t *state,
   return 0;
 
  err:
-  return (ctf_set_errno (fp, errno));
+  ctf_set_errno (fp, errno);
+  return -1;
 }
 
 /* Dump one section-offset field from the file header into the cds_items.  */
@@ -281,7 +285,8 @@ ctf_dump_header_sectfield (ctf_dict_t *fp, ctf_dump_state_t *state,
   return 0;
 
  err:
-  return (ctf_set_errno (fp, errno));
+  ctf_set_errno (fp, errno);
+  return -1;
 }
 
 /* Dump the file header into the cds_items.  */
@@ -398,7 +403,8 @@ ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
   return 0;
  err:
   free (flagstr);
-  return (ctf_set_errno (fp, errno));
+  ctf_set_errno (fp, errno);
+  return -1;
 }
 
 /* Dump a single label into the cds_items.  */
@@ -412,7 +418,10 @@ ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
   ctf_dump_state_t *state = arg;
 
   if (asprintf (&str, "%s -> ", name) < 0)
-    return (ctf_set_errno (state->cds_fp, errno));
+    {
+      ctf_set_errno (state->cds_fp, errno);
+      return -1;
+    }
 
   if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type,
 				       CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
@@ -487,7 +496,10 @@ ctf_dump_var (const char *name, ctf_id_t type, void *arg)
   ctf_dump_state_t *state = arg;
 
   if (asprintf (&str, "%s -> ", name) < 0)
-    return (ctf_set_errno (state->cds_fp, errno));
+    {
+      ctf_set_errno (state->cds_fp, errno);
+      return -1;
+    }
 
   if ((typestr = ctf_dump_format_type (state->cds_fp, type,
 				       CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
@@ -540,7 +552,8 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
  oom:
   free (typestr);
   free (bit);
-  return (ctf_set_errno (state->cdm_fp, errno));
+  ctf_set_errno (state->cdm_fp, errno);
+  return -1;
 }
 
 /* Report the number of digits in the hexadecimal representation of a type
@@ -569,7 +582,10 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
 
   /* Indent neatly.  */
   if (asprintf (&indent, "    %*s", type_hex_digits (id), "") < 0)
-    return (ctf_set_errno (state->cds_fp, ENOMEM));
+    {
+      ctf_set_errno (state->cds_fp, ENOMEM);
+      return -1;
+    }
 
   /* Dump the type itself.  */
   if ((str = ctf_dump_format_type (state->cds_fp, id,
@@ -654,7 +670,8 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
  oom:
   free (indent);
   free (str);
-  return ctf_set_errno (state->cds_fp, ENOMEM);
+  ctf_set_errno (state->cds_fp, ENOMEM);
+  return -1;
 }
 
 /* Dump the string table into the cds_items.  */
@@ -671,7 +688,10 @@ ctf_dump_str (ctf_dict_t *fp, ctf_dump_state_t *state)
       if (asprintf (&str, "0x%lx: %s",
 		    (unsigned long) (s - fp->ctf_str[CTF_STRTAB_0].cts_strs),
 		    s) < 0)
-	return (ctf_set_errno (fp, errno));
+	{
+	  ctf_set_errno (fp, errno);
+	  return -1;
+	}
       ctf_dump_append (state, str);
       s += strlen (s) + 1;
     }
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index da687762c89..77d74ef0ea9 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -741,7 +741,6 @@ extern struct ctf_archive *ctf_arc_open_internal (const char *, int *);
 extern void ctf_arc_close_internal (struct ctf_archive *);
 extern const ctf_preamble_t *ctf_arc_bufpreamble (const ctf_sect_t *);
 extern void *ctf_set_open_errno (int *, int);
-extern unsigned long ctf_set_errno (ctf_dict_t *, int);
 extern void ctf_flip_header (ctf_header_t *);
 extern int ctf_flip (ctf_dict_t *, ctf_header_t *, unsigned char *, int);
 
diff --git a/libctf/ctf-inlines.h b/libctf/ctf-inlines.h
index 6bda68d68e6..86661348215 100644
--- a/libctf/ctf-inlines.h
+++ b/libctf/ctf-inlines.h
@@ -90,6 +90,12 @@ ctf_assert_internal (ctf_dict_t *fp, const char *file, size_t line,
   return expr;
 }
 
+static inline void
+ctf_set_errno (ctf_dict_t *fp, int err)
+{
+  fp->ctf_errno = err;
+}
+
 #ifdef	__cplusplus
 }
 #endif
diff --git a/libctf/ctf-labels.c b/libctf/ctf-labels.c
index 16b111b14df..9ac8aae6c26 100644
--- a/libctf/ctf-labels.c
+++ b/libctf/ctf-labels.c
@@ -48,12 +48,12 @@ ctf_label_topmost (ctf_dict_t *fp)
 
   if (num_labels == 0)
     {
-      (void) ctf_set_errno (fp, ECTF_NOLABELDATA);
+      ctf_set_errno (fp, ECTF_NOLABELDATA);
       return NULL;
     }
 
   if ((s = ctf_strraw (fp, (ctlp + num_labels - 1)->ctl_label)) == NULL)
-    (void) ctf_set_errno (fp, ECTF_CORRUPT);
+    ctf_set_errno (fp, ECTF_CORRUPT);
 
   return s;
 }
@@ -74,7 +74,10 @@ ctf_label_iter (ctf_dict_t *fp, ctf_label_f *func, void *arg)
     return -1;			/* errno is set for us.  */
 
   if (num_labels == 0)
-    return (ctf_set_errno (fp, ECTF_NOLABELDATA));
+    {
+      ctf_set_errno (fp, ECTF_NOLABELDATA);
+      return -1;
+    }
 
   for (i = 0; i < num_labels; i++, ctlp++)
     {
@@ -84,7 +87,8 @@ ctf_label_iter (ctf_dict_t *fp, ctf_label_f *func, void *arg)
 	  ctf_err_warn (fp, 0, ECTF_CORRUPT,
 			"failed to decode label %u with type %u",
 			ctlp->ctl_label, ctlp->ctl_type);
-	  return (ctf_set_errno (fp, ECTF_CORRUPT));
+	  ctf_set_errno (fp, ECTF_CORRUPT);
+	  return -1;
 	}
 
       linfo.ctb_type = ctlp->ctl_type;
@@ -133,8 +137,9 @@ ctf_label_info (ctf_dict_t *fp, const char *lname, ctf_lblinfo_t *linfo)
   if ((rc = ctf_label_iter (fp, label_info_cb, &cb_arg)) < 0)
     return rc;
 
-  if (rc != 1)
-    return (ctf_set_errno (fp, ECTF_NOLABEL));
+  if (rc == 1)
+    return 0;
 
-  return 0;
+  ctf_set_errno (fp, ECTF_NOLABEL);
+  return -1;
 }
diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c
index 9babec2aa37..63da718ae4b 100644
--- a/libctf/ctf-link.c
+++ b/libctf/ctf-link.c
@@ -142,7 +142,8 @@ ctf_link_add_ctf_internal (ctf_dict_t *fp, ctf_archive_t *ctf,
  oom1:
   free (filename);
  oom:
-  return ctf_set_errno (fp, ENOMEM);
+  ctf_set_errno (fp, ENOMEM);
+  return -1;
 }
 
 /* Add a file, memory buffer, or unopened file (by name) to a link.
@@ -173,12 +174,18 @@ ctf_link_add (ctf_dict_t *fp, ctf_archive_t *ctf, const char *name,
 	      void *buf _libctf_unused_, size_t n _libctf_unused_)
 {
   if (buf)
-    return (ctf_set_errno (fp, ECTF_NOTYET));
+    {
+      ctf_set_errno (fp, ECTF_NOTYET);
+      return -1;
+    }
 
   if (!((ctf && name && !buf)
 	|| (name && !buf && !ctf)
 	|| (buf && name && !ctf)))
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return -1;
+    }
 
   /* We can only lazily open files if libctf.so is in use rather than
      libctf-nobfd.so.  This is a little tricky: in shared libraries, we can use
@@ -187,21 +194,33 @@ ctf_link_add (ctf_dict_t *fp, ctf_archive_t *ctf, const char *name,
 
 #if defined (PIC)
   if (!buf && !ctf && name && !ctf_open)
-    return (ctf_set_errno (fp, ECTF_NEEDSBFD));
+    {
+      ctf_set_errno (fp, ECTF_NEEDSBFD);
+      return -1;
+    }
 #elif NOBFD
   if (!buf && !ctf && name)
-    return (ctf_set_errno (fp, ECTF_NEEDSBFD));
+    {
+      ctf_set_errno (fp, ECTF_NEEDSBFD);
+      return -1;
+    }
 #endif
 
   if (fp->ctf_link_outputs)
-    return (ctf_set_errno (fp, ECTF_LINKADDEDLATE));
+    {
+      ctf_set_errno (fp, ECTF_LINKADDEDLATE);
+      return -1;
+    }
   if (fp->ctf_link_inputs == NULL)
     fp->ctf_link_inputs = ctf_dynhash_create (ctf_hash_string,
 					      ctf_hash_eq_string, free,
 					      ctf_link_input_close);
 
   if (fp->ctf_link_inputs == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    {
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
+    }
 
   return ctf_link_add_ctf_internal (fp, ctf, NULL, name);
 }
@@ -378,7 +397,10 @@ ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
 
   /* Mappings cannot be set up if per-CU output dicts already exist.  */
   if (fp->ctf_link_outputs && ctf_dynhash_elements (fp->ctf_link_outputs) != 0)
-      return (ctf_set_errno (fp, ECTF_LINKADDEDLATE));
+    {
+      ctf_set_errno (fp, ECTF_LINKADDEDLATE);
+      return -1;
+    }
 
   if (fp->ctf_link_in_cu_mapping == NULL)
     fp->ctf_link_in_cu_mapping = ctf_dynhash_create (ctf_hash_string,
@@ -582,7 +604,10 @@ ctf_link_one_variable (ctf_dict_t *fp, ctf_dict_t *in_fp, const char *name,
 
   if (check_variable (name, per_cu_out_fp, dst_type, &dvd))
     if (ctf_add_variable (per_cu_out_fp, name, dst_type) < 0)
-      return (ctf_set_errno (fp, ctf_errno (per_cu_out_fp)));
+      {
+	ctf_set_errno (fp, ctf_errno (per_cu_out_fp));
+	return -1;
+      }
   return 0;
 }
 
@@ -915,7 +940,10 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
 	    }
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
-	return ctf_set_errno (fp, ctf_errno (inputs[i]));
+	{
+	  ctf_set_errno (fp, ctf_errno (inputs[i]));
+	  return -1;
+	}
 
       /* Next the symbols.  We integrate data symbols even though the compiler
 	 is currently doing the same, to allow the compiler to stop in
@@ -930,7 +958,10 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
 	    }
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
-	return ctf_set_errno (fp, ctf_errno (inputs[i]));
+	{
+	  ctf_set_errno (fp, ctf_errno (inputs[i]));
+	  return -1;
+	}
 
       /* Finally the function symbols.  */
 
@@ -943,7 +974,10 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
 	    }
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
-	return ctf_set_errno (fp, ctf_errno (inputs[i]));
+	{
+	  ctf_set_errno (fp, ctf_errno (inputs[i]));
+	  return -1;
+	}
     }
   return 0;
 }
@@ -1070,7 +1104,8 @@ ctf_link_deduplicating_one_symtypetab (ctf_dict_t *fp, ctf_dict_t *input,
 			_("symbol %s in input file %s found conflicting "
 			  "even when trying in per-CU dict."), name,
 			ctf_unnamed_cuname (input));
-	  return (ctf_set_errno (fp, ECTF_DUPLICATE));
+	  ctf_set_errno (fp, ECTF_DUPLICATE);
+    return -1;
 	}
     }
   if (ctf_errno (input) != ECTF_NEXT_END)
@@ -1330,7 +1365,8 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
     {
       ctf_err_warn (fp, 0, err, _("iteration error in CU-mapped deduplicating "
 				  "link"));
-      return ctf_set_errno (fp, err);
+      ctf_set_errno (fp, err);
+      return -1;
     }
 
   return 0;
@@ -1503,7 +1539,10 @@ ctf_link (ctf_dict_t *fp, int flags)
 					       ctf_dict_close);
 
   if (fp->ctf_link_outputs == NULL)
-    return ctf_set_errno (fp, ENOMEM);
+    {
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
+    }
 
   fp->ctf_flags |= LCTF_LINKING;
   ctf_link_deduplicating (fp);
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index c65849118cb..6dbc7cd70a6 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -30,7 +30,10 @@ grow_pptrtab (ctf_dict_t *fp, size_t new_len)
 
   if ((new_pptrtab = realloc (fp->ctf_pptrtab, sizeof (uint32_t)
 			      * new_len)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    {
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
+    }
 
   fp->ctf_pptrtab = new_pptrtab;
 
@@ -143,7 +146,10 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
   ctf_id_t ntype, ptype;
 
   if (name == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return CTF_ERR;
+    }
 
   for (p = name, end = name + strlen (name); *p != '\0'; p = q)
     {
@@ -292,7 +298,10 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
     }
 
   if (*p != '\0' || type == 0)
-    return (ctf_set_errno (fp, ECTF_SYNTAX));
+    {
+      ctf_set_errno (fp, ECTF_SYNTAX);
+      return CTF_ERR;
+    }
 
   return type;
 
@@ -306,13 +315,14 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
       if (fp->ctf_pptrtab_typemax < fp->ctf_typemax)
 	{
 	  if (refresh_pptrtab (fp, fp->ctf_parent) < 0)
-	    return -1;			/* errno is set for us.  */
+	    return CTF_ERR;			/* errno is set for us.  */
 	}
 
       if ((ptype = ctf_lookup_by_name_internal (fp->ctf_parent, fp,
 						name)) != CTF_ERR)
 	return ptype;
-      return (ctf_set_errno (fp, ctf_errno (fp->ctf_parent)));
+      ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
+      return CTF_ERR;
     }
 
   return CTF_ERR;
@@ -336,7 +346,7 @@ ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
 
   if ((fp = ctf_get_dict (fp, type)) == NULL)
     {
-      (void) ctf_set_errno (*fpp, ECTF_NOPARENT);
+      ctf_set_errno (*fpp, ECTF_NOPARENT);
       return NULL;
     }
 
@@ -351,7 +361,7 @@ ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
 	  *fpp = fp;
 	  return &dtd->dtd_data;
 	}
-      (void) ctf_set_errno (*fpp, ECTF_BADID);
+      ctf_set_errno (*fpp, ECTF_BADID);
       return NULL;
     }
 
@@ -364,7 +374,7 @@ ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
       return (LCTF_INDEX_TO_TYPEPTR (fp, idx));
     }
 
-  (void) ctf_set_errno (*fpp, ECTF_BADID);
+  ctf_set_errno (*fpp, ECTF_BADID);
   return NULL;
 }
 
@@ -407,10 +417,12 @@ ctf_lookup_variable (ctf_dict_t *fp, const char *name)
 
           if ((ptype = ctf_lookup_variable (fp->ctf_parent, name)) != CTF_ERR)
             return ptype;
-          return (ctf_set_errno (fp, ctf_errno (fp->ctf_parent)));
+          ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
+          return CTF_ERR;
         }
 
-      return (ctf_set_errno (fp, ECTF_NOTYPEDAT));
+      ctf_set_errno (fp, ECTF_NOTYPEDAT);
+      return CTF_ERR;
     }
 
   return ent->ctv_type;
@@ -622,13 +634,13 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
 	  break;
 	default:
 	  ctf_set_errno (fp, ECTF_SYMTAB);
-	  return (unsigned long) -1;
+	  return CTF_ERR;
 	}
     }
 
   /* Searched everything, still not found.  */
 
-  return (unsigned long) -1;
+  return CTF_ERR;
 
  try_parent:
   if (fp->ctf_parent)
@@ -636,22 +648,22 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
       unsigned long psym;
 
       if ((psym = ctf_lookup_symbol_idx (fp->ctf_parent, symname))
-          != (unsigned long) -1)
+          != CTF_ERR)
         return psym;
 
       ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
-      return (unsigned long) -1;
+      return CTF_ERR;
     }
   else
     {
       ctf_set_errno (fp, err);
-      return (unsigned long) -1;
+      return CTF_ERR;
     }
 oom:
   ctf_set_errno (fp, ENOMEM);
   ctf_err_warn (fp, 0, ENOMEM, _("cannot allocate memory for symbol "
 				 "lookup hashtab"));
-  return (unsigned long) -1;
+  return CTF_ERR;
 
 }
 
@@ -673,7 +685,10 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	{
+	  ctf_set_errno (fp, ENOMEM);
+	  return CTF_ERR;
+	}
 
       i->cu.ctn_fp = fp;
       i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next;
@@ -682,10 +697,16 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
     }
 
   if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
+    {
+      ctf_set_errno (fp, ECTF_NEXT_WRONGFUN);
+      return CTF_ERR;
+    }
 
   if (fp != i->cu.ctn_fp)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
+    {
+      ctf_set_errno (fp, ECTF_NEXT_WRONGFP);
+      return CTF_ERR;
+    }
 
   /* We intentionally use raw access, not ctf_lookup_by_symbol, to avoid
      incurring additional sorting cost for unsorted symtypetabs coming from the
@@ -701,7 +722,8 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
       if (!dynh)
 	{
 	  ctf_next_destroy (i);
-	  return (ctf_set_errno (fp, ECTF_NEXT_END));
+	  ctf_set_errno (fp, ECTF_NEXT_END);
+	  return CTF_ERR;
 	}
 
       err = ctf_dynhash_next (dynh, &i->ctn_next, &dyn_name, &dyn_value);
@@ -710,7 +732,8 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
 	{
 	  ctf_next_destroy (i);
 	  *it = NULL;
-	  return ctf_set_errno (fp, err);
+	  ctf_set_errno (fp, err);
+	  return CTF_ERR;
 	}
 
       *name = dyn_name;
@@ -786,7 +809,8 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
  end:
   ctf_next_destroy (i);
   *it = NULL;
-  return (ctf_set_errno (fp, ECTF_NEXT_END));
+  ctf_set_errno (fp, ECTF_NEXT_END);
+  return CTF_ERR;
 }
 
 /* A bsearch function for function and object index names.  */
@@ -821,7 +845,7 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 	       "indexed symtypetab\n", symidx, symname);
 
   if (symname[0] == '\0')
-    return -1;					/* errno is set for us.  */
+    return CTF_ERR;					/* errno is set for us.  */
 
   if (is_function)
     {
@@ -835,7 +859,7 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 	      == NULL)
 	    {
 	      ctf_err_warn (fp, 0, 0, _("cannot sort function symidx"));
-	      return -1;				/* errno is set for us.  */
+	      return CTF_ERR;				/* errno is set for us.  */
 	    }
 	}
       symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff);
@@ -855,7 +879,7 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 	      == NULL)
 	    {
 	      ctf_err_warn (fp, 0, 0, _("cannot sort object symidx"));
-	      return -1;				/* errno is set for us. */
+	      return CTF_ERR;				/* errno is set for us. */
 	    }
 	}
 
@@ -878,7 +902,10 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 
   /* Should be impossible, but be paranoid.  */
   if ((idx - sxlate) > (ptrdiff_t) nidx)
-    return (ctf_set_errno (fp, ECTF_CORRUPT));
+    {
+      ctf_set_errno (fp, ECTF_CORRUPT);
+      return CTF_ERR;
+    }
 
   ctf_dprintf ("Symbol %lx (%s) is of type %x\n", symidx, symname,
 	       symtypetab[*idx]);
@@ -1014,7 +1041,10 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
       return ret;
     }
   else
-    return (ctf_set_errno (fp, err));
+    {
+      ctf_set_errno (fp, err);
+      return CTF_ERR;
+    }
 }
 
 /* Given a symbol table index, return the type of the function or data object
@@ -1046,7 +1076,10 @@ ctf_func_info (ctf_dict_t *fp, unsigned long symidx, ctf_funcinfo_t *fip)
     return -1;					/* errno is set for us.  */
 
   if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
-    return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    {
+      ctf_set_errno (fp, ECTF_NOTFUNC);
+      return -1;
+    }
 
   return ctf_func_type_info (fp, type, fip);
 }
@@ -1064,7 +1097,10 @@ ctf_func_args (ctf_dict_t *fp, unsigned long symidx, uint32_t argc,
     return -1;					/* errno is set for us.  */
 
   if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
-    return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    {
+      ctf_set_errno (fp, ECTF_NOTFUNC);
+      return -1;
+    }
 
   return ctf_func_type_args (fp, type, argc, argv);
 }
diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c
index 35f635b6559..fa5f2aab732 100644
--- a/libctf/ctf-open.c
+++ b/libctf/ctf-open.c
@@ -1935,7 +1935,10 @@ ctf_parent_name_set (ctf_dict_t *fp, const char *name)
     free (fp->ctf_dynparname);
 
   if ((fp->ctf_dynparname = strdup (name)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    {
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
+    }
   fp->ctf_parname = fp->ctf_dynparname;
   return 0;
 }
@@ -1956,7 +1959,10 @@ ctf_cuname_set (ctf_dict_t *fp, const char *name)
     free (fp->ctf_dyncuname);
 
   if ((fp->ctf_dyncuname = strdup (name)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    {
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
+    }
   fp->ctf_cuname = fp->ctf_dyncuname;
   return 0;
 }
@@ -1969,10 +1975,16 @@ int
 ctf_import (ctf_dict_t *fp, ctf_dict_t *pfp)
 {
   if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return -1;
+    }
 
   if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel)
-    return (ctf_set_errno (fp, ECTF_DMODEL));
+    {
+      ctf_set_errno (fp, ECTF_DMODEL);
+      return -1;
+    }
 
   if (fp->ctf_parent && !fp->ctf_parent_unreffed)
     ctf_dict_close (fp->ctf_parent);
@@ -2008,10 +2020,16 @@ int
 ctf_import_unref (ctf_dict_t *fp, ctf_dict_t *pfp)
 {
   if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
-    return (ctf_set_errno (fp, EINVAL));
+    {
+      ctf_set_errno (fp, EINVAL);
+      return -1;
+    }
 
   if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel)
-    return (ctf_set_errno (fp, ECTF_DMODEL));
+    {
+      ctf_set_errno (fp, ECTF_DMODEL);
+      return -1;
+    }
 
   if (fp->ctf_parent && !fp->ctf_parent_unreffed)
     ctf_dict_close (fp->ctf_parent);
@@ -2052,7 +2070,8 @@ ctf_setmodel (ctf_dict_t *fp, int model)
 	}
     }
 
-  return (ctf_set_errno (fp, EINVAL));
+  ctf_set_errno (fp, EINVAL);
+  return -1;
 }
 
 /* Return the data model constant for the CTF dict.  */
diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
index ba830a2b095..2d3756d31fd 100644
--- a/libctf/ctf-serialize.c
+++ b/libctf/ctf-serialize.c
@@ -123,7 +123,10 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 
       if ((linker_known = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
 					      NULL, NULL)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	{
+	  ctf_set_errno (fp, ENOMEM);
+	  return -1;
+	}
 
       while ((err = ctf_dynhash_cnext (symfp->ctf_dynsyms, &i,
 				       &name, &ctf_sym)) == 0)
@@ -147,7 +150,8 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 	  if (ctf_dynhash_cinsert (linker_known, name, ctf_sym) < 0)
 	    {
 	      ctf_dynhash_destroy (linker_known);
-	      return (ctf_set_errno (fp, ENOMEM));
+	      ctf_set_errno (fp, ENOMEM);
+	      return -1;
 	    }
 	}
       if (err != ECTF_NEXT_END)
@@ -155,7 +159,8 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols during "
 				  "serialization"));
 	  ctf_dynhash_destroy (linker_known);
-	  return (ctf_set_errno (fp, err));
+	  ctf_set_errno (fp, err);
+	  return -1;
 	}
     }
 
@@ -219,7 +224,8 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
       ctf_err_warn (fp, 0, err, _("iterating over CTF symtypetab during "
 				  "serialization"));
       ctf_dynhash_destroy (linker_known);
-      return (ctf_set_errno (fp, err));
+      ctf_set_errno (fp, err);
+      return -1;
     }
 
   if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
@@ -236,7 +242,8 @@ symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols "
 				      "during CTF serialization"));
 	  ctf_dynhash_destroy (linker_known);
-	  return (ctf_set_errno (fp, err));
+	  ctf_set_errno (fp, err);
+	  return -1;
 	}
     }
 
@@ -970,7 +977,10 @@ ctf_serialize (ctf_dict_t *fp)
   memset (&symstate, 0, sizeof (emit_symtypetab_state_t));
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    {
+      ctf_set_errno (fp, ECTF_RDONLY);
+      return -1;
+    }
 
   /* Update required?  */
   if (!(fp->ctf_flags & LCTF_DIRTY))
@@ -1026,7 +1036,10 @@ ctf_serialize (ctf_dict_t *fp)
   buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
 
   if ((buf = malloc (buf_size)) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+    {
+      ctf_set_errno (fp, EAGAIN);
+      return -1;
+    }
 
   memcpy (buf, &hdr, sizeof (ctf_header_t));
   t = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_objtoff;
@@ -1106,7 +1119,8 @@ ctf_serialize (ctf_dict_t *fp)
 				       1, &err)) == NULL)
     {
       free (buf);
-      return (ctf_set_errno (fp, err));
+      ctf_set_errno (fp, err);
+      return -1;
     }
 
   (void) ctf_setmodel (nfp, ctf_getmodel (fp));
@@ -1221,7 +1235,8 @@ ctf_serialize (ctf_dict_t *fp)
 
 oom:
   free (buf);
-  return (ctf_set_errno (fp, EAGAIN));
+  ctf_set_errno (fp, EAGAIN);
+  return -1;
 err:
   free (buf);
   return -1;					/* errno is set for us.  */
@@ -1248,7 +1263,10 @@ ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
   while (resid != 0)
     {
       if ((len = gzwrite (fd, buf, resid)) <= 0)
-	return (ctf_set_errno (fp, errno));
+	{
+	  ctf_set_errno (fp, errno);
+	  return -1;
+	}
       resid -= len;
       buf += len;
     }
@@ -1258,7 +1276,10 @@ ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
   while (resid != 0)
     {
       if ((len = gzwrite (fd, buf, resid)) <= 0)
-	return (ctf_set_errno (fp, errno));
+	{
+	  ctf_set_errno (fp, errno);
+	  return -1;
+	}
       resid -= len;
       buf += len;
     }
@@ -1378,7 +1399,8 @@ ctf_compress_write (ctf_dict_t *fp, int fd)
     {
       if ((len = write (fd, bp, buf_len)) < 0)
 	{
-	  err = ctf_set_errno (fp, errno);
+	  ctf_set_errno (fp, errno);
+	  err = CTF_ERR;
 	  ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
 	  goto ret;
 	}
@@ -1412,7 +1434,8 @@ ctf_write (ctf_dict_t *fp, int fd)
     {
       if ((len = write (fd, bp, buf_len)) < 0)
 	{
-	  err = ctf_set_errno (fp, errno);
+	  ctf_set_errno (fp, errno);
+	  err = CTF_ERR;
 	  ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
 	  goto ret;
 	}
diff --git a/libctf/ctf-string.c b/libctf/ctf-string.c
index 911e94700f1..ec8532fc47c 100644
--- a/libctf/ctf-string.c
+++ b/libctf/ctf-string.c
@@ -298,7 +298,10 @@ ctf_str_move_pending (ctf_dict_t *fp, uint32_t *new_ref, ptrdiff_t bytes)
     return 0;
 
   if (ctf_dynset_insert (fp->ctf_str_pending_ref, (void *) new_ref) < 0)
-    return (ctf_set_errno (fp, ENOMEM));
+    {
+      ctf_set_errno (fp, ENOMEM);
+      return -1;
+    }
 
   ctf_dynset_remove (fp->ctf_str_pending_ref,
 		     (void *) ((signed char *) new_ref - bytes));
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index c20ff825d9a..224a79c872b 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -119,7 +119,10 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 	return -1;			/* errno is set for us.  */
 
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (ofp, ENOMEM);
+	{
+	  ctf_set_errno (ofp, ENOMEM);
+	  return -1;
+	}
       i->cu.ctn_fp = ofp;
       i->ctn_tp = tp;
 
@@ -129,7 +132,8 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
       if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
 	{
 	  ctf_next_destroy (i);
-	  return (ctf_set_errno (ofp, ECTF_NOTSOU));
+	  ctf_set_errno (ofp, ECTF_NOTSOU);
+	  return -1;
 	}
 
       if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
@@ -150,14 +154,23 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
     }
 
   if ((void (*) (void)) ctf_member_next != i->ctn_iter_fun)
-    return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN));
+    {
+      ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN);
+      return -1;
+    }
 
   if (ofp != i->cu.ctn_fp)
-    return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFP));
+    {
+      ctf_set_errno (ofp, ECTF_NEXT_WRONGFP);
+      return -1;
+    }
 
   /* Resolve to the native dict of this type.  */
   if ((fp = ctf_get_dict (ofp, type)) == NULL)
-    return (ctf_set_errno (ofp, ECTF_NOPARENT));
+    {
+      ctf_set_errno (ofp, ECTF_NOPARENT);
+      return -1;
+    }
 
   max_vlen = LCTF_INFO_VLEN (fp, i->ctn_tp->ctt_info);
 
@@ -177,7 +190,10 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 
       if (ctf_struct_member (fp, &memb, i->ctn_tp, i->u.ctn_vlen, i->ctn_size,
 			     i->ctn_n) < 0)
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+	{
+	  ctf_set_errno (ofp, ctf_errno (fp));
+	  return -1;
+	}
 
       membname = ctf_strptr (fp, memb.ctlm_name);
 
@@ -221,7 +237,10 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 	}
 
       if (!ctf_assert (fp, (i->ctn_next == NULL)))
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+	{
+	  ctf_set_errno (ofp, ctf_errno (fp));
+	  return -1;
+	}
 
       i->ctn_type = 0;
       /* This sub-struct has ended: on to the next real member.  */
@@ -233,7 +252,8 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
  end_iter:
   ctf_next_destroy (i);
   *it = NULL;
-  return ctf_set_errno (ofp, ECTF_NEXT_END);
+  ctf_set_errno (ofp, ECTF_NEXT_END);
+  return -1;
 }
 
 /* Iterate over the members of an ENUM.  We pass the string name and associated
@@ -426,7 +446,10 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	{
+	  ctf_set_errno (fp, ENOMEM);
+	  return CTF_ERR;
+	}
 
       i->cu.ctn_fp = fp;
       i->ctn_type = 1;
@@ -435,10 +458,16 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
     }
 
   if ((void (*) (void)) ctf_type_next != i->ctn_iter_fun)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
+    {
+      ctf_set_errno (fp, ECTF_NEXT_WRONGFUN);
+      return CTF_ERR;
+    }
 
   if (fp != i->cu.ctn_fp)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
+    {
+      ctf_set_errno (fp, ECTF_NEXT_WRONGFP);
+      return CTF_ERR;
+    }
 
   while (i->ctn_type <= fp->ctf_typemax)
     {
@@ -456,7 +485,8 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
     }
   ctf_next_destroy (i);
   *it = NULL;
-  return ctf_set_errno (fp, ECTF_NEXT_END);
+  ctf_set_errno (fp, ECTF_NEXT_END);
+  return CTF_ERR;
 }
 
 /* Iterate over every variable in the given CTF dict, in arbitrary order.
@@ -494,12 +524,18 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
   ctf_next_t *i = *it;
 
   if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parent == NULL))
-    return (ctf_set_errno (fp, ECTF_NOPARENT));
+    {
+      ctf_set_errno (fp, ECTF_NOPARENT);
+      return CTF_ERR;
+    }
 
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	{
+	  ctf_set_errno (fp, ENOMEM);
+	  return CTF_ERR;
+	}
 
       i->cu.ctn_fp = fp;
       i->ctn_iter_fun = (void (*) (void)) ctf_variable_next;
@@ -509,10 +545,16 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
     }
 
   if ((void (*) (void)) ctf_variable_next != i->ctn_iter_fun)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
+    {
+      ctf_set_errno (fp, ECTF_NEXT_WRONGFUN);
+      return CTF_ERR;
+    }
 
   if (fp != i->cu.ctn_fp)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
+    {
+      ctf_set_errno (fp, ECTF_NEXT_WRONGFP);
+      return CTF_ERR;
+    }
 
   if (!(fp->ctf_flags & LCTF_RDWR))
     {
@@ -538,7 +580,8 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
  end_iter:
   ctf_next_destroy (i);
   *it = NULL;
-  return ctf_set_errno (fp, ECTF_NEXT_END);
+  ctf_set_errno (fp, ECTF_NEXT_END);
+  return CTF_ERR;
 }
 
 /* Follow a given type through the graph for TYPEDEF, VOLATILE, CONST, and
@@ -560,7 +603,10 @@ ctf_type_resolve (ctf_dict_t *fp, ctf_id_t type)
   const ctf_type_t *tp;
 
   if (type == 0)
-    return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE));
+    {
+      ctf_set_errno (ofp, ECTF_NONREPRESENTABLE);
+      return CTF_ERR;
+    }
 
   while ((tp = ctf_lookup_by_id (&fp, type)) != NULL)
     {
@@ -575,18 +621,21 @@ ctf_type_resolve (ctf_dict_t *fp, ctf_id_t type)
 	    {
 	      ctf_err_warn (ofp, 0, ECTF_CORRUPT, _("type %lx cycle detected"),
 			    otype);
-	      return (ctf_set_errno (ofp, ECTF_CORRUPT));
+	      ctf_set_errno (ofp, ECTF_CORRUPT);
+	      return CTF_ERR;
 	    }
 	  prev = type;
 	  type = tp->ctt_type;
 	  break;
 	case CTF_K_UNKNOWN:
-	  return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE));
+	  ctf_set_errno (ofp, ECTF_NONREPRESENTABLE);
+	  return CTF_ERR;
 	default:
 	  return type;
 	}
       if (type == 0)
-	return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE));
+	ctf_set_errno (ofp, ECTF_NONREPRESENTABLE);
+	return CTF_ERR;
     }
 
   return CTF_ERR;		/* errno is set for us.  */
@@ -612,7 +661,10 @@ ctf_type_resolve_unsliced (ctf_dict_t *fp, ctf_id_t type)
       ctf_id_t ret;
 
       if ((ret = ctf_type_reference (fp, type)) == CTF_ERR)
-	return (ctf_set_errno (ofp, ctf_errno (fp)));
+	{
+	  ctf_set_errno (ofp, ctf_errno (fp));
+	  return CTF_ERR;
+	}
       return ret;
     }
   return type;
@@ -836,7 +888,7 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
     }
 
   if (cd.cd_enomem)
-    (void) ctf_set_errno (fp, ENOMEM);
+    ctf_set_errno (fp, ENOMEM);
 
   buf = ctf_decl_buf (&cd);
 
@@ -854,14 +906,14 @@ ctf_type_lname (ctf_dict_t *fp, ctf_id_t type, char *buf, size_t len)
   size_t slen;
 
   if (str == NULL)
-    return CTF_ERR;			/* errno is set for us.  */
+    return -1;			/* errno is set for us.  */
 
   slen = strlen (str);
   snprintf (buf, len, "%s", str);
   free (str);
 
   if (slen >= len)
-    (void) ctf_set_errno (fp, ECTF_NAMELEN);
+    ctf_set_errno (fp, ECTF_NAMELEN);
 
   return slen;
 }
@@ -956,7 +1008,8 @@ ctf_type_size (ctf_dict_t *fp, ctf_id_t type)
 
     case CTF_K_FORWARD:
       /* Forwards do not have a meaningful size.  */
-      return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
+      ctf_set_errno (ofp, ECTF_INCOMPLETE);
+      return -1;
 
     default: /* including slices of enums, etc */
       return (ctf_get_ctt_size (fp, tp, NULL, NULL));
@@ -1039,7 +1092,8 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
 
     case CTF_K_FORWARD:
       /* Forwards do not have a meaningful alignment.  */
-      return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
+      ctf_set_errno (ofp, ECTF_INCOMPLETE);
+      return -1;
 
     default:  /* including slices of enums, etc */
       return (ctf_get_ctt_size (fp, tp, NULL, NULL));
@@ -1139,7 +1193,8 @@ ctf_type_reference (ctf_dict_t *fp, ctf_id_t type)
 	return sp->cts_type;
       }
     default:
-      return (ctf_set_errno (ofp, ECTF_NOTREF));
+      ctf_set_errno (ofp, ECTF_NOTREF);
+      return CTF_ERR;
     }
 }
 
@@ -1164,15 +1219,22 @@ ctf_type_pointer (ctf_dict_t *fp, ctf_id_t type)
     return (LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD)));
 
   if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
-    return (ctf_set_errno (ofp, ECTF_NOTYPE));
+    {
+      ctf_set_errno (ofp, ECTF_NOTYPE);
+      return CTF_ERR;
+    }
 
   if (ctf_lookup_by_id (&fp, type) == NULL)
-    return (ctf_set_errno (ofp, ECTF_NOTYPE));
+    {
+      ctf_set_errno (ofp, ECTF_NOTYPE);
+      return CTF_ERR;
+    }
 
   if ((ntype = fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, type)]) != 0)
     return (LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD)));
 
-  return (ctf_set_errno (ofp, ECTF_NOTYPE));
+  ctf_set_errno (ofp, ECTF_NOTYPE);
+  return CTF_ERR;
 }
 
 /* Return the encoding for the specified INTEGER, FLOAT, or ENUM.  */
@@ -1235,7 +1297,8 @@ ctf_type_encoding (ctf_dict_t *fp, ctf_id_t type, ctf_encoding_t *ep)
 	break;
       }
     default:
-      return (ctf_set_errno (ofp, ECTF_NOTINTFP));
+      ctf_set_errno (ofp, ECTF_NOTINTFP);
+      return -1;
     }
 
   return 0;
@@ -1370,7 +1433,10 @@ ctf_member_count (ctf_dict_t *fp, ctf_id_t type)
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION && kind != CTF_K_ENUM)
-    return (ctf_set_errno (ofp, ECTF_NOTSUE));
+    {
+      ctf_set_errno (ofp, ECTF_NOTSUE);
+      return -1;
+    }
 
   return LCTF_INFO_VLEN (fp, tp->ctt_info);
 }
@@ -1398,7 +1464,10 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
-    return (ctf_set_errno (ofp, ECTF_NOTSOU));
+    {
+      ctf_set_errno (ofp, ECTF_NOTSOU);
+      return -1;
+    }
 
   n = LCTF_INFO_VLEN (fp, tp->ctt_info);
   if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
@@ -1418,7 +1487,10 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
       const char *membname;
 
       if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0)
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+	{
+	  ctf_set_errno (ofp, ctf_errno (fp));
+	  return -1;
+	}
 
       membname = ctf_strptr (fp, memb.ctlm_name);
 
@@ -1439,7 +1511,8 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
 	}
     }
 
-  return (ctf_set_errno (ofp, ECTF_NOMEMBNAM));
+  ctf_set_errno (ofp, ECTF_NOMEMBNAM);
+  return -1;
 }
 
 /* Return the array type, index, and size information for the specified ARRAY.  */
@@ -1457,7 +1530,10 @@ ctf_array_info (ctf_dict_t *fp, ctf_id_t type, ctf_arinfo_t *arp)
     return -1;			/* errno is set for us.  */
 
   if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ARRAY)
-    return (ctf_set_errno (ofp, ECTF_NOTARRAY));
+    {
+      ctf_set_errno (ofp, ECTF_NOTARRAY);
+      return -1;
+    }
 
   if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
     ap = (const ctf_array_t *) dtd->dtd_vlen;
@@ -1584,7 +1660,10 @@ ctf_func_type_info (ctf_dict_t *fp, ctf_id_t type, ctf_funcinfo_t *fip)
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
   if (kind != CTF_K_FUNCTION)
-    return (ctf_set_errno (ofp, ECTF_NOTFUNC));
+    {
+      ctf_set_errno (ofp, ECTF_NOTFUNC);
+      return -1;
+    }
 
   fip->ctc_return = tp->ctt_type;
   fip->ctc_flags = 0;
@@ -1697,7 +1776,10 @@ ctf_type_rvisit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func,
       ctf_lmember_t memb;
 
       if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0)
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+	{
+	  ctf_set_errno (ofp, ctf_errno (fp));
+	  return -1;
+	}
 
       if ((rc = ctf_type_rvisit (fp, memb.ctlm_type,
 				 func, arg, ctf_strptr (fp, memb.ctlm_name),
diff --git a/libctf/ctf-util.c b/libctf/ctf-util.c
index 9f83ab9ab0b..e0d412df390 100644
--- a/libctf/ctf-util.c
+++ b/libctf/ctf-util.c
@@ -255,16 +255,6 @@ ctf_set_open_errno (int *errp, int error)
   return NULL;
 }
 
-/* Store the specified error code into the CTF dict, and then return CTF_ERR /
-   -1 for the benefit of the caller. */
-
-unsigned long
-ctf_set_errno (ctf_dict_t *fp, int err)
-{
-  fp->ctf_errno = err;
-  return CTF_ERR;
-}
-
 /* Create a ctf_next_t.  */
 
 ctf_next_t *
-- 
2.25.1


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

* Re: [PATCH v5] libctf: Sanitize error types for PR 30836
  2023-10-05  8:39                                   ` [PATCH v5] libctf: Sanitize error types for PR 30836 Torbjörn SVENSSON
@ 2023-10-09 10:27                                     ` Nick Alcock
  2023-10-09 14:44                                       ` [PATCH v6] " Torbjörn SVENSSON
  0 siblings, 1 reply; 41+ messages in thread
From: Nick Alcock @ 2023-10-09 10:27 UTC (permalink / raw)
  To: Torbjörn SVENSSON; +Cc: binutils, nick.alcock, amodra, Yvan ROUX

On 5 Oct 2023, Torbjörn SVENSSON verbalised:

> v1 -> v2:
> Changed all functions with signed interger return type to return -1 based on
> comment from Alan.

(integer)

> v2 -> v3:
> Added ctf_set_errno_signed function to return a signed -1 value based on
> comment from Nick.
>
> v3 -> v4:
> - Moved ctf_set_errno_signed function to ctf-inlines.h, renamed it to
> ctf_set_int_errno and converted it to an inline function.
> - Moved ctf_set_errno function to ctf-inlines.h, renamed it to
> ctf_set_type_errno, changed return type to ctf_id_t and converted it to an
> inline function.
> - Updated the changelog entry in the commit message. Is this list really
> required? I don't think it give much information in this patch and 'git log'
> have mixed commits (some have the entry while others don't).
>
> v4 -> v5:
> Updated in accordance with comments from Nick.
> - Changed return type to void for ctf_set_errno.
> - Inline the return on every call to ctf_set_errno.
> - Merged ctf_set_int_errno and ctf_set_type_errno into ctf_set_errno.
> - Droped log entry as it's too many places with this change to make it
>   readable.
> - Corrected a few places where -1 was returned where it should have been
>   CTF_ERR.
>
>
> @Nick: Can you please try this is in your test bench and let me know if it's
> ok for trunk?

... I don't understand why we even have a ctf_set_errno any more. It
does nothing that fp->ctf_errno = FOO doesn't. (Is it just to keep the
commit size down? If so, that seems sensible: either of us can follow it
up with a patch removing ctf_set_errno entirely as redundant.)


Alternatively -- and I promise I'll stop constantly changing my mind in
a moment! it's just this patch seems likely to be pervasive enough that
I'd like to get it right first time -- since nearly all functions in
ctf-api.h return either ctf_id_t or int, we could just do what you did
in the *previous* patch and have two functions for those:

ctf_id_t ctf_set_typed_errno()

for functions returning ctf_id_t, and

int ctf_set_errno()

for functions returning int. The original problem, those few functions
that return other types, would still need to do things "by hand",
probably by setting fp->ctf_errno before returning.

I *think* that would work for all callers and let people just compare
with CTF_ERR for ctf_id_t and unsigned types and with < 0 for all the
others, like they're suposed to be.

That way about half the call sites could stay unchanged, most of the
rest only need one a _typed_ added, and hopefully it's easier to grasp?
plus there is less need to introduce new { ... } just for the sake of
setting the errno value.

We still have a potential problem with functions returning unsigned
types that might be wider than ctf_id_t, since CTF_ERR isn't suitable to
compare against to detect errors for those; thankfully the only one of
those is ctf_archive_count, which cannot return errors :)

Again, really sorry I keep chopping and changing like this, but every
time you do something I think of a possible better way. (Unless I've
missed something, which I probably have.)

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

* [PATCH v6] libctf: Sanitize error types for PR 30836
  2023-10-09 10:27                                     ` Nick Alcock
@ 2023-10-09 14:44                                       ` Torbjörn SVENSSON
  2023-10-09 15:11                                         ` [PATCH v7] " Torbjörn SVENSSON
  0 siblings, 1 reply; 41+ messages in thread
From: Torbjörn SVENSSON @ 2023-10-09 14:44 UTC (permalink / raw)
  To: binutils, nick.alcock; +Cc: amodra, Torbjörn SVENSSON, Yvan ROUX

v1 -> v2:
Changed all functions with signed integer return type to return -1 based on
comment from Alan.

v2 -> v3:
Added ctf_set_errno_signed function to return a signed -1 value based on
comment from Nick.

v3 -> v4:
- Moved ctf_set_errno_signed function to ctf-inlines.h, renamed it to
ctf_set_int_errno and converted it to an inline function.
- Moved ctf_set_errno function to ctf-inlines.h, renamed it to
ctf_set_type_errno, changed return type to ctf_id_t and converted it to an
inline function.
- Updated the changelog entry in the commit message. Is this list really
required? I don't think it give much information in this patch and 'git log'
have mixed commits (some have the entry while others don't).

v4 -> v5:
Updated in accordance with comments from Nick.
- Changed return type to void for ctf_set_errno.
- Inline the return on every call to ctf_set_errno.
- Merged ctf_set_int_errno and ctf_set_type_errno into ctf_set_errno.
- Droped log entry as it's too many places with this change to make it
  readable.
- Corrected a few places where -1 was returned where it should have been
  CTF_ERR.

v4 -> v6:
Updated in accordance with comments from Nick.
Patch is now mostly v4 again with additions:
- Renamed ctf_set_type_errno to ctf_set_typed_errno.
- Renamed ctf_set_int_errno to ctf_set_errno.
- Droped log entry as it's too many places with this change to make it
  readable.
- Corrected a few places where -1 was returned where it should have been
  CTF_ERR.



@Nick: Can you please try this is in your test bench and let me know if it's
ok for trunk?


--

Made sure there is no implicit conversion between signed and unsigned
return value for functions setting the ctf_errno value.
An example of the problem is that in ctf_member_next, the "offset" value
is either 0L or (ctf_id_t)-1L, but it should have been 0L or -1L.
The issue was discovered while building a 64 bit ld binary to be
executed on the Windows platform.
Example object file that demonstrates the issue is attached in the PR.

Signed-off-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
Co-Authored-By: Yvan ROUX <yvan.roux@foss.st.com>
---
 libctf/ctf-create.c    | 97 ++++++++++++++++++++----------------------
 libctf/ctf-dedup.c     | 37 ++++++++--------
 libctf/ctf-dump.c      | 20 ++++-----
 libctf/ctf-impl.h      |  1 -
 libctf/ctf-inlines.h   | 17 ++++++++
 libctf/ctf-labels.c    |  4 +-
 libctf/ctf-link.c      | 37 +++++++---------
 libctf/ctf-lookup.c    | 74 ++++++++++++++++----------------
 libctf/ctf-serialize.c |  6 +--
 libctf/ctf-string.c    |  2 +-
 libctf/ctf-subr.c      | 10 ++---
 libctf/ctf-types.c     | 69 +++++++++++++++---------------
 libctf/ctf-util.c      | 10 -----
 13 files changed, 188 insertions(+), 196 deletions(-)

diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 6b342dc64a2..d2b21e50eaf 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -225,10 +225,7 @@ ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
   const char *name;
   if (ctf_dynhash_insert (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type,
 			  dtd) < 0)
-    {
-      ctf_set_errno (fp, ENOMEM);
-      return -1;
-    }
+    return ctf_set_errno (fp, ENOMEM);
 
   if (flag == CTF_ADD_ROOT && dtd->dtd_data.ctt_name
       && (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL)
@@ -239,8 +236,7 @@ ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
 	{
 	  ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t)
 			      dtd->dtd_type);
-	  ctf_set_errno (fp, ENOMEM);
-	  return -1;
+	  return ctf_set_errno (fp, ENOMEM);
 	}
     }
   ctf_list_append (&fp->ctf_dtdefs, dtd);
@@ -329,10 +325,7 @@ int
 ctf_dvd_insert (ctf_dict_t *fp, ctf_dvdef_t *dvd)
 {
   if (ctf_dynhash_insert (fp->ctf_dvhash, dvd->dvd_name, dvd) < 0)
-    {
-      ctf_set_errno (fp, ENOMEM);
-      return -1;
-    }
+    return ctf_set_errno (fp, ENOMEM);
   ctf_list_append (&fp->ctf_dvdefs, dvd);
   return 0;
 }
@@ -453,23 +446,23 @@ ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
   ctf_id_t type;
 
   if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_typed_errno (fp, ECTF_RDONLY));
 
   if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) >= CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, ECTF_FULL));
+    return (ctf_set_typed_errno (fp, ECTF_FULL));
 
   if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) == (CTF_MAX_PTYPE - 1))
-    return (ctf_set_errno (fp, ECTF_FULL));
+    return (ctf_set_typed_errno (fp, ECTF_FULL));
 
   /* Make sure ptrtab always grows to be big enough for all types.  */
   if (ctf_grow_ptrtab (fp) < 0)
       return CTF_ERR;				/* errno is set for us. */
 
   if ((dtd = calloc (1, sizeof (ctf_dtdef_t))) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+    return (ctf_set_typed_errno (fp, EAGAIN));
 
   dtd->dtd_vlen_alloc = vlen;
   if (vlen > 0)
@@ -499,7 +492,7 @@ ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
   return type;
 
  oom:
-  ctf_set_errno (fp, EAGAIN);
+  ctf_set_typed_errno (fp, EAGAIN);
  err:
   free (dtd->dtd_vlen);
   free (dtd);
@@ -532,13 +525,13 @@ ctf_add_encoded (ctf_dict_t *fp, uint32_t flag,
   uint32_t encoding;
 
   if (ep == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (name == NULL || name[0] == '\0')
-    return (ctf_set_errno (fp, ECTF_NONAME));
+    return (ctf_set_typed_errno (fp, ECTF_NONAME));
 
   if (!ctf_assert (fp, kind == CTF_K_INTEGER || kind == CTF_K_FLOAT))
-    return -1;					/* errno is set for us.  */
+    return CTF_ERR;					/* errno is set for us.  */
 
   if ((type = ctf_add_generic (fp, flag, name, kind, sizeof (uint32_t),
 			       &dtd)) == CTF_ERR)
@@ -570,7 +563,7 @@ ctf_add_reftype (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref, uint32_t kind)
   int child = fp->ctf_flags & LCTF_CHILD;
 
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (ref != 0 && ctf_lookup_by_id (&tmp, ref) == NULL)
     return CTF_ERR;		/* errno is set for us.  */
@@ -613,13 +606,13 @@ ctf_add_slice (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref,
   ctf_dict_t *tmp = fp;
 
   if (ep == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if ((ep->cte_bits > 255) || (ep->cte_offset > 255))
-    return (ctf_set_errno (fp, ECTF_SLICEOVERFLOW));
+    return (ctf_set_typed_errno (fp, ECTF_SLICEOVERFLOW));
 
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (ref != 0 && ((tp = ctf_lookup_by_id (&tmp, ref)) == NULL))
     return CTF_ERR;		/* errno is set for us.  */
@@ -634,7 +627,7 @@ ctf_add_slice (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref,
   if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) &&
       (kind != CTF_K_ENUM)
       && (ref != 0))
-    return (ctf_set_errno (fp, ECTF_NOTINTFP));
+    return (ctf_set_typed_errno (fp, ECTF_NOTINTFP));
 
   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_SLICE,
 			       sizeof (ctf_slice_t), &dtd)) == CTF_ERR)
@@ -682,7 +675,7 @@ ctf_add_array (ctf_dict_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
   ctf_dict_t *tmp = fp;
 
   if (arp == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (arp->ctr_contents != 0
       && ctf_lookup_by_id (&tmp, arp->ctr_contents) == NULL)
@@ -697,7 +690,7 @@ ctf_add_array (ctf_dict_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
       ctf_err_warn (fp, 1, ECTF_INCOMPLETE,
 		    _("ctf_add_array: index type %lx is incomplete"),
 		    arp->ctr_contents);
-      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+      return (ctf_set_typed_errno (fp, ECTF_INCOMPLETE));
     }
 
   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_ARRAY,
@@ -751,11 +744,11 @@ ctf_add_function (ctf_dict_t *fp, uint32_t flag,
   size_t i;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_typed_errno (fp, ECTF_RDONLY));
 
   if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0
       || (ctc->ctc_argc != 0 && argv == NULL))
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   vlen = ctc->ctc_argc;
   if (ctc->ctc_flags & CTF_FUNC_VARARG)
@@ -766,7 +759,7 @@ ctf_add_function (ctf_dict_t *fp, uint32_t flag,
     return CTF_ERR;				/* errno is set for us.  */
 
   if (vlen > CTF_MAX_VLEN)
-    return (ctf_set_errno (fp, EOVERFLOW));
+    return (ctf_set_typed_errno (fp, EOVERFLOW));
 
   /* One word extra allocated for padding for 4-byte alignment if need be.
      Not reflected in vlen: we don't want to copy anything into it, and
@@ -818,7 +811,7 @@ ctf_add_struct_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (dtd->dtd_vlen_alloc == 0)
     {
       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_typed_errno (fp, ENOMEM));
       dtd->dtd_vlen_alloc = initial_vlen;
     }
 
@@ -858,7 +851,7 @@ ctf_add_union_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (dtd->dtd_vlen_alloc == 0)
     {
       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_typed_errno (fp, ENOMEM));
       dtd->dtd_vlen_alloc = initial_vlen;
     }
 
@@ -897,7 +890,7 @@ ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
   if (dtd->dtd_vlen_alloc == 0)
     {
       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_typed_errno (fp, ENOMEM));
       dtd->dtd_vlen_alloc = initial_vlen;
     }
 
@@ -925,7 +918,7 @@ ctf_add_enum_encoded (ctf_dict_t *fp, uint32_t flag, const char *name,
     {
       if ((ctf_type_kind (fp, type) != CTF_K_FORWARD) &&
 	  (ctf_type_kind_unsliced (fp, type) != CTF_K_ENUM))
-	return (ctf_set_errno (fp, ECTF_NOTINTFP));
+	return (ctf_set_typed_errno (fp, ECTF_NOTINTFP));
     }
   else if ((type = ctf_add_enum (fp, flag, name)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
@@ -943,10 +936,10 @@ ctf_add_forward (ctf_dict_t *fp, uint32_t flag, const char *name,
   ctf_id_t type = 0;
 
   if (!ctf_forwardable_kind (kind))
-    return (ctf_set_errno (fp, ECTF_NOTSUE));
+    return (ctf_set_typed_errno (fp, ECTF_NOTSUE));
 
   if (name == NULL || name[0] == '\0')
-    return (ctf_set_errno (fp, ECTF_NONAME));
+    return (ctf_set_typed_errno (fp, ECTF_NONAME));
 
   /* If the type is already defined or exists as a forward tag, just
      return the ctf_id_t of the existing definition.  */
@@ -985,7 +978,7 @@ ctf_add_unknown (ctf_dict_t *fp, uint32_t flag, const char *name)
 			_("ctf_add_unknown: cannot add unknown type "
 			  "named %s: type of this name already defined"),
 			name ? name : _("(unnamed type)"));
-	  return (ctf_set_errno (fp, ECTF_CONFLICT));
+	  return (ctf_set_typed_errno (fp, ECTF_CONFLICT));
 	}
     }
 
@@ -1007,10 +1000,10 @@ ctf_add_typedef (ctf_dict_t *fp, uint32_t flag, const char *name,
   ctf_dict_t *tmp = fp;
 
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (name == NULL || name[0] == '\0')
-    return (ctf_set_errno (fp, ECTF_NONAME));
+    return (ctf_set_typed_errno (fp, ECTF_NONAME));
 
   if (ref != 0 && ctf_lookup_by_id (&tmp, ref) == NULL)
     return CTF_ERR;		/* errno is set for us.  */
@@ -1575,14 +1568,14 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
   ctf_id_t orig_src_type = src_type;
 
   if (!(dst_fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (dst_fp, ECTF_RDONLY));
+    return (ctf_set_typed_errno (dst_fp, ECTF_RDONLY));
 
   if ((src_tp = ctf_lookup_by_id (&src_fp, src_type)) == NULL)
-    return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+    return (ctf_set_typed_errno (dst_fp, ctf_errno (src_fp)));
 
   if ((ctf_type_resolve (src_fp, src_type) == CTF_ERR)
       && (ctf_errno (src_fp) == ECTF_NONREPRESENTABLE))
-    return (ctf_set_errno (dst_fp, ECTF_NONREPRESENTABLE));
+    return (ctf_set_typed_errno (dst_fp, ECTF_NONREPRESENTABLE));
 
   name = ctf_strptr (src_fp, src_tp->ctt_name);
   kind = LCTF_INFO_KIND (src_fp, src_tp->ctt_info);
@@ -1661,7 +1654,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 			_("ctf_add_type: conflict for type %s: "
 			  "kinds differ, new: %i; old (ID %lx): %i"),
 			name, kind, dst_type, dst_kind);
-	  return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	  return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 	}
     }
 
@@ -1672,7 +1665,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
   if (kind == CTF_K_INTEGER || kind == CTF_K_FLOAT || kind == CTF_K_SLICE)
     {
       if (ctf_type_encoding (src_fp, src_type, &src_en) != 0)
-	return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+	return (ctf_set_typed_errno (dst_fp, ctf_errno (src_fp)));
 
       if (dst_type != CTF_ERR)
 	{
@@ -1702,7 +1695,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 		}
 	      else
 		  {
-		    return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		    return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 		  }
 	    }
 	  else
@@ -1740,7 +1733,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 
   if (ctf_dynhash_insert (proc_tracking_fp->ctf_add_processing,
 			  (void *) (uintptr_t) src_type, (void *) 1) < 0)
-    return ctf_set_errno (dst_fp, ENOMEM);
+    return ctf_set_typed_errno (dst_fp, ENOMEM);
 
   switch (kind)
     {
@@ -1785,7 +1778,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 
     case CTF_K_ARRAY:
       if (ctf_array_info (src_fp, src_type, &src_ar) != 0)
-	return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+	return (ctf_set_typed_errno (dst_fp, ctf_errno (src_fp)));
 
       src_ar.ctr_contents =
 	ctf_add_type_internal (dst_fp, src_fp, src_ar.ctr_contents,
@@ -1812,7 +1805,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 			    src_ar.ctr_index, src_ar.ctr_nelems,
 			    dst_ar.ctr_contents, dst_ar.ctr_index,
 			    dst_ar.ctr_nelems);
-	      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	      return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 	    }
 	}
       else
@@ -1859,7 +1852,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 				"size differs, old %li, new %li"), name,
 			      dst_type, (long) ctf_type_size (src_fp, src_type),
 			      (long) ctf_type_size (dst_fp, dst_type));
-		return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 	      }
 
 	    if (ctf_member_iter (src_fp, src_type, membcmp, &dst))
@@ -1867,7 +1860,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 		ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
 			      _("conflict for type %s against ID %lx: members "
 				"differ, see above"), name, dst_type);
-		return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 	      }
 
 	    break;
@@ -1925,7 +1918,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 	      ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
 			    _("conflict for enum %s against ID %lx: members "
 			      "differ, see above"), name, dst_type);
-	      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	      return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 	    }
 	}
       else
@@ -1964,7 +1957,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
       break;
 
     default:
-      return (ctf_set_errno (dst_fp, ECTF_CORRUPT));
+      return (ctf_set_typed_errno (dst_fp, ECTF_CORRUPT));
     }
 
   if (dst_type != CTF_ERR)
@@ -1985,7 +1978,7 @@ ctf_add_type (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type)
   /* We store the hash on the source, because it contains only source type IDs:
      but callers will invariably expect errors to appear on the dest.  */
   if (!src_fp->ctf_add_processing)
-    return (ctf_set_errno (dst_fp, ENOMEM));
+    return (ctf_set_typed_errno (dst_fp, ENOMEM));
 
   id = ctf_add_type_internal (dst_fp, src_fp, src_type, src_fp);
   ctf_dynhash_empty (src_fp->ctf_add_processing);
diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c
index 5fdddfd0b54..39520675a62 100644
--- a/libctf/ctf-dedup.c
+++ b/libctf/ctf-dedup.c
@@ -321,7 +321,7 @@ id_to_packed_id (ctf_dict_t *fp, int input_num, ctf_id_t type)
 
  oom:
   free (dynkey);
-  ctf_set_errno (fp, ENOMEM);
+  ctf_set_typed_errno (fp, ENOMEM);
   return NULL;
 }
 
@@ -398,7 +398,7 @@ intern (ctf_dict_t *fp, char *atom)
     {
       if (ctf_dynset_insert (fp->ctf_dedup_atoms, atom) < 0)
 	{
-	  ctf_set_errno (fp, ENOMEM);
+	  ctf_set_typed_errno (fp, ENOMEM);
 	  return NULL;
 	}
       foo = atom;
@@ -461,7 +461,7 @@ ctf_decorate_type_name (ctf_dict_t *fp, const char *name, int kind)
   return ret;
 
  oom:
-  ctf_set_errno (fp, ENOMEM);
+  ctf_set_typed_errno (fp, ENOMEM);
   return NULL;
 }
 
@@ -981,7 +981,7 @@ ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs,
 		input_num, gettext (whaterr), type, kind);
   return NULL;
  oom:
-  ctf_set_errno (fp, errno);
+  ctf_set_typed_errno (fp, errno);
   ctf_err_warn (fp, 0, 0, _("%s (%i): %s: during type hashing for type %lx, "
 			    "kind %i"), ctf_link_input_name (input),
 		input_num, gettext (whaterr), type, kind);
@@ -1051,7 +1051,7 @@ ctf_dedup_hash_type (ctf_dict_t *fp, ctf_dict_t *input,
 
   if ((tp = ctf_lookup_by_id (&input, type)) == NULL)
     {
-      ctf_set_errno (fp, ctf_errno (input));
+      ctf_set_typed_errno (fp, ctf_errno (input));
       ctf_err_warn (fp, 0, 0, _("%s (%i): lookup failure for type %lx: "
 				"flags %x"), ctf_link_input_name (input),
 		    input_num, type, flags);
@@ -1140,7 +1140,7 @@ ctf_dedup_hash_type (ctf_dict_t *fp, ctf_dict_t *input,
   return hval;
 
  oom:
-  ctf_set_errno (fp, errno);
+  ctf_set_typed_errno (fp, errno);
  err:
   ctf_err_warn (fp, 0, 0, _("%s (%i): %s: during type hashing, "
 			    "type %lx, kind %i"),
@@ -1318,8 +1318,7 @@ ctf_dedup_mark_conflicting_hash (ctf_dict_t *fp, const char *hval)
   if (ctf_dynset_cinsert (d->cd_conflicting_types, hval) < 0)
     {
       ctf_dprintf ("Out of memory marking %s as conflicted\n", hval);
-      ctf_set_errno (fp, errno);
-      return -1;
+      return ctf_set_errno (fp, errno);
     }
 
   /* If any types cite this type, mark them conflicted too.  */
@@ -2452,7 +2451,7 @@ ctf_dedup_maybe_synthesize_forward (ctf_dict_t *output, ctf_dict_t *target,
       if ((emitted_forward = ctf_add_forward (target, CTF_ADD_ROOT, name,
 					      fwdkind)) == CTF_ERR)
 	{
-	  ctf_set_errno (output, ctf_errno (target));
+	  ctf_set_typed_errno (output, ctf_errno (target));
 	  return CTF_ERR;
 	}
 
@@ -2460,7 +2459,7 @@ ctf_dedup_maybe_synthesize_forward (ctf_dict_t *output, ctf_dict_t *target,
 			       decorated, (void *) (uintptr_t)
 			       emitted_forward) < 0)
 	{
-	  ctf_set_errno (output, ENOMEM);
+	  ctf_set_typed_errno (output, ENOMEM);
 	  return CTF_ERR;
 	}
     }
@@ -2525,7 +2524,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
   if ((input->ctf_flags & LCTF_CHILD) && (LCTF_TYPE_ISPARENT (input, id)))
     {
       if (!ctf_assert (output, parents[input_num] <= ninputs))
-	return -1;
+	return CTF_ERR;
       input = inputs[parents[input_num]];
       input_num = parents[input_num];
     }
@@ -2534,7 +2533,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
 			     CTF_DEDUP_GID (output, input_num, id));
 
   if (!ctf_assert (output, hval && td->cd_output_emission_hashes))
-    return -1;
+    return CTF_ERR;
 
   /* If this type is a conflicted tagged structure, union, or forward,
      substitute a synthetic forward instead, emitting it if need be.  Only do
@@ -2550,10 +2549,10 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
     case 0: /* No forward needed.  */
       break;
     case -1:
-      ctf_set_errno (err_fp, ctf_errno (output));
+      ctf_set_typed_errno (err_fp, ctf_errno (output));
       ctf_err_warn (err_fp, 0, 0, _("cannot add synthetic forward for type "
 				    "%i/%lx"), input_num, id);
-      return -1;
+      return CTF_ERR;
     default:
       return emitted_forward;
     }
@@ -2568,7 +2567,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
       ctf_dprintf ("Checking shared parent for target\n");
       if (!ctf_assert (output, (target != output)
 		       && (target->ctf_flags & LCTF_CHILD)))
-	return -1;
+	return CTF_ERR;
 
       target_id = ctf_dynhash_lookup (od->cd_output_emission_hashes, hval);
 
@@ -2582,13 +2581,13 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
 	  ctf_err_warn (err_fp, 0, ctf_errno (output),
 			_("cannot add synthetic forward for type %i/%lx"),
 			input_num, id);
-	  return ctf_set_errno (err_fp, ctf_errno (output));
+	  return ctf_set_typed_errno (err_fp, ctf_errno (output));
 	default:
 	  return emitted_forward;
 	}
     }
   if (!ctf_assert (output, target_id))
-    return -1;
+    return CTF_ERR;
   return (ctf_id_t) (uintptr_t) target_id;
 }
 
@@ -3101,7 +3100,7 @@ ctf_dedup_emit (ctf_dict_t *output, ctf_dict_t **inputs, uint32_t ninputs,
     {
       ctf_err_warn (output, 0, ENOMEM,
 		    _("out of memory allocating link outputs array"));
-      ctf_set_errno (output, ENOMEM);
+      ctf_set_typed_errno (output, ENOMEM);
       return NULL;
     }
   *noutputs = num_outputs;
@@ -3152,7 +3151,7 @@ ctf_dedup_type_mapping (ctf_dict_t *fp, ctf_dict_t *src_fp, ctf_id_t src_type)
     output = fp->ctf_parent;
   else
     {
-      ctf_set_errno (fp, ECTF_INTERNAL);
+      ctf_set_typed_errno (fp, ECTF_INTERNAL);
       ctf_err_warn (fp, 0, ECTF_INTERNAL,
 		    _("dict %p passed to ctf_dedup_type_mapping is not a "
 		      "deduplicated output"), (void *) fp);
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index 686951a9869..05ef66b586a 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -93,7 +93,7 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
   ctf_id_t new_id;
   char *str = NULL, *bit = NULL, *buf = NULL;
 
-  ctf_set_errno (fp, 0);
+  ctf_set_typed_errno (fp, 0);
   new_id = id;
   do
     {
@@ -117,7 +117,7 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
 	{
 	  if (id == 0 || ctf_errno (fp) == ECTF_NONREPRESENTABLE)
 	    {
-	      ctf_set_errno (fp, ECTF_NONREPRESENTABLE);
+	      ctf_set_typed_errno (fp, ECTF_NONREPRESENTABLE);
 	      str = str_append (str, " (type not represented in CTF)");
 	      return str;
 	    }
@@ -237,7 +237,7 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
   return str;
 
  oom:
-  ctf_set_errno (fp, errno);
+  ctf_set_typed_errno (fp, errno);
  err:
   ctf_err_warn (fp, 1, 0, _("cannot format name dumping type 0x%lx"), id);
   free (buf);
@@ -707,7 +707,7 @@ ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
 
       if ((*statep = malloc (sizeof (struct ctf_dump_state))) == NULL)
 	{
-	  ctf_set_errno (fp, ENOMEM);
+	  ctf_set_typed_errno (fp, ENOMEM);
 	  goto end;
 	}
       state = *statep;
@@ -726,7 +726,7 @@ ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
 	    {
 	      if (ctf_errno (fp) != ECTF_NOLABELDATA)
 		goto end;		/* errno is set for us.  */
-	      ctf_set_errno (fp, 0);
+	      ctf_set_typed_errno (fp, 0);
 	    }
 	  break;
 	case CTF_SECT_OBJT:
@@ -749,7 +749,7 @@ ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
 	  ctf_dump_str (fp, state);
 	  break;
 	default:
-	  ctf_set_errno (fp, ECTF_DUMPSECTUNKNOWN);
+	  ctf_set_typed_errno (fp, ECTF_DUMPSECTUNKNOWN);
 	  goto end;
 	}
     }
@@ -759,7 +759,7 @@ ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
 
       if (state->cds_sect != sect)
 	{
-	  ctf_set_errno (fp, ECTF_DUMPSECTCHANGED);
+	  ctf_set_typed_errno (fp, ECTF_DUMPSECTCHANGED);
 	  goto end;
 	}
     }
@@ -813,18 +813,18 @@ ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
       str = strdup (state->cds_current->cdi_item);
       if (!str)
 	{
-	  ctf_set_errno (fp, ENOMEM);
+	  ctf_set_typed_errno (fp, ENOMEM);
 	  return str;
 	}
     }
 
-  ctf_set_errno (fp, 0);
+  ctf_set_typed_errno (fp, 0);
   return str;
 
  end:
   ctf_dump_free (state);
   free (state);
-  ctf_set_errno (fp, 0);
+  ctf_set_typed_errno (fp, 0);
   *statep = NULL;
   return NULL;
 }
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index da687762c89..77d74ef0ea9 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -741,7 +741,6 @@ extern struct ctf_archive *ctf_arc_open_internal (const char *, int *);
 extern void ctf_arc_close_internal (struct ctf_archive *);
 extern const ctf_preamble_t *ctf_arc_bufpreamble (const ctf_sect_t *);
 extern void *ctf_set_open_errno (int *, int);
-extern unsigned long ctf_set_errno (ctf_dict_t *, int);
 extern void ctf_flip_header (ctf_header_t *);
 extern int ctf_flip (ctf_dict_t *, ctf_header_t *, unsigned char *, int);
 
diff --git a/libctf/ctf-inlines.h b/libctf/ctf-inlines.h
index 6bda68d68e6..84044a1d16c 100644
--- a/libctf/ctf-inlines.h
+++ b/libctf/ctf-inlines.h
@@ -90,6 +90,23 @@ ctf_assert_internal (ctf_dict_t *fp, const char *file, size_t line,
   return expr;
 }
 
+static inline int
+ctf_set_errno (ctf_dict_t *fp, int err)
+{
+  fp->ctf_errno = err;
+  /* Don't rely on CTF_ERR here as it will not properly sign extend on 64-bit
+     Windows ABI.  */
+  return -1;
+}
+
+static inline ctf_id_t
+ctf_set_typed_errno (ctf_dict_t *fp, int err)
+{
+  fp->ctf_errno = err;
+  return CTF_ERR;
+}
+
+
 #ifdef	__cplusplus
 }
 #endif
diff --git a/libctf/ctf-labels.c b/libctf/ctf-labels.c
index 16b111b14df..61742b3fb5f 100644
--- a/libctf/ctf-labels.c
+++ b/libctf/ctf-labels.c
@@ -48,12 +48,12 @@ ctf_label_topmost (ctf_dict_t *fp)
 
   if (num_labels == 0)
     {
-      (void) ctf_set_errno (fp, ECTF_NOLABELDATA);
+      (void) ctf_set_typed_errno (fp, ECTF_NOLABELDATA);
       return NULL;
     }
 
   if ((s = ctf_strraw (fp, (ctlp + num_labels - 1)->ctl_label)) == NULL)
-    (void) ctf_set_errno (fp, ECTF_CORRUPT);
+    (void) ctf_set_typed_errno (fp, ECTF_CORRUPT);
 
   return s;
 }
diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c
index 9babec2aa37..86fc26da7b6 100644
--- a/libctf/ctf-link.c
+++ b/libctf/ctf-link.c
@@ -243,8 +243,7 @@ ctf_link_lazy_open (ctf_dict_t *fp, ctf_link_input_t *input)
 #else
   ctf_err_warn (fp, 0, ECTF_NEEDSBFD, _("cannot open %s lazily"),
 		input->clin_filename);
-  ctf_set_errno (fp, ECTF_NEEDSBFD);
-  return -1;
+  return ctf_set_errno (fp, ECTF_NEEDSBFD);
 #endif
 
   /* Having no CTF sections is not an error.  We just don't need to do
@@ -257,8 +256,7 @@ ctf_link_lazy_open (ctf_dict_t *fp, ctf_link_input_t *input)
 
       ctf_err_warn (fp, 0, err, _("opening CTF %s failed"),
 		    input->clin_filename);
-      ctf_set_errno (fp, err);
-      return -1;
+      return ctf_set_errno (fp, err);
     }
 
   if ((count = ctf_archive_count (input->clin_arc)) == 0)
@@ -334,7 +332,7 @@ ctf_create_per_cu (ctf_dict_t *fp, ctf_dict_t *input, const char *cu_name)
 	{
 	  ctf_err_warn (fp, 0, err, _("cannot create per-CU CTF archive for "
 				      "input CU %s"), cu_name);
-	  ctf_set_errno (fp, err);
+	  ctf_set_typed_errno (fp, err);
 	  return NULL;
 	}
 
@@ -357,7 +355,7 @@ ctf_create_per_cu (ctf_dict_t *fp, ctf_dict_t *input, const char *cu_name)
  oom:
   free (dynname);
   ctf_dict_close (cu_fp);
-  ctf_set_errno (fp, ENOMEM);
+  ctf_set_typed_errno (fp, ENOMEM);
   return NULL;
 }
 
@@ -680,8 +678,7 @@ ctf_link_deduplicating_count_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names,
     {
       ctf_err_warn (fp, 0, err, _("iteration error counting deduplicating "
 				  "CTF link inputs"));
-      ctf_set_errno (fp, err);
-      return -1;
+      return ctf_set_errno (fp, err);
     }
 
   if (!count)
@@ -783,7 +780,7 @@ ctf_link_deduplicating_open_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names,
 	  if (err != ECTF_NOMEMBNAM)
 	    {
 	      ctf_next_destroy (i);
-	      ctf_set_errno (fp, err);
+	      ctf_set_typed_errno (fp, err);
 	      goto err;
 	    }
 	}
@@ -835,7 +832,7 @@ ctf_link_deduplicating_open_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names,
   err = ENOMEM;
 
  iterr:
-  ctf_set_errno (fp, err);
+  ctf_set_typed_errno (fp, err);
 
  err:
   free (dedup_inputs);
@@ -1355,8 +1352,7 @@ ctf_link_empty_outputs (ctf_dict_t *fp)
     {
       fp->ctf_flags &= ~LCTF_LINKING;
       ctf_err_warn (fp, 1, err, _("iteration error removing old outputs"));
-      ctf_set_errno (fp, err);
-      return -1;
+      return ctf_set_errno (fp, err);
     }
   return 0;
 }
@@ -1433,7 +1429,7 @@ ctf_link_deduplicating (ctf_dict_t *fp)
       continue;
 
     oom_one_output:
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_typed_errno (fp, ENOMEM);
       ctf_err_warn (fp, 0, 0, _("out of memory allocating link outputs"));
       free (dynname);
 
@@ -1465,7 +1461,7 @@ ctf_link_deduplicating (ctf_dict_t *fp)
     return;					/* errno is set for us.  */
 
   ninputs = 0;					/* Prevent double-close.  */
-  ctf_set_errno (fp, 0);
+  ctf_set_typed_errno (fp, 0);
 
   /* Fall through.  */
 
@@ -1536,8 +1532,7 @@ ctf_link (ctf_dict_t *fp, int flags)
 	{
 	  fp->ctf_flags &= ~LCTF_LINKING;
 	  ctf_err_warn (fp, 1, err, _("iteration error creating empty CUs"));
-	  ctf_set_errno (fp, err);
-	  return -1;
+	  return ctf_set_errno (fp, err);
 	}
     }
 
@@ -1785,14 +1780,14 @@ ctf_accumulate_archive_names (void *key, void *value, void *arg_)
   if ((names = realloc (arg->names, sizeof (char *) * ++(arg->i))) == NULL)
     {
       (arg->i)--;
-      ctf_set_errno (arg->fp, ENOMEM);
+      ctf_set_typed_errno (arg->fp, ENOMEM);
       return;
     }
 
   if ((files = realloc (arg->files, sizeof (ctf_dict_t *) * arg->i)) == NULL)
     {
       (arg->i)--;
-      ctf_set_errno (arg->fp, ENOMEM);
+      ctf_set_typed_errno (arg->fp, ENOMEM);
       return;
     }
 
@@ -1815,7 +1810,7 @@ ctf_accumulate_archive_names (void *key, void *value, void *arg_)
 				  sizeof (char *) * ++(arg->ndynames))) == NULL)
 	    {
 	      (arg->ndynames)--;
-	      ctf_set_errno (arg->fp, ENOMEM);
+	      ctf_set_typed_errno (arg->fp, ENOMEM);
 	      return;
 	    }
 	    arg->dynames = dynames;
@@ -1986,7 +1981,7 @@ ctf_link_write (ctf_dict_t *fp, size_t *size, size_t threshold)
 			       threshold)) < 0)
     {
       errloc = "archive writing";
-      ctf_set_errno (fp, err);
+      ctf_set_typed_errno (fp, err);
       goto err;
     }
 
@@ -2036,7 +2031,7 @@ ctf_link_write (ctf_dict_t *fp, size_t *size, size_t threshold)
   return buf;
 
  err_no:
-  ctf_set_errno (fp, errno);
+  ctf_set_typed_errno (fp, errno);
 
   /* Turn off the is-linking flag on all the dicts in this link.  */
   for (i = 0; i < arg.i; i++)
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index c65849118cb..7746fea7419 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -143,7 +143,7 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
   ctf_id_t ntype, ptype;
 
   if (name == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   for (p = name, end = name + strlen (name); *p != '\0'; p = q)
     {
@@ -274,7 +274,7 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
 		  fp->ctf_tmp_typeslice = xstrndup (p, (size_t) (q - p));
 		  if (fp->ctf_tmp_typeslice == NULL)
 		    {
-		      ctf_set_errno (fp, ENOMEM);
+		      ctf_set_typed_errno (fp, ENOMEM);
 		      return CTF_ERR;
 		    }
 		}
@@ -292,12 +292,12 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
     }
 
   if (*p != '\0' || type == 0)
-    return (ctf_set_errno (fp, ECTF_SYNTAX));
+    return (ctf_set_typed_errno (fp, ECTF_SYNTAX));
 
   return type;
 
  notype:
-  ctf_set_errno (fp, ECTF_NOTYPE);
+  ctf_set_typed_errno (fp, ECTF_NOTYPE);
   if (fp->ctf_parent != NULL)
     {
       /* Need to look up in the parent, from the child's perspective.
@@ -306,13 +306,13 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
       if (fp->ctf_pptrtab_typemax < fp->ctf_typemax)
 	{
 	  if (refresh_pptrtab (fp, fp->ctf_parent) < 0)
-	    return -1;			/* errno is set for us.  */
+	    return CTF_ERR;			/* errno is set for us.  */
 	}
 
       if ((ptype = ctf_lookup_by_name_internal (fp->ctf_parent, fp,
 						name)) != CTF_ERR)
 	return ptype;
-      return (ctf_set_errno (fp, ctf_errno (fp->ctf_parent)));
+      return (ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent)));
     }
 
   return CTF_ERR;
@@ -336,7 +336,7 @@ ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
 
   if ((fp = ctf_get_dict (fp, type)) == NULL)
     {
-      (void) ctf_set_errno (*fpp, ECTF_NOPARENT);
+      (void) ctf_set_typed_errno (*fpp, ECTF_NOPARENT);
       return NULL;
     }
 
@@ -351,7 +351,7 @@ ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
 	  *fpp = fp;
 	  return &dtd->dtd_data;
 	}
-      (void) ctf_set_errno (*fpp, ECTF_BADID);
+      (void) ctf_set_typed_errno (*fpp, ECTF_BADID);
       return NULL;
     }
 
@@ -364,7 +364,7 @@ ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
       return (LCTF_INDEX_TO_TYPEPTR (fp, idx));
     }
 
-  (void) ctf_set_errno (*fpp, ECTF_BADID);
+  (void) ctf_set_typed_errno (*fpp, ECTF_BADID);
   return NULL;
 }
 
@@ -407,10 +407,10 @@ ctf_lookup_variable (ctf_dict_t *fp, const char *name)
 
           if ((ptype = ctf_lookup_variable (fp->ctf_parent, name)) != CTF_ERR)
             return ptype;
-          return (ctf_set_errno (fp, ctf_errno (fp->ctf_parent)));
+          return (ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent)));
         }
 
-      return (ctf_set_errno (fp, ECTF_NOTYPEDAT));
+      return (ctf_set_typed_errno (fp, ECTF_NOTYPEDAT));
     }
 
   return ent->ctv_type;
@@ -447,7 +447,7 @@ ctf_symidx_sort (ctf_dict_t *fp, uint32_t *idx, size_t *nidx,
 
   if ((sorted = malloc (len)) == NULL)
     {
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_typed_errno (fp, ENOMEM);
       return NULL;
     }
 
@@ -512,7 +512,7 @@ ctf_lookup_symbol_name (ctf_dict_t *fp, unsigned long symidx)
       }
       break;
     default:
-      ctf_set_errno (fp, ECTF_SYMTAB);
+      ctf_set_typed_errno (fp, ECTF_SYMTAB);
       return _CTF_NULLSTR;
     }
 
@@ -526,12 +526,12 @@ ctf_lookup_symbol_name (ctf_dict_t *fp, unsigned long symidx)
       const char *ret;
       ret = ctf_lookup_symbol_name (fp->ctf_parent, symidx);
       if (ret == NULL)
-	ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
+	ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent));
       return ret;
     }
   else
     {
-      ctf_set_errno (fp, err);
+      ctf_set_typed_errno (fp, err);
       return _CTF_NULLSTR;
     }
 }
@@ -621,14 +621,14 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
 	  }
 	  break;
 	default:
-	  ctf_set_errno (fp, ECTF_SYMTAB);
-	  return (unsigned long) -1;
+	  ctf_set_typed_errno (fp, ECTF_SYMTAB);
+	  return CTF_ERR;
 	}
     }
 
   /* Searched everything, still not found.  */
 
-  return (unsigned long) -1;
+  return CTF_ERR;
 
  try_parent:
   if (fp->ctf_parent)
@@ -636,22 +636,22 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
       unsigned long psym;
 
       if ((psym = ctf_lookup_symbol_idx (fp->ctf_parent, symname))
-          != (unsigned long) -1)
+          != CTF_ERR)
         return psym;
 
-      ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
-      return (unsigned long) -1;
+      ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent));
+      return CTF_ERR;
     }
   else
     {
-      ctf_set_errno (fp, err);
-      return (unsigned long) -1;
+      ctf_set_typed_errno (fp, err);
+      return CTF_ERR;
     }
 oom:
-  ctf_set_errno (fp, ENOMEM);
+  ctf_set_typed_errno (fp, ENOMEM);
   ctf_err_warn (fp, 0, ENOMEM, _("cannot allocate memory for symbol "
 				 "lookup hashtab"));
-  return (unsigned long) -1;
+  return CTF_ERR;
 
 }
 
@@ -673,7 +673,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	return ctf_set_typed_errno (fp, ENOMEM);
 
       i->cu.ctn_fp = fp;
       i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next;
@@ -682,10 +682,10 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
     }
 
   if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN));
 
   if (fp != i->cu.ctn_fp)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
 
   /* We intentionally use raw access, not ctf_lookup_by_symbol, to avoid
      incurring additional sorting cost for unsorted symtypetabs coming from the
@@ -701,7 +701,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
       if (!dynh)
 	{
 	  ctf_next_destroy (i);
-	  return (ctf_set_errno (fp, ECTF_NEXT_END));
+	  return (ctf_set_typed_errno (fp, ECTF_NEXT_END));
 	}
 
       err = ctf_dynhash_next (dynh, &i->ctn_next, &dyn_name, &dyn_value);
@@ -710,7 +710,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
 	{
 	  ctf_next_destroy (i);
 	  *it = NULL;
-	  return ctf_set_errno (fp, err);
+	  return ctf_set_typed_errno (fp, err);
 	}
 
       *name = dyn_name;
@@ -786,7 +786,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
  end:
   ctf_next_destroy (i);
   *it = NULL;
-  return (ctf_set_errno (fp, ECTF_NEXT_END));
+  return (ctf_set_typed_errno (fp, ECTF_NEXT_END));
 }
 
 /* A bsearch function for function and object index names.  */
@@ -821,7 +821,7 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 	       "indexed symtypetab\n", symidx, symname);
 
   if (symname[0] == '\0')
-    return -1;					/* errno is set for us.  */
+    return CTF_ERR;					/* errno is set for us.  */
 
   if (is_function)
     {
@@ -835,7 +835,7 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 	      == NULL)
 	    {
 	      ctf_err_warn (fp, 0, 0, _("cannot sort function symidx"));
-	      return -1;				/* errno is set for us.  */
+	      return CTF_ERR;				/* errno is set for us.  */
 	    }
 	}
       symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff);
@@ -855,7 +855,7 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 	      == NULL)
 	    {
 	      ctf_err_warn (fp, 0, 0, _("cannot sort object symidx"));
-	      return -1;				/* errno is set for us. */
+	      return CTF_ERR;				/* errno is set for us. */
 	    }
 	}
 
@@ -878,7 +878,7 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 
   /* Should be impossible, but be paranoid.  */
   if ((idx - sxlate) > (ptrdiff_t) nidx)
-    return (ctf_set_errno (fp, ECTF_CORRUPT));
+    return (ctf_set_typed_errno (fp, ECTF_CORRUPT));
 
   ctf_dprintf ("Symbol %lx (%s) is of type %x\n", symidx, symname,
 	       symtypetab[*idx]);
@@ -1010,11 +1010,11 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
       ctf_id_t ret = ctf_lookup_by_sym_or_name (fp->ctf_parent, symidx,
 						symname);
       if (ret == CTF_ERR)
-	ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
+	ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent));
       return ret;
     }
   else
-    return (ctf_set_errno (fp, err));
+    return (ctf_set_typed_errno (fp, err));
 }
 
 /* Given a symbol table index, return the type of the function or data object
diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
index ba830a2b095..b702108e112 100644
--- a/libctf/ctf-serialize.c
+++ b/libctf/ctf-serialize.c
@@ -1294,7 +1294,7 @@ ctf_write_mem (ctf_dict_t *fp, size_t *size, size_t threshold)
   if ((buf = malloc (compress_len
 		     + sizeof (struct ctf_header))) == NULL)
     {
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_typed_errno (fp, ENOMEM);
       ctf_err_warn (fp, 0, 0, _("ctf_write_mem: cannot allocate %li bytes"),
 		    (unsigned long) (compress_len + sizeof (struct ctf_header)));
       return NULL;
@@ -1317,7 +1317,7 @@ ctf_write_mem (ctf_dict_t *fp, size_t *size, size_t threshold)
     {
       if ((flipped = malloc (fp->ctf_size)) == NULL)
 	{
-	  ctf_set_errno (fp, ENOMEM);
+	  ctf_set_typed_errno (fp, ENOMEM);
 	  ctf_err_warn (fp, 0, 0, _("ctf_write_mem: cannot allocate %li bytes"),
 			(unsigned long) (fp->ctf_size + sizeof (struct ctf_header)));
 	  return NULL;
@@ -1343,7 +1343,7 @@ ctf_write_mem (ctf_dict_t *fp, size_t *size, size_t threshold)
       if ((rc = compress (bp, (uLongf *) &compress_len,
 			  src, fp->ctf_size)) != Z_OK)
 	{
-	  ctf_set_errno (fp, ECTF_COMPRESS);
+	  ctf_set_typed_errno (fp, ECTF_COMPRESS);
 	  ctf_err_warn (fp, 0, 0, _("zlib deflate err: %s"), zError (rc));
 	  free (buf);
 	  return NULL;
diff --git a/libctf/ctf-string.c b/libctf/ctf-string.c
index 911e94700f1..33cbb5032f2 100644
--- a/libctf/ctf-string.c
+++ b/libctf/ctf-string.c
@@ -229,7 +229,7 @@ ctf_str_add_ref_internal (ctf_dict_t *fp, const char *str,
   free (atom);
   free (aref);
   free (newstr);
-  ctf_set_errno (fp, ENOMEM);
+  ctf_set_typed_errno (fp, ENOMEM);
   return NULL;
 }
 
diff --git a/libctf/ctf-subr.c b/libctf/ctf-subr.c
index f4118328a83..6a47131439f 100644
--- a/libctf/ctf-subr.c
+++ b/libctf/ctf-subr.c
@@ -288,7 +288,7 @@ ctf_errwarning_next (ctf_dict_t *fp, ctf_next_t **it, int *is_warning,
 	  if (errp)
 	    *errp = ENOMEM;
 	  else if (fp)
-	    ctf_set_errno (fp, ENOMEM);
+	    ctf_set_typed_errno (fp, ENOMEM);
 	  return NULL;
 	}
 
@@ -302,7 +302,7 @@ ctf_errwarning_next (ctf_dict_t *fp, ctf_next_t **it, int *is_warning,
       if (errp)
 	*errp = ECTF_NEXT_WRONGFUN;
       else if (fp)
-	ctf_set_errno (fp, ECTF_NEXT_WRONGFUN);
+	ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN);
       return NULL;
     }
 
@@ -311,7 +311,7 @@ ctf_errwarning_next (ctf_dict_t *fp, ctf_next_t **it, int *is_warning,
       if (errp)
 	*errp = ECTF_NEXT_WRONGFP;
       else if (fp)
-	ctf_set_errno (fp, ECTF_NEXT_WRONGFP);
+	ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP);
       return NULL;
     }
 
@@ -324,7 +324,7 @@ ctf_errwarning_next (ctf_dict_t *fp, ctf_next_t **it, int *is_warning,
       if (errp)
 	*errp = ECTF_NEXT_END;
       else if (fp)
-	ctf_set_errno (fp, ECTF_NEXT_END);
+	ctf_set_typed_errno (fp, ECTF_NEXT_END);
       return NULL;
     }
 
@@ -342,5 +342,5 @@ ctf_assert_fail_internal (ctf_dict_t *fp, const char *file, size_t line,
 {
   ctf_err_warn (fp, 0, ECTF_INTERNAL, _("%s: %lu: libctf assertion failed: %s"),
 		file, (long unsigned int) line, exprstr);
-  ctf_set_errno (fp, ECTF_INTERNAL);
+  ctf_set_typed_errno (fp, ECTF_INTERNAL);
 }
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index c20ff825d9a..8f325ef9c19 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -287,7 +287,7 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 
       if ((i = ctf_next_create ()) == NULL)
 	{
-	  ctf_set_errno (ofp, ENOMEM);
+	  ctf_set_typed_errno (ofp, ENOMEM);
 	  return NULL;
 	}
       i->cu.ctn_fp = ofp;
@@ -299,7 +299,7 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
       if (kind != CTF_K_ENUM)
 	{
 	  ctf_next_destroy (i);
-	  ctf_set_errno (ofp, ECTF_NOTENUM);
+	  ctf_set_typed_errno (ofp, ECTF_NOTENUM);
 	  return NULL;
 	}
 
@@ -318,20 +318,20 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 
   if ((void (*) (void)) ctf_enum_next != i->ctn_iter_fun)
     {
-      ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN);
+      ctf_set_typed_errno (ofp, ECTF_NEXT_WRONGFUN);
       return NULL;
     }
 
   if (ofp != i->cu.ctn_fp)
     {
-      ctf_set_errno (ofp, ECTF_NEXT_WRONGFP);
+      ctf_set_typed_errno (ofp, ECTF_NEXT_WRONGFP);
       return NULL;
     }
 
   /* Resolve to the native dict of this type.  */
   if ((fp = ctf_get_dict (ofp, type)) == NULL)
     {
-      ctf_set_errno (ofp, ECTF_NOPARENT);
+      ctf_set_typed_errno (ofp, ECTF_NOPARENT);
       return NULL;
     }
 
@@ -349,7 +349,7 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
  end_iter:
   ctf_next_destroy (i);
   *it = NULL;
-  ctf_set_errno (ofp, ECTF_NEXT_END);
+  ctf_set_typed_errno (ofp, ECTF_NEXT_END);
   return NULL;
 }
 
@@ -426,7 +426,7 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	return ctf_set_typed_errno (fp, ENOMEM);
 
       i->cu.ctn_fp = fp;
       i->ctn_type = 1;
@@ -435,10 +435,10 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
     }
 
   if ((void (*) (void)) ctf_type_next != i->ctn_iter_fun)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN));
 
   if (fp != i->cu.ctn_fp)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
 
   while (i->ctn_type <= fp->ctf_typemax)
     {
@@ -456,7 +456,7 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
     }
   ctf_next_destroy (i);
   *it = NULL;
-  return ctf_set_errno (fp, ECTF_NEXT_END);
+  return ctf_set_typed_errno (fp, ECTF_NEXT_END);
 }
 
 /* Iterate over every variable in the given CTF dict, in arbitrary order.
@@ -494,12 +494,12 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
   ctf_next_t *i = *it;
 
   if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parent == NULL))
-    return (ctf_set_errno (fp, ECTF_NOPARENT));
+    return (ctf_set_typed_errno (fp, ECTF_NOPARENT));
 
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	return ctf_set_typed_errno (fp, ENOMEM);
 
       i->cu.ctn_fp = fp;
       i->ctn_iter_fun = (void (*) (void)) ctf_variable_next;
@@ -509,10 +509,10 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
     }
 
   if ((void (*) (void)) ctf_variable_next != i->ctn_iter_fun)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN));
 
   if (fp != i->cu.ctn_fp)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
 
   if (!(fp->ctf_flags & LCTF_RDWR))
     {
@@ -538,7 +538,7 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
  end_iter:
   ctf_next_destroy (i);
   *it = NULL;
-  return ctf_set_errno (fp, ECTF_NEXT_END);
+  return ctf_set_typed_errno (fp, ECTF_NEXT_END);
 }
 
 /* Follow a given type through the graph for TYPEDEF, VOLATILE, CONST, and
@@ -560,7 +560,7 @@ ctf_type_resolve (ctf_dict_t *fp, ctf_id_t type)
   const ctf_type_t *tp;
 
   if (type == 0)
-    return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE));
+    return (ctf_set_typed_errno (ofp, ECTF_NONREPRESENTABLE));
 
   while ((tp = ctf_lookup_by_id (&fp, type)) != NULL)
     {
@@ -575,18 +575,18 @@ ctf_type_resolve (ctf_dict_t *fp, ctf_id_t type)
 	    {
 	      ctf_err_warn (ofp, 0, ECTF_CORRUPT, _("type %lx cycle detected"),
 			    otype);
-	      return (ctf_set_errno (ofp, ECTF_CORRUPT));
+	      return (ctf_set_typed_errno (ofp, ECTF_CORRUPT));
 	    }
 	  prev = type;
 	  type = tp->ctt_type;
 	  break;
 	case CTF_K_UNKNOWN:
-	  return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE));
+	  return (ctf_set_typed_errno (ofp, ECTF_NONREPRESENTABLE));
 	default:
 	  return type;
 	}
       if (type == 0)
-	return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE));
+	return (ctf_set_typed_errno (ofp, ECTF_NONREPRESENTABLE));
     }
 
   return CTF_ERR;		/* errno is set for us.  */
@@ -612,7 +612,7 @@ ctf_type_resolve_unsliced (ctf_dict_t *fp, ctf_id_t type)
       ctf_id_t ret;
 
       if ((ret = ctf_type_reference (fp, type)) == CTF_ERR)
-	return (ctf_set_errno (ofp, ctf_errno (fp)));
+	return (ctf_set_typed_errno (ofp, ctf_errno (fp)));
       return ret;
     }
   return type;
@@ -675,7 +675,7 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
   if (cd.cd_err != 0)
     {
       ctf_decl_fini (&cd);
-      ctf_set_errno (fp, cd.cd_err);
+      ctf_set_typed_errno (fp, cd.cd_err);
       return NULL;
     }
 
@@ -720,7 +720,7 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
 
 	      if (name[0] == '\0')
 		{
-		  ctf_set_errno (fp, ECTF_CORRUPT);
+		  ctf_set_typed_errno (fp, ECTF_CORRUPT);
 		  ctf_decl_fini (&cd);
 		  return NULL;
 		}
@@ -744,7 +744,7 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
 
 		if ((argv = calloc (fi.ctc_argc, sizeof (ctf_id_t *))) == NULL)
 		  {
-		    ctf_set_errno (rfp, errno);
+		    ctf_set_typed_errno (rfp, errno);
 		    goto err;
 		  }
 
@@ -775,7 +775,7 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
 		break;
 
 	      err:
-		ctf_set_errno (fp, ctf_errno (rfp));
+		ctf_set_typed_errno (fp, ctf_errno (rfp));
 		free (argv);
 		ctf_decl_fini (&cd);
 		return NULL;
@@ -804,7 +804,7 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
 		    ctf_decl_sprintf (&cd, "enum %s", name);
 		    break;
 		  default:
-		    ctf_set_errno (fp, ECTF_CORRUPT);
+		    ctf_set_typed_errno (fp, ECTF_CORRUPT);
 		    ctf_decl_fini (&cd);
 		    return NULL;
 		  }
@@ -836,7 +836,7 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
     }
 
   if (cd.cd_enomem)
-    (void) ctf_set_errno (fp, ENOMEM);
+    (void) ctf_set_typed_errno (fp, ENOMEM);
 
   buf = ctf_decl_buf (&cd);
 
@@ -854,7 +854,7 @@ ctf_type_lname (ctf_dict_t *fp, ctf_id_t type, char *buf, size_t len)
   size_t slen;
 
   if (str == NULL)
-    return CTF_ERR;			/* errno is set for us.  */
+    return -1;			/* errno is set for us.  */
 
   slen = strlen (str);
   snprintf (buf, len, "%s", str);
@@ -1139,7 +1139,7 @@ ctf_type_reference (ctf_dict_t *fp, ctf_id_t type)
 	return sp->cts_type;
       }
     default:
-      return (ctf_set_errno (ofp, ECTF_NOTREF));
+      return (ctf_set_typed_errno (ofp, ECTF_NOTREF));
     }
 }
 
@@ -1164,15 +1164,15 @@ ctf_type_pointer (ctf_dict_t *fp, ctf_id_t type)
     return (LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD)));
 
   if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
-    return (ctf_set_errno (ofp, ECTF_NOTYPE));
+    return (ctf_set_typed_errno (ofp, ECTF_NOTYPE));
 
   if (ctf_lookup_by_id (&fp, type) == NULL)
-    return (ctf_set_errno (ofp, ECTF_NOTYPE));
+    return (ctf_set_typed_errno (ofp, ECTF_NOTYPE));
 
   if ((ntype = fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, type)]) != 0)
     return (LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD)));
 
-  return (ctf_set_errno (ofp, ECTF_NOTYPE));
+  return (ctf_set_typed_errno (ofp, ECTF_NOTYPE));
 }
 
 /* Return the encoding for the specified INTEGER, FLOAT, or ENUM.  */
@@ -1494,7 +1494,7 @@ ctf_enum_name (ctf_dict_t *fp, ctf_id_t type, int value)
 
   if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM)
     {
-      ctf_set_errno (ofp, ECTF_NOTENUM);
+      ctf_set_typed_errno (ofp, ECTF_NOTENUM);
       return NULL;
     }
 
@@ -1511,7 +1511,7 @@ ctf_enum_name (ctf_dict_t *fp, ctf_id_t type, int value)
 	return (ctf_strptr (fp, ep->cte_name));
     }
 
-  ctf_set_errno (ofp, ECTF_NOENUMNAM);
+  ctf_set_typed_errno (ofp, ECTF_NOENUMNAM);
   return NULL;
 }
 
@@ -1557,8 +1557,7 @@ ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp)
 	}
     }
 
-  ctf_set_errno (ofp, ECTF_NOENUMNAM);
-  return -1;
+  return ctf_set_errno (ofp, ECTF_NOENUMNAM);
 }
 
 /* Given a type ID relating to a function type, return info on return types and
diff --git a/libctf/ctf-util.c b/libctf/ctf-util.c
index 9f83ab9ab0b..e0d412df390 100644
--- a/libctf/ctf-util.c
+++ b/libctf/ctf-util.c
@@ -255,16 +255,6 @@ ctf_set_open_errno (int *errp, int error)
   return NULL;
 }
 
-/* Store the specified error code into the CTF dict, and then return CTF_ERR /
-   -1 for the benefit of the caller. */
-
-unsigned long
-ctf_set_errno (ctf_dict_t *fp, int err)
-{
-  fp->ctf_errno = err;
-  return CTF_ERR;
-}
-
 /* Create a ctf_next_t.  */
 
 ctf_next_t *
-- 
2.25.1


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

* [PATCH v7] libctf: Sanitize error types for PR 30836
  2023-10-09 14:44                                       ` [PATCH v6] " Torbjörn SVENSSON
@ 2023-10-09 15:11                                         ` Torbjörn SVENSSON
  2023-10-11 11:14                                           ` Nick Alcock
  2023-10-13 14:01                                           ` [PATCH] libctf: check for problems with error returns Nick Alcock
  0 siblings, 2 replies; 41+ messages in thread
From: Torbjörn SVENSSON @ 2023-10-09 15:11 UTC (permalink / raw)
  To: binutils, nick.alcock; +Cc: amodra, Torbjörn SVENSSON, Yvan ROUX

v1 -> v2:
Changed all functions with signed integer return type to return -1 based on
comment from Alan.

v2 -> v3:
Added ctf_set_errno_signed function to return a signed -1 value based on
comment from Nick.

v3 -> v4:
- Moved ctf_set_errno_signed function to ctf-inlines.h, renamed it to
ctf_set_int_errno and converted it to an inline function.
- Moved ctf_set_errno function to ctf-inlines.h, renamed it to
ctf_set_type_errno, changed return type to ctf_id_t and converted it to an
inline function.
- Updated the changelog entry in the commit message. Is this list really
required? I don't think it give much information in this patch and 'git log'
have mixed commits (some have the entry while others don't).

v4 -> v5:
Updated in accordance with comments from Nick.
- Changed return type to void for ctf_set_errno.
- Inline the return on every call to ctf_set_errno.
- Merged ctf_set_int_errno and ctf_set_type_errno into ctf_set_errno.
- Droped log entry as it's too many places with this change to make it
  readable.
- Corrected a few places where -1 was returned where it should have been
  CTF_ERR.

v4 -> v6:
Updated in accordance with comments from Nick.
Patch is now mostly v4 again with additions:
- Renamed ctf_set_type_errno to ctf_set_typed_errno.
- Renamed ctf_set_int_errno to ctf_set_errno.
- Droped log entry as it's too many places with this change to make it
  readable.
- Corrected a few places where -1 was returned where it should have been
  CTF_ERR.

v6 -> v7:
- Reverted chunks that called ctf_set_type_errno in v6 that does not return
  to reduce the number of changed. Thanks Yvan ROUX for pointing this out.



@Nick: Can you please try this is in your test bench and let me know if it's
ok for trunk?

--


Made sure there is no implicit conversion between signed and unsigned
return value for functions setting the ctf_errno value.
An example of the problem is that in ctf_member_next, the "offset" value
is either 0L or (ctf_id_t)-1L, but it should have been 0L or -1L.
The issue was discovered while building a 64 bit ld binary to be
executed on the Windows platform.
Example object file that demonstrates the issue is attached in the PR.

Signed-off-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
Co-Authored-By: Yvan ROUX <yvan.roux@foss.st.com>
---
 libctf/ctf-create.c  | 95 ++++++++++++++++++++------------------------
 libctf/ctf-dedup.c   | 15 ++++---
 libctf/ctf-impl.h    |  1 -
 libctf/ctf-inlines.h | 17 ++++++++
 libctf/ctf-labels.c  |  4 +-
 libctf/ctf-link.c    | 15 +++----
 libctf/ctf-lookup.c  | 52 ++++++++++++------------
 libctf/ctf-types.c   | 43 ++++++++++----------
 libctf/ctf-util.c    | 10 -----
 9 files changed, 122 insertions(+), 130 deletions(-)

diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 6b342dc64a2..fff18e529be 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -225,10 +225,7 @@ ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
   const char *name;
   if (ctf_dynhash_insert (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type,
 			  dtd) < 0)
-    {
-      ctf_set_errno (fp, ENOMEM);
-      return -1;
-    }
+    return ctf_set_errno (fp, ENOMEM);
 
   if (flag == CTF_ADD_ROOT && dtd->dtd_data.ctt_name
       && (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL)
@@ -239,8 +236,7 @@ ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
 	{
 	  ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t)
 			      dtd->dtd_type);
-	  ctf_set_errno (fp, ENOMEM);
-	  return -1;
+	  return ctf_set_errno (fp, ENOMEM);
 	}
     }
   ctf_list_append (&fp->ctf_dtdefs, dtd);
@@ -329,10 +325,7 @@ int
 ctf_dvd_insert (ctf_dict_t *fp, ctf_dvdef_t *dvd)
 {
   if (ctf_dynhash_insert (fp->ctf_dvhash, dvd->dvd_name, dvd) < 0)
-    {
-      ctf_set_errno (fp, ENOMEM);
-      return -1;
-    }
+    return ctf_set_errno (fp, ENOMEM);
   ctf_list_append (&fp->ctf_dvdefs, dvd);
   return 0;
 }
@@ -453,23 +446,23 @@ ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
   ctf_id_t type;
 
   if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_typed_errno (fp, ECTF_RDONLY));
 
   if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) >= CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, ECTF_FULL));
+    return (ctf_set_typed_errno (fp, ECTF_FULL));
 
   if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) == (CTF_MAX_PTYPE - 1))
-    return (ctf_set_errno (fp, ECTF_FULL));
+    return (ctf_set_typed_errno (fp, ECTF_FULL));
 
   /* Make sure ptrtab always grows to be big enough for all types.  */
   if (ctf_grow_ptrtab (fp) < 0)
       return CTF_ERR;				/* errno is set for us. */
 
   if ((dtd = calloc (1, sizeof (ctf_dtdef_t))) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+    return (ctf_set_typed_errno (fp, EAGAIN));
 
   dtd->dtd_vlen_alloc = vlen;
   if (vlen > 0)
@@ -532,13 +525,13 @@ ctf_add_encoded (ctf_dict_t *fp, uint32_t flag,
   uint32_t encoding;
 
   if (ep == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (name == NULL || name[0] == '\0')
-    return (ctf_set_errno (fp, ECTF_NONAME));
+    return (ctf_set_typed_errno (fp, ECTF_NONAME));
 
   if (!ctf_assert (fp, kind == CTF_K_INTEGER || kind == CTF_K_FLOAT))
-    return -1;					/* errno is set for us.  */
+    return CTF_ERR;					/* errno is set for us.  */
 
   if ((type = ctf_add_generic (fp, flag, name, kind, sizeof (uint32_t),
 			       &dtd)) == CTF_ERR)
@@ -570,7 +563,7 @@ ctf_add_reftype (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref, uint32_t kind)
   int child = fp->ctf_flags & LCTF_CHILD;
 
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (ref != 0 && ctf_lookup_by_id (&tmp, ref) == NULL)
     return CTF_ERR;		/* errno is set for us.  */
@@ -613,13 +606,13 @@ ctf_add_slice (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref,
   ctf_dict_t *tmp = fp;
 
   if (ep == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if ((ep->cte_bits > 255) || (ep->cte_offset > 255))
-    return (ctf_set_errno (fp, ECTF_SLICEOVERFLOW));
+    return (ctf_set_typed_errno (fp, ECTF_SLICEOVERFLOW));
 
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (ref != 0 && ((tp = ctf_lookup_by_id (&tmp, ref)) == NULL))
     return CTF_ERR;		/* errno is set for us.  */
@@ -634,7 +627,7 @@ ctf_add_slice (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref,
   if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) &&
       (kind != CTF_K_ENUM)
       && (ref != 0))
-    return (ctf_set_errno (fp, ECTF_NOTINTFP));
+    return (ctf_set_typed_errno (fp, ECTF_NOTINTFP));
 
   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_SLICE,
 			       sizeof (ctf_slice_t), &dtd)) == CTF_ERR)
@@ -682,7 +675,7 @@ ctf_add_array (ctf_dict_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
   ctf_dict_t *tmp = fp;
 
   if (arp == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (arp->ctr_contents != 0
       && ctf_lookup_by_id (&tmp, arp->ctr_contents) == NULL)
@@ -697,7 +690,7 @@ ctf_add_array (ctf_dict_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
       ctf_err_warn (fp, 1, ECTF_INCOMPLETE,
 		    _("ctf_add_array: index type %lx is incomplete"),
 		    arp->ctr_contents);
-      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+      return (ctf_set_typed_errno (fp, ECTF_INCOMPLETE));
     }
 
   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_ARRAY,
@@ -751,11 +744,11 @@ ctf_add_function (ctf_dict_t *fp, uint32_t flag,
   size_t i;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_typed_errno (fp, ECTF_RDONLY));
 
   if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0
       || (ctc->ctc_argc != 0 && argv == NULL))
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   vlen = ctc->ctc_argc;
   if (ctc->ctc_flags & CTF_FUNC_VARARG)
@@ -766,7 +759,7 @@ ctf_add_function (ctf_dict_t *fp, uint32_t flag,
     return CTF_ERR;				/* errno is set for us.  */
 
   if (vlen > CTF_MAX_VLEN)
-    return (ctf_set_errno (fp, EOVERFLOW));
+    return (ctf_set_typed_errno (fp, EOVERFLOW));
 
   /* One word extra allocated for padding for 4-byte alignment if need be.
      Not reflected in vlen: we don't want to copy anything into it, and
@@ -818,7 +811,7 @@ ctf_add_struct_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (dtd->dtd_vlen_alloc == 0)
     {
       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_typed_errno (fp, ENOMEM));
       dtd->dtd_vlen_alloc = initial_vlen;
     }
 
@@ -858,7 +851,7 @@ ctf_add_union_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (dtd->dtd_vlen_alloc == 0)
     {
       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_typed_errno (fp, ENOMEM));
       dtd->dtd_vlen_alloc = initial_vlen;
     }
 
@@ -897,7 +890,7 @@ ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
   if (dtd->dtd_vlen_alloc == 0)
     {
       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_typed_errno (fp, ENOMEM));
       dtd->dtd_vlen_alloc = initial_vlen;
     }
 
@@ -925,7 +918,7 @@ ctf_add_enum_encoded (ctf_dict_t *fp, uint32_t flag, const char *name,
     {
       if ((ctf_type_kind (fp, type) != CTF_K_FORWARD) &&
 	  (ctf_type_kind_unsliced (fp, type) != CTF_K_ENUM))
-	return (ctf_set_errno (fp, ECTF_NOTINTFP));
+	return (ctf_set_typed_errno (fp, ECTF_NOTINTFP));
     }
   else if ((type = ctf_add_enum (fp, flag, name)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
@@ -943,10 +936,10 @@ ctf_add_forward (ctf_dict_t *fp, uint32_t flag, const char *name,
   ctf_id_t type = 0;
 
   if (!ctf_forwardable_kind (kind))
-    return (ctf_set_errno (fp, ECTF_NOTSUE));
+    return (ctf_set_typed_errno (fp, ECTF_NOTSUE));
 
   if (name == NULL || name[0] == '\0')
-    return (ctf_set_errno (fp, ECTF_NONAME));
+    return (ctf_set_typed_errno (fp, ECTF_NONAME));
 
   /* If the type is already defined or exists as a forward tag, just
      return the ctf_id_t of the existing definition.  */
@@ -985,7 +978,7 @@ ctf_add_unknown (ctf_dict_t *fp, uint32_t flag, const char *name)
 			_("ctf_add_unknown: cannot add unknown type "
 			  "named %s: type of this name already defined"),
 			name ? name : _("(unnamed type)"));
-	  return (ctf_set_errno (fp, ECTF_CONFLICT));
+	  return (ctf_set_typed_errno (fp, ECTF_CONFLICT));
 	}
     }
 
@@ -1007,10 +1000,10 @@ ctf_add_typedef (ctf_dict_t *fp, uint32_t flag, const char *name,
   ctf_dict_t *tmp = fp;
 
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (name == NULL || name[0] == '\0')
-    return (ctf_set_errno (fp, ECTF_NONAME));
+    return (ctf_set_typed_errno (fp, ECTF_NONAME));
 
   if (ref != 0 && ctf_lookup_by_id (&tmp, ref) == NULL)
     return CTF_ERR;		/* errno is set for us.  */
@@ -1575,14 +1568,14 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
   ctf_id_t orig_src_type = src_type;
 
   if (!(dst_fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (dst_fp, ECTF_RDONLY));
+    return (ctf_set_typed_errno (dst_fp, ECTF_RDONLY));
 
   if ((src_tp = ctf_lookup_by_id (&src_fp, src_type)) == NULL)
-    return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+    return (ctf_set_typed_errno (dst_fp, ctf_errno (src_fp)));
 
   if ((ctf_type_resolve (src_fp, src_type) == CTF_ERR)
       && (ctf_errno (src_fp) == ECTF_NONREPRESENTABLE))
-    return (ctf_set_errno (dst_fp, ECTF_NONREPRESENTABLE));
+    return (ctf_set_typed_errno (dst_fp, ECTF_NONREPRESENTABLE));
 
   name = ctf_strptr (src_fp, src_tp->ctt_name);
   kind = LCTF_INFO_KIND (src_fp, src_tp->ctt_info);
@@ -1661,7 +1654,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 			_("ctf_add_type: conflict for type %s: "
 			  "kinds differ, new: %i; old (ID %lx): %i"),
 			name, kind, dst_type, dst_kind);
-	  return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	  return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 	}
     }
 
@@ -1672,7 +1665,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
   if (kind == CTF_K_INTEGER || kind == CTF_K_FLOAT || kind == CTF_K_SLICE)
     {
       if (ctf_type_encoding (src_fp, src_type, &src_en) != 0)
-	return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+	return (ctf_set_typed_errno (dst_fp, ctf_errno (src_fp)));
 
       if (dst_type != CTF_ERR)
 	{
@@ -1702,7 +1695,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 		}
 	      else
 		  {
-		    return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		    return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 		  }
 	    }
 	  else
@@ -1740,7 +1733,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 
   if (ctf_dynhash_insert (proc_tracking_fp->ctf_add_processing,
 			  (void *) (uintptr_t) src_type, (void *) 1) < 0)
-    return ctf_set_errno (dst_fp, ENOMEM);
+    return ctf_set_typed_errno (dst_fp, ENOMEM);
 
   switch (kind)
     {
@@ -1785,7 +1778,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 
     case CTF_K_ARRAY:
       if (ctf_array_info (src_fp, src_type, &src_ar) != 0)
-	return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+	return (ctf_set_typed_errno (dst_fp, ctf_errno (src_fp)));
 
       src_ar.ctr_contents =
 	ctf_add_type_internal (dst_fp, src_fp, src_ar.ctr_contents,
@@ -1812,7 +1805,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 			    src_ar.ctr_index, src_ar.ctr_nelems,
 			    dst_ar.ctr_contents, dst_ar.ctr_index,
 			    dst_ar.ctr_nelems);
-	      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	      return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 	    }
 	}
       else
@@ -1859,7 +1852,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 				"size differs, old %li, new %li"), name,
 			      dst_type, (long) ctf_type_size (src_fp, src_type),
 			      (long) ctf_type_size (dst_fp, dst_type));
-		return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 	      }
 
 	    if (ctf_member_iter (src_fp, src_type, membcmp, &dst))
@@ -1867,7 +1860,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 		ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
 			      _("conflict for type %s against ID %lx: members "
 				"differ, see above"), name, dst_type);
-		return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 	      }
 
 	    break;
@@ -1925,7 +1918,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 	      ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
 			    _("conflict for enum %s against ID %lx: members "
 			      "differ, see above"), name, dst_type);
-	      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	      return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 	    }
 	}
       else
@@ -1964,7 +1957,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
       break;
 
     default:
-      return (ctf_set_errno (dst_fp, ECTF_CORRUPT));
+      return (ctf_set_typed_errno (dst_fp, ECTF_CORRUPT));
     }
 
   if (dst_type != CTF_ERR)
@@ -1985,7 +1978,7 @@ ctf_add_type (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type)
   /* We store the hash on the source, because it contains only source type IDs:
      but callers will invariably expect errors to appear on the dest.  */
   if (!src_fp->ctf_add_processing)
-    return (ctf_set_errno (dst_fp, ENOMEM));
+    return (ctf_set_typed_errno (dst_fp, ENOMEM));
 
   id = ctf_add_type_internal (dst_fp, src_fp, src_type, src_fp);
   ctf_dynhash_empty (src_fp->ctf_add_processing);
diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c
index 5fdddfd0b54..7a4b8584a4e 100644
--- a/libctf/ctf-dedup.c
+++ b/libctf/ctf-dedup.c
@@ -1318,8 +1318,7 @@ ctf_dedup_mark_conflicting_hash (ctf_dict_t *fp, const char *hval)
   if (ctf_dynset_cinsert (d->cd_conflicting_types, hval) < 0)
     {
       ctf_dprintf ("Out of memory marking %s as conflicted\n", hval);
-      ctf_set_errno (fp, errno);
-      return -1;
+      return ctf_set_errno (fp, errno);
     }
 
   /* If any types cite this type, mark them conflicted too.  */
@@ -2525,7 +2524,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
   if ((input->ctf_flags & LCTF_CHILD) && (LCTF_TYPE_ISPARENT (input, id)))
     {
       if (!ctf_assert (output, parents[input_num] <= ninputs))
-	return -1;
+	return CTF_ERR;
       input = inputs[parents[input_num]];
       input_num = parents[input_num];
     }
@@ -2534,7 +2533,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
 			     CTF_DEDUP_GID (output, input_num, id));
 
   if (!ctf_assert (output, hval && td->cd_output_emission_hashes))
-    return -1;
+    return CTF_ERR;
 
   /* If this type is a conflicted tagged structure, union, or forward,
      substitute a synthetic forward instead, emitting it if need be.  Only do
@@ -2553,7 +2552,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
       ctf_set_errno (err_fp, ctf_errno (output));
       ctf_err_warn (err_fp, 0, 0, _("cannot add synthetic forward for type "
 				    "%i/%lx"), input_num, id);
-      return -1;
+      return CTF_ERR;
     default:
       return emitted_forward;
     }
@@ -2568,7 +2567,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
       ctf_dprintf ("Checking shared parent for target\n");
       if (!ctf_assert (output, (target != output)
 		       && (target->ctf_flags & LCTF_CHILD)))
-	return -1;
+	return CTF_ERR;
 
       target_id = ctf_dynhash_lookup (od->cd_output_emission_hashes, hval);
 
@@ -2582,13 +2581,13 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
 	  ctf_err_warn (err_fp, 0, ctf_errno (output),
 			_("cannot add synthetic forward for type %i/%lx"),
 			input_num, id);
-	  return ctf_set_errno (err_fp, ctf_errno (output));
+	  return ctf_set_typed_errno (err_fp, ctf_errno (output));
 	default:
 	  return emitted_forward;
 	}
     }
   if (!ctf_assert (output, target_id))
-    return -1;
+    return CTF_ERR;
   return (ctf_id_t) (uintptr_t) target_id;
 }
 
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index da687762c89..77d74ef0ea9 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -741,7 +741,6 @@ extern struct ctf_archive *ctf_arc_open_internal (const char *, int *);
 extern void ctf_arc_close_internal (struct ctf_archive *);
 extern const ctf_preamble_t *ctf_arc_bufpreamble (const ctf_sect_t *);
 extern void *ctf_set_open_errno (int *, int);
-extern unsigned long ctf_set_errno (ctf_dict_t *, int);
 extern void ctf_flip_header (ctf_header_t *);
 extern int ctf_flip (ctf_dict_t *, ctf_header_t *, unsigned char *, int);
 
diff --git a/libctf/ctf-inlines.h b/libctf/ctf-inlines.h
index 6bda68d68e6..84044a1d16c 100644
--- a/libctf/ctf-inlines.h
+++ b/libctf/ctf-inlines.h
@@ -90,6 +90,23 @@ ctf_assert_internal (ctf_dict_t *fp, const char *file, size_t line,
   return expr;
 }
 
+static inline int
+ctf_set_errno (ctf_dict_t *fp, int err)
+{
+  fp->ctf_errno = err;
+  /* Don't rely on CTF_ERR here as it will not properly sign extend on 64-bit
+     Windows ABI.  */
+  return -1;
+}
+
+static inline ctf_id_t
+ctf_set_typed_errno (ctf_dict_t *fp, int err)
+{
+  fp->ctf_errno = err;
+  return CTF_ERR;
+}
+
+
 #ifdef	__cplusplus
 }
 #endif
diff --git a/libctf/ctf-labels.c b/libctf/ctf-labels.c
index 16b111b14df..61742b3fb5f 100644
--- a/libctf/ctf-labels.c
+++ b/libctf/ctf-labels.c
@@ -48,12 +48,12 @@ ctf_label_topmost (ctf_dict_t *fp)
 
   if (num_labels == 0)
     {
-      (void) ctf_set_errno (fp, ECTF_NOLABELDATA);
+      (void) ctf_set_typed_errno (fp, ECTF_NOLABELDATA);
       return NULL;
     }
 
   if ((s = ctf_strraw (fp, (ctlp + num_labels - 1)->ctl_label)) == NULL)
-    (void) ctf_set_errno (fp, ECTF_CORRUPT);
+    (void) ctf_set_typed_errno (fp, ECTF_CORRUPT);
 
   return s;
 }
diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c
index 9babec2aa37..27d11c97893 100644
--- a/libctf/ctf-link.c
+++ b/libctf/ctf-link.c
@@ -243,8 +243,7 @@ ctf_link_lazy_open (ctf_dict_t *fp, ctf_link_input_t *input)
 #else
   ctf_err_warn (fp, 0, ECTF_NEEDSBFD, _("cannot open %s lazily"),
 		input->clin_filename);
-  ctf_set_errno (fp, ECTF_NEEDSBFD);
-  return -1;
+  return ctf_set_errno (fp, ECTF_NEEDSBFD);
 #endif
 
   /* Having no CTF sections is not an error.  We just don't need to do
@@ -257,8 +256,7 @@ ctf_link_lazy_open (ctf_dict_t *fp, ctf_link_input_t *input)
 
       ctf_err_warn (fp, 0, err, _("opening CTF %s failed"),
 		    input->clin_filename);
-      ctf_set_errno (fp, err);
-      return -1;
+      return ctf_set_errno (fp, err);
     }
 
   if ((count = ctf_archive_count (input->clin_arc)) == 0)
@@ -680,8 +678,7 @@ ctf_link_deduplicating_count_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names,
     {
       ctf_err_warn (fp, 0, err, _("iteration error counting deduplicating "
 				  "CTF link inputs"));
-      ctf_set_errno (fp, err);
-      return -1;
+      return ctf_set_errno (fp, err);
     }
 
   if (!count)
@@ -1355,8 +1352,7 @@ ctf_link_empty_outputs (ctf_dict_t *fp)
     {
       fp->ctf_flags &= ~LCTF_LINKING;
       ctf_err_warn (fp, 1, err, _("iteration error removing old outputs"));
-      ctf_set_errno (fp, err);
-      return -1;
+      return ctf_set_errno (fp, err);
     }
   return 0;
 }
@@ -1536,8 +1532,7 @@ ctf_link (ctf_dict_t *fp, int flags)
 	{
 	  fp->ctf_flags &= ~LCTF_LINKING;
 	  ctf_err_warn (fp, 1, err, _("iteration error creating empty CUs"));
-	  ctf_set_errno (fp, err);
-	  return -1;
+	  return ctf_set_errno (fp, err);
 	}
     }
 
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index c65849118cb..500b77ab868 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -143,7 +143,7 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
   ctf_id_t ntype, ptype;
 
   if (name == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   for (p = name, end = name + strlen (name); *p != '\0'; p = q)
     {
@@ -292,7 +292,7 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
     }
 
   if (*p != '\0' || type == 0)
-    return (ctf_set_errno (fp, ECTF_SYNTAX));
+    return (ctf_set_typed_errno (fp, ECTF_SYNTAX));
 
   return type;
 
@@ -306,13 +306,13 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
       if (fp->ctf_pptrtab_typemax < fp->ctf_typemax)
 	{
 	  if (refresh_pptrtab (fp, fp->ctf_parent) < 0)
-	    return -1;			/* errno is set for us.  */
+	    return CTF_ERR;			/* errno is set for us.  */
 	}
 
       if ((ptype = ctf_lookup_by_name_internal (fp->ctf_parent, fp,
 						name)) != CTF_ERR)
 	return ptype;
-      return (ctf_set_errno (fp, ctf_errno (fp->ctf_parent)));
+      return (ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent)));
     }
 
   return CTF_ERR;
@@ -336,7 +336,7 @@ ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
 
   if ((fp = ctf_get_dict (fp, type)) == NULL)
     {
-      (void) ctf_set_errno (*fpp, ECTF_NOPARENT);
+      (void) ctf_set_typed_errno (*fpp, ECTF_NOPARENT);
       return NULL;
     }
 
@@ -351,7 +351,7 @@ ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
 	  *fpp = fp;
 	  return &dtd->dtd_data;
 	}
-      (void) ctf_set_errno (*fpp, ECTF_BADID);
+      (void) ctf_set_typed_errno (*fpp, ECTF_BADID);
       return NULL;
     }
 
@@ -364,7 +364,7 @@ ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
       return (LCTF_INDEX_TO_TYPEPTR (fp, idx));
     }
 
-  (void) ctf_set_errno (*fpp, ECTF_BADID);
+  (void) ctf_set_typed_errno (*fpp, ECTF_BADID);
   return NULL;
 }
 
@@ -407,10 +407,10 @@ ctf_lookup_variable (ctf_dict_t *fp, const char *name)
 
           if ((ptype = ctf_lookup_variable (fp->ctf_parent, name)) != CTF_ERR)
             return ptype;
-          return (ctf_set_errno (fp, ctf_errno (fp->ctf_parent)));
+          return (ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent)));
         }
 
-      return (ctf_set_errno (fp, ECTF_NOTYPEDAT));
+      return (ctf_set_typed_errno (fp, ECTF_NOTYPEDAT));
     }
 
   return ent->ctv_type;
@@ -622,13 +622,13 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
 	  break;
 	default:
 	  ctf_set_errno (fp, ECTF_SYMTAB);
-	  return (unsigned long) -1;
+	  return CTF_ERR;
 	}
     }
 
   /* Searched everything, still not found.  */
 
-  return (unsigned long) -1;
+  return CTF_ERR;
 
  try_parent:
   if (fp->ctf_parent)
@@ -636,22 +636,22 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
       unsigned long psym;
 
       if ((psym = ctf_lookup_symbol_idx (fp->ctf_parent, symname))
-          != (unsigned long) -1)
+          != CTF_ERR)
         return psym;
 
       ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
-      return (unsigned long) -1;
+      return CTF_ERR;
     }
   else
     {
       ctf_set_errno (fp, err);
-      return (unsigned long) -1;
+      return CTF_ERR;
     }
 oom:
   ctf_set_errno (fp, ENOMEM);
   ctf_err_warn (fp, 0, ENOMEM, _("cannot allocate memory for symbol "
 				 "lookup hashtab"));
-  return (unsigned long) -1;
+  return CTF_ERR;
 
 }
 
@@ -673,7 +673,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	return ctf_set_typed_errno (fp, ENOMEM);
 
       i->cu.ctn_fp = fp;
       i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next;
@@ -682,10 +682,10 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
     }
 
   if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN));
 
   if (fp != i->cu.ctn_fp)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
 
   /* We intentionally use raw access, not ctf_lookup_by_symbol, to avoid
      incurring additional sorting cost for unsorted symtypetabs coming from the
@@ -701,7 +701,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
       if (!dynh)
 	{
 	  ctf_next_destroy (i);
-	  return (ctf_set_errno (fp, ECTF_NEXT_END));
+	  return (ctf_set_typed_errno (fp, ECTF_NEXT_END));
 	}
 
       err = ctf_dynhash_next (dynh, &i->ctn_next, &dyn_name, &dyn_value);
@@ -710,7 +710,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
 	{
 	  ctf_next_destroy (i);
 	  *it = NULL;
-	  return ctf_set_errno (fp, err);
+	  return ctf_set_typed_errno (fp, err);
 	}
 
       *name = dyn_name;
@@ -786,7 +786,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
  end:
   ctf_next_destroy (i);
   *it = NULL;
-  return (ctf_set_errno (fp, ECTF_NEXT_END));
+  return (ctf_set_typed_errno (fp, ECTF_NEXT_END));
 }
 
 /* A bsearch function for function and object index names.  */
@@ -821,7 +821,7 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 	       "indexed symtypetab\n", symidx, symname);
 
   if (symname[0] == '\0')
-    return -1;					/* errno is set for us.  */
+    return CTF_ERR;					/* errno is set for us.  */
 
   if (is_function)
     {
@@ -835,7 +835,7 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 	      == NULL)
 	    {
 	      ctf_err_warn (fp, 0, 0, _("cannot sort function symidx"));
-	      return -1;				/* errno is set for us.  */
+	      return CTF_ERR;				/* errno is set for us.  */
 	    }
 	}
       symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff);
@@ -855,7 +855,7 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 	      == NULL)
 	    {
 	      ctf_err_warn (fp, 0, 0, _("cannot sort object symidx"));
-	      return -1;				/* errno is set for us. */
+	      return CTF_ERR;				/* errno is set for us. */
 	    }
 	}
 
@@ -878,7 +878,7 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 
   /* Should be impossible, but be paranoid.  */
   if ((idx - sxlate) > (ptrdiff_t) nidx)
-    return (ctf_set_errno (fp, ECTF_CORRUPT));
+    return (ctf_set_typed_errno (fp, ECTF_CORRUPT));
 
   ctf_dprintf ("Symbol %lx (%s) is of type %x\n", symidx, symname,
 	       symtypetab[*idx]);
@@ -1014,7 +1014,7 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
       return ret;
     }
   else
-    return (ctf_set_errno (fp, err));
+    return (ctf_set_typed_errno (fp, err));
 }
 
 /* Given a symbol table index, return the type of the function or data object
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index c20ff825d9a..12b4225a88a 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -426,7 +426,7 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	return ctf_set_typed_errno (fp, ENOMEM);
 
       i->cu.ctn_fp = fp;
       i->ctn_type = 1;
@@ -435,10 +435,10 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
     }
 
   if ((void (*) (void)) ctf_type_next != i->ctn_iter_fun)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN));
 
   if (fp != i->cu.ctn_fp)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
 
   while (i->ctn_type <= fp->ctf_typemax)
     {
@@ -456,7 +456,7 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
     }
   ctf_next_destroy (i);
   *it = NULL;
-  return ctf_set_errno (fp, ECTF_NEXT_END);
+  return ctf_set_typed_errno (fp, ECTF_NEXT_END);
 }
 
 /* Iterate over every variable in the given CTF dict, in arbitrary order.
@@ -494,12 +494,12 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
   ctf_next_t *i = *it;
 
   if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parent == NULL))
-    return (ctf_set_errno (fp, ECTF_NOPARENT));
+    return (ctf_set_typed_errno (fp, ECTF_NOPARENT));
 
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	return ctf_set_typed_errno (fp, ENOMEM);
 
       i->cu.ctn_fp = fp;
       i->ctn_iter_fun = (void (*) (void)) ctf_variable_next;
@@ -509,10 +509,10 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
     }
 
   if ((void (*) (void)) ctf_variable_next != i->ctn_iter_fun)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN));
 
   if (fp != i->cu.ctn_fp)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
 
   if (!(fp->ctf_flags & LCTF_RDWR))
     {
@@ -538,7 +538,7 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
  end_iter:
   ctf_next_destroy (i);
   *it = NULL;
-  return ctf_set_errno (fp, ECTF_NEXT_END);
+  return ctf_set_typed_errno (fp, ECTF_NEXT_END);
 }
 
 /* Follow a given type through the graph for TYPEDEF, VOLATILE, CONST, and
@@ -560,7 +560,7 @@ ctf_type_resolve (ctf_dict_t *fp, ctf_id_t type)
   const ctf_type_t *tp;
 
   if (type == 0)
-    return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE));
+    return (ctf_set_typed_errno (ofp, ECTF_NONREPRESENTABLE));
 
   while ((tp = ctf_lookup_by_id (&fp, type)) != NULL)
     {
@@ -575,18 +575,18 @@ ctf_type_resolve (ctf_dict_t *fp, ctf_id_t type)
 	    {
 	      ctf_err_warn (ofp, 0, ECTF_CORRUPT, _("type %lx cycle detected"),
 			    otype);
-	      return (ctf_set_errno (ofp, ECTF_CORRUPT));
+	      return (ctf_set_typed_errno (ofp, ECTF_CORRUPT));
 	    }
 	  prev = type;
 	  type = tp->ctt_type;
 	  break;
 	case CTF_K_UNKNOWN:
-	  return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE));
+	  return (ctf_set_typed_errno (ofp, ECTF_NONREPRESENTABLE));
 	default:
 	  return type;
 	}
       if (type == 0)
-	return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE));
+	return (ctf_set_typed_errno (ofp, ECTF_NONREPRESENTABLE));
     }
 
   return CTF_ERR;		/* errno is set for us.  */
@@ -612,7 +612,7 @@ ctf_type_resolve_unsliced (ctf_dict_t *fp, ctf_id_t type)
       ctf_id_t ret;
 
       if ((ret = ctf_type_reference (fp, type)) == CTF_ERR)
-	return (ctf_set_errno (ofp, ctf_errno (fp)));
+	return (ctf_set_typed_errno (ofp, ctf_errno (fp)));
       return ret;
     }
   return type;
@@ -836,7 +836,7 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
     }
 
   if (cd.cd_enomem)
-    (void) ctf_set_errno (fp, ENOMEM);
+    (void) ctf_set_typed_errno (fp, ENOMEM);
 
   buf = ctf_decl_buf (&cd);
 
@@ -854,7 +854,7 @@ ctf_type_lname (ctf_dict_t *fp, ctf_id_t type, char *buf, size_t len)
   size_t slen;
 
   if (str == NULL)
-    return CTF_ERR;			/* errno is set for us.  */
+    return -1;			/* errno is set for us.  */
 
   slen = strlen (str);
   snprintf (buf, len, "%s", str);
@@ -1139,7 +1139,7 @@ ctf_type_reference (ctf_dict_t *fp, ctf_id_t type)
 	return sp->cts_type;
       }
     default:
-      return (ctf_set_errno (ofp, ECTF_NOTREF));
+      return (ctf_set_typed_errno (ofp, ECTF_NOTREF));
     }
 }
 
@@ -1164,15 +1164,15 @@ ctf_type_pointer (ctf_dict_t *fp, ctf_id_t type)
     return (LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD)));
 
   if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
-    return (ctf_set_errno (ofp, ECTF_NOTYPE));
+    return (ctf_set_typed_errno (ofp, ECTF_NOTYPE));
 
   if (ctf_lookup_by_id (&fp, type) == NULL)
-    return (ctf_set_errno (ofp, ECTF_NOTYPE));
+    return (ctf_set_typed_errno (ofp, ECTF_NOTYPE));
 
   if ((ntype = fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, type)]) != 0)
     return (LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD)));
 
-  return (ctf_set_errno (ofp, ECTF_NOTYPE));
+  return (ctf_set_typed_errno (ofp, ECTF_NOTYPE));
 }
 
 /* Return the encoding for the specified INTEGER, FLOAT, or ENUM.  */
@@ -1557,8 +1557,7 @@ ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp)
 	}
     }
 
-  ctf_set_errno (ofp, ECTF_NOENUMNAM);
-  return -1;
+  return ctf_set_errno (ofp, ECTF_NOENUMNAM);
 }
 
 /* Given a type ID relating to a function type, return info on return types and
diff --git a/libctf/ctf-util.c b/libctf/ctf-util.c
index 9f83ab9ab0b..e0d412df390 100644
--- a/libctf/ctf-util.c
+++ b/libctf/ctf-util.c
@@ -255,16 +255,6 @@ ctf_set_open_errno (int *errp, int error)
   return NULL;
 }
 
-/* Store the specified error code into the CTF dict, and then return CTF_ERR /
-   -1 for the benefit of the caller. */
-
-unsigned long
-ctf_set_errno (ctf_dict_t *fp, int err)
-{
-  fp->ctf_errno = err;
-  return CTF_ERR;
-}
-
 /* Create a ctf_next_t.  */
 
 ctf_next_t *
-- 
2.25.1


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

* Re: [PATCH v7] libctf: Sanitize error types for PR 30836
  2023-10-09 15:11                                         ` [PATCH v7] " Torbjörn SVENSSON
@ 2023-10-11 11:14                                           ` Nick Alcock
  2023-10-13 14:01                                           ` [PATCH] libctf: check for problems with error returns Nick Alcock
  1 sibling, 0 replies; 41+ messages in thread
From: Nick Alcock @ 2023-10-11 11:14 UTC (permalink / raw)
  To: Torbjörn SVENSSON; +Cc: binutils, nick.alcock, amodra, Yvan ROUX

On 9 Oct 2023, Torbjörn SVENSSON uttered the following:

> @Nick: Can you please try this is in your test bench and let me know if it's
> ok for trunk?

I think I'll write a testcase too (it'll only show anything on mingw64,
but having testcases that verify that errors are actually seen as errors
seems wise in any case), but yes, testing is about to start :) looks
good at first sight, but I hvaen't tried it on the affected systems yet.
(Presumably a build actually *on* mingw would be affected too, which is
one of my routine test envs.)

-- 
NULL && (void)

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

* [PATCH] libctf: check for problems with error returns
  2023-10-09 15:11                                         ` [PATCH v7] " Torbjörn SVENSSON
  2023-10-11 11:14                                           ` Nick Alcock
@ 2023-10-13 14:01                                           ` Nick Alcock
  2023-10-13 18:31                                             ` Torbjorn SVENSSON
  2024-01-30 12:46                                             ` Andreas Schwab
  1 sibling, 2 replies; 41+ messages in thread
From: Nick Alcock @ 2023-10-13 14:01 UTC (permalink / raw)
  To: binutils; +Cc: torbjorn.svensson, yvan.roux

We do this as a writable test because the only known-affected platforms
(with ssize_t longer than unsigned long) use PE, and we do not have support
for CTF linkage in the PE linker yet.

	PR libctf/30836
	* libctf/testsuite/libctf-writable/libctf-errors.*: New test.
---
 .../testsuite/libctf-writable/libctf-errors.c | 74 +++++++++++++++++++
 .../libctf-writable/libctf-errors.lk          |  1 +
 2 files changed, 75 insertions(+)
 create mode 100644 libctf/testsuite/libctf-writable/libctf-errors.c
 create mode 100644 libctf/testsuite/libctf-writable/libctf-errors.lk

Your patch looks good, and passes every test I can throw at it. I think
it can go in.  You cleaned up a bunch of outright errors in this area,
too, especially in ctf-dedup: thanks!

(You probably want to adjust the commit log so that the version history
is at the bottom rather than the top, or drop it entirely.)


Here's a testcase that fails on mingw64 in the absence of your patch,
without requiring a cross-build to an ELF arch.  (It also checks at
least one instance of the other classes of error return in libctf.)

I'll push this after your commit goes in.  (I can push it, with an
adjusted commit log, if you want.)

diff --git a/libctf/testsuite/libctf-writable/libctf-errors.c b/libctf/testsuite/libctf-writable/libctf-errors.c
new file mode 100644
index 00000000000..71f8268cfad
--- /dev/null
+++ b/libctf/testsuite/libctf-writable/libctf-errors.c
@@ -0,0 +1,74 @@
+/* Make sure that error returns are correct.  Usually this is trivially
+   true, but on platforms with unusual type sizes all the casting might
+   cause problems with unexpected sign-extension and truncation.  */
+
+#include <ctf-api.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (int argc, char *argv[])
+{
+  ctf_dict_t *fp;
+  ctf_next_t *i = NULL;
+  size_t boom = 0;
+  ctf_id_t itype, stype;
+  ctf_encoding_t encoding = {0};
+  ctf_membinfo_t mi;
+  ssize_t ret;
+  int err;
+
+  if ((fp = ctf_create (&err)) == NULL)
+    {
+      fprintf (stderr, "%s: cannot create: %s\n", argv[0], ctf_errmsg (err));
+      return 1;
+    }
+
+  /* First error class: int return.  */
+
+  if (ctf_member_count (fp, 1024) >= 0)
+    fprintf (stderr, "int return: non-error return: %i\n",
+             ctf_member_count(fp, 1024));
+
+  /* Second error class: type ID return.  */
+
+  if (ctf_type_reference (fp, 1024) != CTF_ERR)
+    fprintf (stderr, "ctf_id_t return: non-error return: %li\n",
+             ctf_type_reference (fp, 1024));
+
+  /* Third error class: ssize_t return.  Create a type to iterate over first.  */
+
+  if ((itype = ctf_add_integer (fp, CTF_ADD_ROOT, "int", &encoding)) == CTF_ERR)
+    fprintf (stderr, "cannot add int: %s\n", ctf_errmsg (ctf_errno (fp)));
+  else if ((stype = ctf_add_struct (fp, CTF_ADD_ROOT, "foo")) == CTF_ERR)
+    fprintf (stderr, "cannot add struct: %s\n", ctf_errmsg (ctf_errno (fp)));
+  else if (ctf_add_member (fp, stype, "bar", itype) < 0)
+    fprintf (stderr, "cannot add member: %s\n", ctf_errmsg (ctf_errno (fp)));
+
+  if (ctf_member_info (fp, stype, "bar", &mi) < 0)
+    fprintf (stderr, "cannot get member info: %s\n", ctf_errmsg (ctf_errno (fp)));
+
+  /* Iteration should never produce an offset bigger than the offset just returned,
+     and should quickly terminate.  */
+
+  while ((ret = ctf_member_next (fp, stype, &i, NULL, NULL, 0)) >= 0) {
+    if (ret > mi.ctm_offset)
+      fprintf (stderr, "ssize_t return: unexpected offset: %zi\n", ret);
+    if (boom++ > 1000)
+      {
+        fprintf (stderr, "member iteration went on way too long\n");
+        exit (1);
+      }
+  }
+
+  /* Fourth error class (trivial): pointer return.  */
+  if (ctf_type_aname (fp, 1024) != NULL)
+    fprintf (stderr, "pointer return: non-error return: %p\n",
+             ctf_type_aname (fp, 1024));
+
+  ctf_file_close (fp);
+
+  printf("All done.\n");
+
+  return 0;
+}
diff --git a/libctf/testsuite/libctf-writable/libctf-errors.lk b/libctf/testsuite/libctf-writable/libctf-errors.lk
new file mode 100644
index 00000000000..b944f73d013
--- /dev/null
+++ b/libctf/testsuite/libctf-writable/libctf-errors.lk
@@ -0,0 +1 @@
+All done.

-- 
2.42.0.271.g85384428f1


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

* Re: [PATCH] libctf: check for problems with error returns
  2023-10-13 14:01                                           ` [PATCH] libctf: check for problems with error returns Nick Alcock
@ 2023-10-13 18:31                                             ` Torbjorn SVENSSON
  2023-10-15 19:18                                               ` Nick Alcock
  2024-01-30 12:46                                             ` Andreas Schwab
  1 sibling, 1 reply; 41+ messages in thread
From: Torbjorn SVENSSON @ 2023-10-13 18:31 UTC (permalink / raw)
  To: Nick Alcock, binutils; +Cc: yvan.roux

Hi Nick,

Thanks for validating this patch!

On 2023-10-13 16:01, Nick Alcock wrote:
> We do this as a writable test because the only known-affected platforms
> (with ssize_t longer than unsigned long) use PE, and we do not have support
> for CTF linkage in the PE linker yet.

Is it visible in PE too or only PE32+? Maybe not important, but the Arm 
built variant does not trigger the fault (same source tree as I found 
the issue in, but they build 32-bit and I build 64-bit) when I've 
executed the GCC testsuite.

> 	PR libctf/30836
> 	* libctf/testsuite/libctf-writable/libctf-errors.*: New test.
> ---
>   .../testsuite/libctf-writable/libctf-errors.c | 74 +++++++++++++++++++
>   .../libctf-writable/libctf-errors.lk          |  1 +
>   2 files changed, 75 insertions(+)
>   create mode 100644 libctf/testsuite/libctf-writable/libctf-errors.c
>   create mode 100644 libctf/testsuite/libctf-writable/libctf-errors.lk
> 
> Your patch looks good, and passes every test I can throw at it. I think
> it can go in.  You cleaned up a bunch of outright errors in this area,
> too, especially in ctf-dedup: thanks!

There is still some potential for cleanup as some functions are 
returning "unsigned long", but think it should perhaps be ctf_id_t instead.

> (You probably want to adjust the commit log so that the version history
> is at the bottom rather than the top, or drop it entirely.)

My plan was to drop that part.

Do you think I should have a changelog entry for the commit and if so, 
what should I write in it? Should I list every function that is touched 
(more or less half of the ctf_* functions defined...) or is there some 
better way to document this change?


> Here's a testcase that fails on mingw64 in the absence of your patch,
> without requiring a cross-build to an ELF arch.  (It also checks at
> least one instance of the other classes of error return in libctf.)
> 
> I'll push this after your commit goes in.  (I can push it, with an
> adjusted commit log, if you want.

Fine either way. Either reply to my question about changelog or just 
merge it with the correct answer :)

> 
> diff --git a/libctf/testsuite/libctf-writable/libctf-errors.c b/libctf/testsuite/libctf-writable/libctf-errors.c
> new file mode 100644
> index 00000000000..71f8268cfad
> --- /dev/null
> +++ b/libctf/testsuite/libctf-writable/libctf-errors.c
> @@ -0,0 +1,74 @@
> +/* Make sure that error returns are correct.  Usually this is trivially
> +   true, but on platforms with unusual type sizes all the casting might
> +   cause problems with unexpected sign-extension and truncation.  */
> +
> +#include <ctf-api.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +int
> +main (int argc, char *argv[])
> +{
> +  ctf_dict_t *fp;
> +  ctf_next_t *i = NULL;
> +  size_t boom = 0;
> +  ctf_id_t itype, stype;
> +  ctf_encoding_t encoding = {0};
> +  ctf_membinfo_t mi;
> +  ssize_t ret;
> +  int err;
> +
> +  if ((fp = ctf_create (&err)) == NULL)
> +    {
> +      fprintf (stderr, "%s: cannot create: %s\n", argv[0], ctf_errmsg (err));
> +      return 1;
> +    }
> +
> +  /* First error class: int return.  */
> +
> +  if (ctf_member_count (fp, 1024) >= 0)
> +    fprintf (stderr, "int return: non-error return: %i\n",
> +             ctf_member_count(fp, 1024));
> +
> +  /* Second error class: type ID return.  */
> +
> +  if (ctf_type_reference (fp, 1024) != CTF_ERR)
> +    fprintf (stderr, "ctf_id_t return: non-error return: %li\n",
> +             ctf_type_reference (fp, 1024));
> +
> +  /* Third error class: ssize_t return.  Create a type to iterate over first.  */
> +
> +  if ((itype = ctf_add_integer (fp, CTF_ADD_ROOT, "int", &encoding)) == CTF_ERR)
> +    fprintf (stderr, "cannot add int: %s\n", ctf_errmsg (ctf_errno (fp)));
> +  else if ((stype = ctf_add_struct (fp, CTF_ADD_ROOT, "foo")) == CTF_ERR)
> +    fprintf (stderr, "cannot add struct: %s\n", ctf_errmsg (ctf_errno (fp)));
> +  else if (ctf_add_member (fp, stype, "bar", itype) < 0)
> +    fprintf (stderr, "cannot add member: %s\n", ctf_errmsg (ctf_errno (fp)));

Should these be if-else-if-else-if-statments like above or just 3 
"free-standing" if-statements? I.e. should the 3 potential issue be 
visible in the same run or should they require 3 consecutive runs if all 
of them are failing?

> +
> +  if (ctf_member_info (fp, stype, "bar", &mi) < 0)
> +    fprintf (stderr, "cannot get member info: %s\n", ctf_errmsg (ctf_errno (fp)));
> +
> +  /* Iteration should never produce an offset bigger than the offset just returned,
> +     and should quickly terminate.  */
> +
> +  while ((ret = ctf_member_next (fp, stype, &i, NULL, NULL, 0)) >= 0) {
> +    if (ret > mi.ctm_offset)
> +      fprintf (stderr, "ssize_t return: unexpected offset: %zi\n", ret);
> +    if (boom++ > 1000)
> +      {
> +        fprintf (stderr, "member iteration went on way too long\n");
> +        exit (1);
> +      }
> +  }
> +
> +  /* Fourth error class (trivial): pointer return.  */
> +  if (ctf_type_aname (fp, 1024) != NULL)
> +    fprintf (stderr, "pointer return: non-error return: %p\n",
> +             ctf_type_aname (fp, 1024));
> +
> +  ctf_file_close (fp);
> +
> +  printf("All done.\n");
> +
> +  return 0;
> +}
> diff --git a/libctf/testsuite/libctf-writable/libctf-errors.lk b/libctf/testsuite/libctf-writable/libctf-errors.lk
> new file mode 100644
> index 00000000000..b944f73d013
> --- /dev/null
> +++ b/libctf/testsuite/libctf-writable/libctf-errors.lk
> @@ -0,0 +1 @@
> +All done.
> 

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

* Re: [PATCH] libctf: check for problems with error returns
  2023-10-13 18:31                                             ` Torbjorn SVENSSON
@ 2023-10-15 19:18                                               ` Nick Alcock
  2023-10-16 12:51                                                 ` [PATCH v8] libctf: Sanitize error types for PR 30836 Torbjörn SVENSSON
  2023-10-16 13:02                                                 ` [PATCH] libctf: check for problems with error returns Torbjorn SVENSSON
  0 siblings, 2 replies; 41+ messages in thread
From: Nick Alcock @ 2023-10-15 19:18 UTC (permalink / raw)
  To: Torbjorn SVENSSON; +Cc: binutils, yvan.roux

On 13 Oct 2023, Torbjorn SVENSSON told this:

> Hi Nick,
>
> Thanks for validating this patch!
>
> On 2023-10-13 16:01, Nick Alcock wrote:
>> We do this as a writable test because the only known-affected platforms
>> (with ssize_t longer than unsigned long) use PE, and we do not have support
>> for CTF linkage in the PE linker yet.
>
> Is it visible in PE too or only PE32+? Maybe not important, but the
> Arm built variant does not trigger the fault (same source tree as I
> found the issue in, but they build 32-bit and I build 64-bit) when
> I've executed the GCC testsuite.

The underlying fault is client-side and is visible in anything that does
a ctf_member_next on a platform with sizeof(ssize_t) > sizeof(unsigned
long). The specific instance you saw (a hanging linker) requires CTF in
the input and a linker that deduplicates it, and right now that is ELF
only (because it was painful enough to add that I didn't have the
stamina to add anything else -- if anything else *is* added, it will
probably be PE next, but right now linking PE just blindly concatenates
CTF sections, which isn't very useful).

>> 	PR libctf/30836
>> 	* libctf/testsuite/libctf-writable/libctf-errors.*: New test.
>> ---
>>   .../testsuite/libctf-writable/libctf-errors.c | 74 +++++++++++++++++++
>>   .../libctf-writable/libctf-errors.lk          |  1 +
>>   2 files changed, 75 insertions(+)
>>   create mode 100644 libctf/testsuite/libctf-writable/libctf-errors.c
>>   create mode 100644 libctf/testsuite/libctf-writable/libctf-errors.lk
>> Your patch looks good, and passes every test I can throw at it. I think
>> it can go in.  You cleaned up a bunch of outright errors in this area,
>> too, especially in ctf-dedup: thanks!
>
> There is still some potential for cleanup as some functions are
> returning "unsigned long", but think it should perhaps be ctf_id_t
> instead.

The only one of those i can see is ctf_lookup_symbol_idx. That's
returning a symbol index, not a type ID, so should definitely not be
returning a ctf_id_t. Perhaps it should be an int, but I'm not sure how
big symbol tables in the set of all executable formats can actually
be...

Hm, actually, there is one bit you might want to adjust in ctf-lookup.c.
You fixed one call to ctf_lookup_symbol_idx () in
ctf_lookup_by_sym_or_name ():

    if ((symidx = ctf_lookup_symbol_idx (fp, symname)) == (unsigned long) -1)
      goto try_parent;

but the other one, in ctf_lookup_symbol_idx () itself (doing a recursive
call to check parent dicts), still says

      if ((psym = ctf_lookup_symbol_idx (fp->ctf_parent, symname))
          != CTF_ERR)

Both symidx and psym are unsigned long variables, so probably both
should be checking against (unsigned long) -1.

>> (You probably want to adjust the commit log so that the version history
>> is at the bottom rather than the top, or drop it entirely.)
>
> My plan was to drop that part.

Aha right.

> Do you think I should have a changelog entry for the commit and if so,
> what should I write in it? Should I list every function that is
> touched (more or less half of the ctf_* functions defined...) or is
> there some better way to document this change?

You can just say

	Affected functions adjusted.

or something. A giant list adds no value, I think.

>> Here's a testcase that fails on mingw64 in the absence of your patch,
>> without requiring a cross-build to an ELF arch.  (It also checks at
>> least one instance of the other classes of error return in libctf.)
>> I'll push this after your commit goes in.  (I can push it, with an
>> adjusted commit log, if you want.
>
> Fine either way. Either reply to my question about changelog or just merge it with the correct answer :)

... I think there's one more tiny change :/

>> +  /* Third error class: ssize_t return.  Create a type to iterate over first.  */
>> +
>> +  if ((itype = ctf_add_integer (fp, CTF_ADD_ROOT, "int", &encoding)) == CTF_ERR)
>> +    fprintf (stderr, "cannot add int: %s\n", ctf_errmsg (ctf_errno (fp)));
>> +  else if ((stype = ctf_add_struct (fp, CTF_ADD_ROOT, "foo")) == CTF_ERR)
>> +    fprintf (stderr, "cannot add struct: %s\n", ctf_errmsg (ctf_errno (fp)));
>> +  else if (ctf_add_member (fp, stype, "bar", itype) < 0)
>> +    fprintf (stderr, "cannot add member: %s\n", ctf_errmsg (ctf_errno (fp)));
>
> Should these be if-else-if-else-if-statments like above or just 3 "free-standing" if-statements? I.e. should the 3 potential issue
> be visible in the same run or should they require 3 consecutive runs if all of them are failing?

I was wondering if this was too clever (or unclear!) but the intent is
to only do the later things if the earlier ones didn't fail, i.e. what
would be foo || bar || baz in the shell. (Later operations will also
fail if any of them fail, but the fprintf's from the first failure will
suffice to make the whole test fail -- so maybe it's safe to just do
them in sequence even if the earlier ones failed. Excessive paranoia on
my part perhaps, given that we don't *expect* any of these to fail: it's
just setting things up for the *actual* tests, of ctf_member_info and
ctf_member_next.)

>> +  if (ctf_member_info (fp, stype, "bar", &mi) < 0)
>> +    fprintf (stderr, "cannot get member info: %s\n", ctf_errmsg (ctf_errno (fp)));
>> +
>> +  /* Iteration should never produce an offset bigger than the offset just returned,
>> +     and should quickly terminate.  */
>> +
>> +  while ((ret = ctf_member_next (fp, stype, &i, NULL, NULL, 0)) >= 0) {
>> +    if (ret > mi.ctm_offset)
>> +      fprintf (stderr, "ssize_t return: unexpected offset: %zi\n", ret);

(here.)

-- 
NULL && (void)

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

* [PATCH v8] libctf: Sanitize error types for PR 30836
  2023-10-15 19:18                                               ` Nick Alcock
@ 2023-10-16 12:51                                                 ` Torbjörn SVENSSON
  2023-10-17 15:15                                                   ` Nick Alcock
  2023-10-16 13:02                                                 ` [PATCH] libctf: check for problems with error returns Torbjorn SVENSSON
  1 sibling, 1 reply; 41+ messages in thread
From: Torbjörn SVENSSON @ 2023-10-16 12:51 UTC (permalink / raw)
  To: binutils, nick.alcock; +Cc: amodra, Torbjörn SVENSSON, Yvan ROUX

v1 -> v2:
Changed all functions with signed integer return type to return -1 based on
comment from Alan.

v2 -> v3:
Added ctf_set_errno_signed function to return a signed -1 value based on
comment from Nick.

v3 -> v4:
- Moved ctf_set_errno_signed function to ctf-inlines.h, renamed it to
ctf_set_int_errno and converted it to an inline function.
- Moved ctf_set_errno function to ctf-inlines.h, renamed it to
ctf_set_type_errno, changed return type to ctf_id_t and converted it to an
inline function.
- Updated the changelog entry in the commit message. Is this list really
required? I don't think it give much information in this patch and 'git log'
have mixed commits (some have the entry while others don't).

v4 -> v5:
Updated in accordance with comments from Nick.
- Changed return type to void for ctf_set_errno.
- Inline the return on every call to ctf_set_errno.
- Merged ctf_set_int_errno and ctf_set_type_errno into ctf_set_errno.
- Droped log entry as it's too many places with this change to make it
  readable.
- Corrected a few places where -1 was returned where it should have been
  CTF_ERR.

v4 -> v6:
Updated in accordance with comments from Nick.
Patch is now mostly v4 again with additions:
- Renamed ctf_set_type_errno to ctf_set_typed_errno.
- Renamed ctf_set_int_errno to ctf_set_errno.
- Droped log entry as it's too many places with this change to make it
  readable.
- Corrected a few places where -1 was returned where it should have been
  CTF_ERR.

v6 -> v7:
- Reverted chunks that called ctf_set_type_errno in v6 that does not return
  to reduce the number of changed. Thanks Yvan ROUX for pointing this out.

v7 -> v8:
- Reverted a few more chunks that were changed to ctf_set_typed_errno while
  the return value was not used.
- Reverted some incorrect changes from (unsigned long)-1 to CTF_ERR.
- Collapsed a few scopes that no longer are needed.
- Added the changelog entry to the commit message.


@Nick: With the last minor changes, do you want to rerun the tests or do
you think this is clean enough to just commit it on trunk?

--

Made sure there is no implicit conversion between signed and unsigned
return value for functions setting the ctf_errno value.
An example of the problem is that in ctf_member_next, the "offset" value
is either 0L or (ctf_id_t)-1L, but it should have been 0L or -1L.
The issue was discovered while building a 64 bit ld binary to be
executed on the Windows platform.
Example object file that demonstrates the issue is attached in the PR.

libctf/
	Affected functions adjusted.

Signed-off-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
Co-Authored-By: Yvan ROUX <yvan.roux@foss.st.com>
---
 libctf/ctf-create.c  | 95 ++++++++++++++++++++------------------------
 libctf/ctf-dedup.c   | 25 +++++-------
 libctf/ctf-impl.h    |  1 -
 libctf/ctf-inlines.h | 17 ++++++++
 libctf/ctf-link.c    | 15 +++----
 libctf/ctf-lookup.c  | 39 +++++++++---------
 libctf/ctf-types.c   | 46 ++++++++++-----------
 libctf/ctf-util.c    | 10 -----
 8 files changed, 114 insertions(+), 134 deletions(-)

diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 6b342dc64a2..fff18e529be 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -225,10 +225,7 @@ ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
   const char *name;
   if (ctf_dynhash_insert (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type,
 			  dtd) < 0)
-    {
-      ctf_set_errno (fp, ENOMEM);
-      return -1;
-    }
+    return ctf_set_errno (fp, ENOMEM);
 
   if (flag == CTF_ADD_ROOT && dtd->dtd_data.ctt_name
       && (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL)
@@ -239,8 +236,7 @@ ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
 	{
 	  ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t)
 			      dtd->dtd_type);
-	  ctf_set_errno (fp, ENOMEM);
-	  return -1;
+	  return ctf_set_errno (fp, ENOMEM);
 	}
     }
   ctf_list_append (&fp->ctf_dtdefs, dtd);
@@ -329,10 +325,7 @@ int
 ctf_dvd_insert (ctf_dict_t *fp, ctf_dvdef_t *dvd)
 {
   if (ctf_dynhash_insert (fp->ctf_dvhash, dvd->dvd_name, dvd) < 0)
-    {
-      ctf_set_errno (fp, ENOMEM);
-      return -1;
-    }
+    return ctf_set_errno (fp, ENOMEM);
   ctf_list_append (&fp->ctf_dvdefs, dvd);
   return 0;
 }
@@ -453,23 +446,23 @@ ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
   ctf_id_t type;
 
   if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_typed_errno (fp, ECTF_RDONLY));
 
   if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) >= CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, ECTF_FULL));
+    return (ctf_set_typed_errno (fp, ECTF_FULL));
 
   if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) == (CTF_MAX_PTYPE - 1))
-    return (ctf_set_errno (fp, ECTF_FULL));
+    return (ctf_set_typed_errno (fp, ECTF_FULL));
 
   /* Make sure ptrtab always grows to be big enough for all types.  */
   if (ctf_grow_ptrtab (fp) < 0)
       return CTF_ERR;				/* errno is set for us. */
 
   if ((dtd = calloc (1, sizeof (ctf_dtdef_t))) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+    return (ctf_set_typed_errno (fp, EAGAIN));
 
   dtd->dtd_vlen_alloc = vlen;
   if (vlen > 0)
@@ -532,13 +525,13 @@ ctf_add_encoded (ctf_dict_t *fp, uint32_t flag,
   uint32_t encoding;
 
   if (ep == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (name == NULL || name[0] == '\0')
-    return (ctf_set_errno (fp, ECTF_NONAME));
+    return (ctf_set_typed_errno (fp, ECTF_NONAME));
 
   if (!ctf_assert (fp, kind == CTF_K_INTEGER || kind == CTF_K_FLOAT))
-    return -1;					/* errno is set for us.  */
+    return CTF_ERR;					/* errno is set for us.  */
 
   if ((type = ctf_add_generic (fp, flag, name, kind, sizeof (uint32_t),
 			       &dtd)) == CTF_ERR)
@@ -570,7 +563,7 @@ ctf_add_reftype (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref, uint32_t kind)
   int child = fp->ctf_flags & LCTF_CHILD;
 
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (ref != 0 && ctf_lookup_by_id (&tmp, ref) == NULL)
     return CTF_ERR;		/* errno is set for us.  */
@@ -613,13 +606,13 @@ ctf_add_slice (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref,
   ctf_dict_t *tmp = fp;
 
   if (ep == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if ((ep->cte_bits > 255) || (ep->cte_offset > 255))
-    return (ctf_set_errno (fp, ECTF_SLICEOVERFLOW));
+    return (ctf_set_typed_errno (fp, ECTF_SLICEOVERFLOW));
 
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (ref != 0 && ((tp = ctf_lookup_by_id (&tmp, ref)) == NULL))
     return CTF_ERR;		/* errno is set for us.  */
@@ -634,7 +627,7 @@ ctf_add_slice (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref,
   if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) &&
       (kind != CTF_K_ENUM)
       && (ref != 0))
-    return (ctf_set_errno (fp, ECTF_NOTINTFP));
+    return (ctf_set_typed_errno (fp, ECTF_NOTINTFP));
 
   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_SLICE,
 			       sizeof (ctf_slice_t), &dtd)) == CTF_ERR)
@@ -682,7 +675,7 @@ ctf_add_array (ctf_dict_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
   ctf_dict_t *tmp = fp;
 
   if (arp == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (arp->ctr_contents != 0
       && ctf_lookup_by_id (&tmp, arp->ctr_contents) == NULL)
@@ -697,7 +690,7 @@ ctf_add_array (ctf_dict_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
       ctf_err_warn (fp, 1, ECTF_INCOMPLETE,
 		    _("ctf_add_array: index type %lx is incomplete"),
 		    arp->ctr_contents);
-      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+      return (ctf_set_typed_errno (fp, ECTF_INCOMPLETE));
     }
 
   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_ARRAY,
@@ -751,11 +744,11 @@ ctf_add_function (ctf_dict_t *fp, uint32_t flag,
   size_t i;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_typed_errno (fp, ECTF_RDONLY));
 
   if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0
       || (ctc->ctc_argc != 0 && argv == NULL))
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   vlen = ctc->ctc_argc;
   if (ctc->ctc_flags & CTF_FUNC_VARARG)
@@ -766,7 +759,7 @@ ctf_add_function (ctf_dict_t *fp, uint32_t flag,
     return CTF_ERR;				/* errno is set for us.  */
 
   if (vlen > CTF_MAX_VLEN)
-    return (ctf_set_errno (fp, EOVERFLOW));
+    return (ctf_set_typed_errno (fp, EOVERFLOW));
 
   /* One word extra allocated for padding for 4-byte alignment if need be.
      Not reflected in vlen: we don't want to copy anything into it, and
@@ -818,7 +811,7 @@ ctf_add_struct_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (dtd->dtd_vlen_alloc == 0)
     {
       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_typed_errno (fp, ENOMEM));
       dtd->dtd_vlen_alloc = initial_vlen;
     }
 
@@ -858,7 +851,7 @@ ctf_add_union_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (dtd->dtd_vlen_alloc == 0)
     {
       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_typed_errno (fp, ENOMEM));
       dtd->dtd_vlen_alloc = initial_vlen;
     }
 
@@ -897,7 +890,7 @@ ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
   if (dtd->dtd_vlen_alloc == 0)
     {
       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_typed_errno (fp, ENOMEM));
       dtd->dtd_vlen_alloc = initial_vlen;
     }
 
@@ -925,7 +918,7 @@ ctf_add_enum_encoded (ctf_dict_t *fp, uint32_t flag, const char *name,
     {
       if ((ctf_type_kind (fp, type) != CTF_K_FORWARD) &&
 	  (ctf_type_kind_unsliced (fp, type) != CTF_K_ENUM))
-	return (ctf_set_errno (fp, ECTF_NOTINTFP));
+	return (ctf_set_typed_errno (fp, ECTF_NOTINTFP));
     }
   else if ((type = ctf_add_enum (fp, flag, name)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
@@ -943,10 +936,10 @@ ctf_add_forward (ctf_dict_t *fp, uint32_t flag, const char *name,
   ctf_id_t type = 0;
 
   if (!ctf_forwardable_kind (kind))
-    return (ctf_set_errno (fp, ECTF_NOTSUE));
+    return (ctf_set_typed_errno (fp, ECTF_NOTSUE));
 
   if (name == NULL || name[0] == '\0')
-    return (ctf_set_errno (fp, ECTF_NONAME));
+    return (ctf_set_typed_errno (fp, ECTF_NONAME));
 
   /* If the type is already defined or exists as a forward tag, just
      return the ctf_id_t of the existing definition.  */
@@ -985,7 +978,7 @@ ctf_add_unknown (ctf_dict_t *fp, uint32_t flag, const char *name)
 			_("ctf_add_unknown: cannot add unknown type "
 			  "named %s: type of this name already defined"),
 			name ? name : _("(unnamed type)"));
-	  return (ctf_set_errno (fp, ECTF_CONFLICT));
+	  return (ctf_set_typed_errno (fp, ECTF_CONFLICT));
 	}
     }
 
@@ -1007,10 +1000,10 @@ ctf_add_typedef (ctf_dict_t *fp, uint32_t flag, const char *name,
   ctf_dict_t *tmp = fp;
 
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   if (name == NULL || name[0] == '\0')
-    return (ctf_set_errno (fp, ECTF_NONAME));
+    return (ctf_set_typed_errno (fp, ECTF_NONAME));
 
   if (ref != 0 && ctf_lookup_by_id (&tmp, ref) == NULL)
     return CTF_ERR;		/* errno is set for us.  */
@@ -1575,14 +1568,14 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
   ctf_id_t orig_src_type = src_type;
 
   if (!(dst_fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (dst_fp, ECTF_RDONLY));
+    return (ctf_set_typed_errno (dst_fp, ECTF_RDONLY));
 
   if ((src_tp = ctf_lookup_by_id (&src_fp, src_type)) == NULL)
-    return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+    return (ctf_set_typed_errno (dst_fp, ctf_errno (src_fp)));
 
   if ((ctf_type_resolve (src_fp, src_type) == CTF_ERR)
       && (ctf_errno (src_fp) == ECTF_NONREPRESENTABLE))
-    return (ctf_set_errno (dst_fp, ECTF_NONREPRESENTABLE));
+    return (ctf_set_typed_errno (dst_fp, ECTF_NONREPRESENTABLE));
 
   name = ctf_strptr (src_fp, src_tp->ctt_name);
   kind = LCTF_INFO_KIND (src_fp, src_tp->ctt_info);
@@ -1661,7 +1654,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 			_("ctf_add_type: conflict for type %s: "
 			  "kinds differ, new: %i; old (ID %lx): %i"),
 			name, kind, dst_type, dst_kind);
-	  return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	  return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 	}
     }
 
@@ -1672,7 +1665,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
   if (kind == CTF_K_INTEGER || kind == CTF_K_FLOAT || kind == CTF_K_SLICE)
     {
       if (ctf_type_encoding (src_fp, src_type, &src_en) != 0)
-	return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+	return (ctf_set_typed_errno (dst_fp, ctf_errno (src_fp)));
 
       if (dst_type != CTF_ERR)
 	{
@@ -1702,7 +1695,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 		}
 	      else
 		  {
-		    return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		    return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 		  }
 	    }
 	  else
@@ -1740,7 +1733,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 
   if (ctf_dynhash_insert (proc_tracking_fp->ctf_add_processing,
 			  (void *) (uintptr_t) src_type, (void *) 1) < 0)
-    return ctf_set_errno (dst_fp, ENOMEM);
+    return ctf_set_typed_errno (dst_fp, ENOMEM);
 
   switch (kind)
     {
@@ -1785,7 +1778,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 
     case CTF_K_ARRAY:
       if (ctf_array_info (src_fp, src_type, &src_ar) != 0)
-	return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+	return (ctf_set_typed_errno (dst_fp, ctf_errno (src_fp)));
 
       src_ar.ctr_contents =
 	ctf_add_type_internal (dst_fp, src_fp, src_ar.ctr_contents,
@@ -1812,7 +1805,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 			    src_ar.ctr_index, src_ar.ctr_nelems,
 			    dst_ar.ctr_contents, dst_ar.ctr_index,
 			    dst_ar.ctr_nelems);
-	      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	      return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 	    }
 	}
       else
@@ -1859,7 +1852,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 				"size differs, old %li, new %li"), name,
 			      dst_type, (long) ctf_type_size (src_fp, src_type),
 			      (long) ctf_type_size (dst_fp, dst_type));
-		return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 	      }
 
 	    if (ctf_member_iter (src_fp, src_type, membcmp, &dst))
@@ -1867,7 +1860,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 		ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
 			      _("conflict for type %s against ID %lx: members "
 				"differ, see above"), name, dst_type);
-		return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 	      }
 
 	    break;
@@ -1925,7 +1918,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 	      ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
 			    _("conflict for enum %s against ID %lx: members "
 			      "differ, see above"), name, dst_type);
-	      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	      return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
 	    }
 	}
       else
@@ -1964,7 +1957,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
       break;
 
     default:
-      return (ctf_set_errno (dst_fp, ECTF_CORRUPT));
+      return (ctf_set_typed_errno (dst_fp, ECTF_CORRUPT));
     }
 
   if (dst_type != CTF_ERR)
@@ -1985,7 +1978,7 @@ ctf_add_type (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type)
   /* We store the hash on the source, because it contains only source type IDs:
      but callers will invariably expect errors to appear on the dest.  */
   if (!src_fp->ctf_add_processing)
-    return (ctf_set_errno (dst_fp, ENOMEM));
+    return (ctf_set_typed_errno (dst_fp, ENOMEM));
 
   id = ctf_add_type_internal (dst_fp, src_fp, src_type, src_fp);
   ctf_dynhash_empty (src_fp->ctf_add_processing);
diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c
index 5fdddfd0b54..43f44f1fafd 100644
--- a/libctf/ctf-dedup.c
+++ b/libctf/ctf-dedup.c
@@ -1318,8 +1318,7 @@ ctf_dedup_mark_conflicting_hash (ctf_dict_t *fp, const char *hval)
   if (ctf_dynset_cinsert (d->cd_conflicting_types, hval) < 0)
     {
       ctf_dprintf ("Out of memory marking %s as conflicted\n", hval);
-      ctf_set_errno (fp, errno);
-      return -1;
+      return ctf_set_errno (fp, errno);
     }
 
   /* If any types cite this type, mark them conflicted too.  */
@@ -2451,18 +2450,12 @@ ctf_dedup_maybe_synthesize_forward (ctf_dict_t *output, ctf_dict_t *target,
     {
       if ((emitted_forward = ctf_add_forward (target, CTF_ADD_ROOT, name,
 					      fwdkind)) == CTF_ERR)
-	{
-	  ctf_set_errno (output, ctf_errno (target));
-	  return CTF_ERR;
-	}
+	return ctf_set_typed_errno (output, ctf_errno (target));
 
       if (ctf_dynhash_cinsert (td->cd_output_emission_conflicted_forwards,
 			       decorated, (void *) (uintptr_t)
 			       emitted_forward) < 0)
-	{
-	  ctf_set_errno (output, ENOMEM);
-	  return CTF_ERR;
-	}
+	return ctf_set_typed_errno (output, ENOMEM);
     }
   else
     emitted_forward = (ctf_id_t) (uintptr_t) v;
@@ -2525,7 +2518,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
   if ((input->ctf_flags & LCTF_CHILD) && (LCTF_TYPE_ISPARENT (input, id)))
     {
       if (!ctf_assert (output, parents[input_num] <= ninputs))
-	return -1;
+	return CTF_ERR;
       input = inputs[parents[input_num]];
       input_num = parents[input_num];
     }
@@ -2534,7 +2527,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
 			     CTF_DEDUP_GID (output, input_num, id));
 
   if (!ctf_assert (output, hval && td->cd_output_emission_hashes))
-    return -1;
+    return CTF_ERR;
 
   /* If this type is a conflicted tagged structure, union, or forward,
      substitute a synthetic forward instead, emitting it if need be.  Only do
@@ -2553,7 +2546,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
       ctf_set_errno (err_fp, ctf_errno (output));
       ctf_err_warn (err_fp, 0, 0, _("cannot add synthetic forward for type "
 				    "%i/%lx"), input_num, id);
-      return -1;
+      return CTF_ERR;
     default:
       return emitted_forward;
     }
@@ -2568,7 +2561,7 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
       ctf_dprintf ("Checking shared parent for target\n");
       if (!ctf_assert (output, (target != output)
 		       && (target->ctf_flags & LCTF_CHILD)))
-	return -1;
+	return CTF_ERR;
 
       target_id = ctf_dynhash_lookup (od->cd_output_emission_hashes, hval);
 
@@ -2582,13 +2575,13 @@ ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
 	  ctf_err_warn (err_fp, 0, ctf_errno (output),
 			_("cannot add synthetic forward for type %i/%lx"),
 			input_num, id);
-	  return ctf_set_errno (err_fp, ctf_errno (output));
+	  return ctf_set_typed_errno (err_fp, ctf_errno (output));
 	default:
 	  return emitted_forward;
 	}
     }
   if (!ctf_assert (output, target_id))
-    return -1;
+    return CTF_ERR;
   return (ctf_id_t) (uintptr_t) target_id;
 }
 
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index da687762c89..77d74ef0ea9 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -741,7 +741,6 @@ extern struct ctf_archive *ctf_arc_open_internal (const char *, int *);
 extern void ctf_arc_close_internal (struct ctf_archive *);
 extern const ctf_preamble_t *ctf_arc_bufpreamble (const ctf_sect_t *);
 extern void *ctf_set_open_errno (int *, int);
-extern unsigned long ctf_set_errno (ctf_dict_t *, int);
 extern void ctf_flip_header (ctf_header_t *);
 extern int ctf_flip (ctf_dict_t *, ctf_header_t *, unsigned char *, int);
 
diff --git a/libctf/ctf-inlines.h b/libctf/ctf-inlines.h
index 6bda68d68e6..84044a1d16c 100644
--- a/libctf/ctf-inlines.h
+++ b/libctf/ctf-inlines.h
@@ -90,6 +90,23 @@ ctf_assert_internal (ctf_dict_t *fp, const char *file, size_t line,
   return expr;
 }
 
+static inline int
+ctf_set_errno (ctf_dict_t *fp, int err)
+{
+  fp->ctf_errno = err;
+  /* Don't rely on CTF_ERR here as it will not properly sign extend on 64-bit
+     Windows ABI.  */
+  return -1;
+}
+
+static inline ctf_id_t
+ctf_set_typed_errno (ctf_dict_t *fp, int err)
+{
+  fp->ctf_errno = err;
+  return CTF_ERR;
+}
+
+
 #ifdef	__cplusplus
 }
 #endif
diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c
index 9babec2aa37..27d11c97893 100644
--- a/libctf/ctf-link.c
+++ b/libctf/ctf-link.c
@@ -243,8 +243,7 @@ ctf_link_lazy_open (ctf_dict_t *fp, ctf_link_input_t *input)
 #else
   ctf_err_warn (fp, 0, ECTF_NEEDSBFD, _("cannot open %s lazily"),
 		input->clin_filename);
-  ctf_set_errno (fp, ECTF_NEEDSBFD);
-  return -1;
+  return ctf_set_errno (fp, ECTF_NEEDSBFD);
 #endif
 
   /* Having no CTF sections is not an error.  We just don't need to do
@@ -257,8 +256,7 @@ ctf_link_lazy_open (ctf_dict_t *fp, ctf_link_input_t *input)
 
       ctf_err_warn (fp, 0, err, _("opening CTF %s failed"),
 		    input->clin_filename);
-      ctf_set_errno (fp, err);
-      return -1;
+      return ctf_set_errno (fp, err);
     }
 
   if ((count = ctf_archive_count (input->clin_arc)) == 0)
@@ -680,8 +678,7 @@ ctf_link_deduplicating_count_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names,
     {
       ctf_err_warn (fp, 0, err, _("iteration error counting deduplicating "
 				  "CTF link inputs"));
-      ctf_set_errno (fp, err);
-      return -1;
+      return ctf_set_errno (fp, err);
     }
 
   if (!count)
@@ -1355,8 +1352,7 @@ ctf_link_empty_outputs (ctf_dict_t *fp)
     {
       fp->ctf_flags &= ~LCTF_LINKING;
       ctf_err_warn (fp, 1, err, _("iteration error removing old outputs"));
-      ctf_set_errno (fp, err);
-      return -1;
+      return ctf_set_errno (fp, err);
     }
   return 0;
 }
@@ -1536,8 +1532,7 @@ ctf_link (ctf_dict_t *fp, int flags)
 	{
 	  fp->ctf_flags &= ~LCTF_LINKING;
 	  ctf_err_warn (fp, 1, err, _("iteration error creating empty CUs"));
-	  ctf_set_errno (fp, err);
-	  return -1;
+	  return ctf_set_errno (fp, err);
 	}
     }
 
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index c65849118cb..177cb1b9840 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -143,7 +143,7 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
   ctf_id_t ntype, ptype;
 
   if (name == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_typed_errno (fp, EINVAL));
 
   for (p = name, end = name + strlen (name); *p != '\0'; p = q)
     {
@@ -273,10 +273,7 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
 		  free (fp->ctf_tmp_typeslice);
 		  fp->ctf_tmp_typeslice = xstrndup (p, (size_t) (q - p));
 		  if (fp->ctf_tmp_typeslice == NULL)
-		    {
-		      ctf_set_errno (fp, ENOMEM);
-		      return CTF_ERR;
-		    }
+		    return ctf_set_typed_errno (fp, ENOMEM);
 		}
 
 	      if ((type = ctf_lookup_by_rawhash (fp, lp->ctl_hash,
@@ -292,7 +289,7 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
     }
 
   if (*p != '\0' || type == 0)
-    return (ctf_set_errno (fp, ECTF_SYNTAX));
+    return (ctf_set_typed_errno (fp, ECTF_SYNTAX));
 
   return type;
 
@@ -306,13 +303,13 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
       if (fp->ctf_pptrtab_typemax < fp->ctf_typemax)
 	{
 	  if (refresh_pptrtab (fp, fp->ctf_parent) < 0)
-	    return -1;			/* errno is set for us.  */
+	    return CTF_ERR;			/* errno is set for us.  */
 	}
 
       if ((ptype = ctf_lookup_by_name_internal (fp->ctf_parent, fp,
 						name)) != CTF_ERR)
 	return ptype;
-      return (ctf_set_errno (fp, ctf_errno (fp->ctf_parent)));
+      return (ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent)));
     }
 
   return CTF_ERR;
@@ -407,10 +404,10 @@ ctf_lookup_variable (ctf_dict_t *fp, const char *name)
 
           if ((ptype = ctf_lookup_variable (fp->ctf_parent, name)) != CTF_ERR)
             return ptype;
-          return (ctf_set_errno (fp, ctf_errno (fp->ctf_parent)));
+          return (ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent)));
         }
 
-      return (ctf_set_errno (fp, ECTF_NOTYPEDAT));
+      return (ctf_set_typed_errno (fp, ECTF_NOTYPEDAT));
     }
 
   return ent->ctv_type;
@@ -673,7 +670,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	return ctf_set_typed_errno (fp, ENOMEM);
 
       i->cu.ctn_fp = fp;
       i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next;
@@ -682,10 +679,10 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
     }
 
   if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN));
 
   if (fp != i->cu.ctn_fp)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
 
   /* We intentionally use raw access, not ctf_lookup_by_symbol, to avoid
      incurring additional sorting cost for unsorted symtypetabs coming from the
@@ -701,7 +698,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
       if (!dynh)
 	{
 	  ctf_next_destroy (i);
-	  return (ctf_set_errno (fp, ECTF_NEXT_END));
+	  return (ctf_set_typed_errno (fp, ECTF_NEXT_END));
 	}
 
       err = ctf_dynhash_next (dynh, &i->ctn_next, &dyn_name, &dyn_value);
@@ -710,7 +707,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
 	{
 	  ctf_next_destroy (i);
 	  *it = NULL;
-	  return ctf_set_errno (fp, err);
+	  return ctf_set_typed_errno (fp, err);
 	}
 
       *name = dyn_name;
@@ -786,7 +783,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
  end:
   ctf_next_destroy (i);
   *it = NULL;
-  return (ctf_set_errno (fp, ECTF_NEXT_END));
+  return (ctf_set_typed_errno (fp, ECTF_NEXT_END));
 }
 
 /* A bsearch function for function and object index names.  */
@@ -821,7 +818,7 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 	       "indexed symtypetab\n", symidx, symname);
 
   if (symname[0] == '\0')
-    return -1;					/* errno is set for us.  */
+    return CTF_ERR;					/* errno is set for us.  */
 
   if (is_function)
     {
@@ -835,7 +832,7 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 	      == NULL)
 	    {
 	      ctf_err_warn (fp, 0, 0, _("cannot sort function symidx"));
-	      return -1;				/* errno is set for us.  */
+	      return CTF_ERR;				/* errno is set for us.  */
 	    }
 	}
       symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff);
@@ -855,7 +852,7 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 	      == NULL)
 	    {
 	      ctf_err_warn (fp, 0, 0, _("cannot sort object symidx"));
-	      return -1;				/* errno is set for us. */
+	      return CTF_ERR;				/* errno is set for us. */
 	    }
 	}
 
@@ -878,7 +875,7 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
 
   /* Should be impossible, but be paranoid.  */
   if ((idx - sxlate) > (ptrdiff_t) nidx)
-    return (ctf_set_errno (fp, ECTF_CORRUPT));
+    return (ctf_set_typed_errno (fp, ECTF_CORRUPT));
 
   ctf_dprintf ("Symbol %lx (%s) is of type %x\n", symidx, symname,
 	       symtypetab[*idx]);
@@ -1014,7 +1011,7 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
       return ret;
     }
   else
-    return (ctf_set_errno (fp, err));
+    return (ctf_set_typed_errno (fp, err));
 }
 
 /* Given a symbol table index, return the type of the function or data object
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index c20ff825d9a..694d6ea79e4 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -426,7 +426,7 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	return ctf_set_typed_errno (fp, ENOMEM);
 
       i->cu.ctn_fp = fp;
       i->ctn_type = 1;
@@ -435,10 +435,10 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
     }
 
   if ((void (*) (void)) ctf_type_next != i->ctn_iter_fun)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN));
 
   if (fp != i->cu.ctn_fp)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
 
   while (i->ctn_type <= fp->ctf_typemax)
     {
@@ -456,7 +456,7 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
     }
   ctf_next_destroy (i);
   *it = NULL;
-  return ctf_set_errno (fp, ECTF_NEXT_END);
+  return ctf_set_typed_errno (fp, ECTF_NEXT_END);
 }
 
 /* Iterate over every variable in the given CTF dict, in arbitrary order.
@@ -494,12 +494,12 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
   ctf_next_t *i = *it;
 
   if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parent == NULL))
-    return (ctf_set_errno (fp, ECTF_NOPARENT));
+    return (ctf_set_typed_errno (fp, ECTF_NOPARENT));
 
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	return ctf_set_typed_errno (fp, ENOMEM);
 
       i->cu.ctn_fp = fp;
       i->ctn_iter_fun = (void (*) (void)) ctf_variable_next;
@@ -509,10 +509,10 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
     }
 
   if ((void (*) (void)) ctf_variable_next != i->ctn_iter_fun)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN));
 
   if (fp != i->cu.ctn_fp)
-    return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
 
   if (!(fp->ctf_flags & LCTF_RDWR))
     {
@@ -538,7 +538,7 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
  end_iter:
   ctf_next_destroy (i);
   *it = NULL;
-  return ctf_set_errno (fp, ECTF_NEXT_END);
+  return ctf_set_typed_errno (fp, ECTF_NEXT_END);
 }
 
 /* Follow a given type through the graph for TYPEDEF, VOLATILE, CONST, and
@@ -560,7 +560,7 @@ ctf_type_resolve (ctf_dict_t *fp, ctf_id_t type)
   const ctf_type_t *tp;
 
   if (type == 0)
-    return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE));
+    return (ctf_set_typed_errno (ofp, ECTF_NONREPRESENTABLE));
 
   while ((tp = ctf_lookup_by_id (&fp, type)) != NULL)
     {
@@ -575,18 +575,18 @@ ctf_type_resolve (ctf_dict_t *fp, ctf_id_t type)
 	    {
 	      ctf_err_warn (ofp, 0, ECTF_CORRUPT, _("type %lx cycle detected"),
 			    otype);
-	      return (ctf_set_errno (ofp, ECTF_CORRUPT));
+	      return (ctf_set_typed_errno (ofp, ECTF_CORRUPT));
 	    }
 	  prev = type;
 	  type = tp->ctt_type;
 	  break;
 	case CTF_K_UNKNOWN:
-	  return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE));
+	  return (ctf_set_typed_errno (ofp, ECTF_NONREPRESENTABLE));
 	default:
 	  return type;
 	}
       if (type == 0)
-	return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE));
+	return (ctf_set_typed_errno (ofp, ECTF_NONREPRESENTABLE));
     }
 
   return CTF_ERR;		/* errno is set for us.  */
@@ -612,7 +612,7 @@ ctf_type_resolve_unsliced (ctf_dict_t *fp, ctf_id_t type)
       ctf_id_t ret;
 
       if ((ret = ctf_type_reference (fp, type)) == CTF_ERR)
-	return (ctf_set_errno (ofp, ctf_errno (fp)));
+	return (ctf_set_typed_errno (ofp, ctf_errno (fp)));
       return ret;
     }
   return type;
@@ -854,7 +854,7 @@ ctf_type_lname (ctf_dict_t *fp, ctf_id_t type, char *buf, size_t len)
   size_t slen;
 
   if (str == NULL)
-    return CTF_ERR;			/* errno is set for us.  */
+    return -1;			/* errno is set for us.  */
 
   slen = strlen (str);
   snprintf (buf, len, "%s", str);
@@ -1139,7 +1139,7 @@ ctf_type_reference (ctf_dict_t *fp, ctf_id_t type)
 	return sp->cts_type;
       }
     default:
-      return (ctf_set_errno (ofp, ECTF_NOTREF));
+      return (ctf_set_typed_errno (ofp, ECTF_NOTREF));
     }
 }
 
@@ -1164,15 +1164,15 @@ ctf_type_pointer (ctf_dict_t *fp, ctf_id_t type)
     return (LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD)));
 
   if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
-    return (ctf_set_errno (ofp, ECTF_NOTYPE));
+    return (ctf_set_typed_errno (ofp, ECTF_NOTYPE));
 
   if (ctf_lookup_by_id (&fp, type) == NULL)
-    return (ctf_set_errno (ofp, ECTF_NOTYPE));
+    return (ctf_set_typed_errno (ofp, ECTF_NOTYPE));
 
   if ((ntype = fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, type)]) != 0)
     return (LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD)));
 
-  return (ctf_set_errno (ofp, ECTF_NOTYPE));
+  return (ctf_set_typed_errno (ofp, ECTF_NOTYPE));
 }
 
 /* Return the encoding for the specified INTEGER, FLOAT, or ENUM.  */
@@ -1535,10 +1535,7 @@ ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp)
     return -1;			/* errno is set for us.  */
 
   if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM)
-    {
-      (void) ctf_set_errno (ofp, ECTF_NOTENUM);
-      return -1;
-    }
+    return ctf_set_errno (ofp, ECTF_NOTENUM);
 
   ctf_get_ctt_size (fp, tp, NULL, &increment);
 
@@ -1557,8 +1554,7 @@ ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp)
 	}
     }
 
-  ctf_set_errno (ofp, ECTF_NOENUMNAM);
-  return -1;
+  return ctf_set_errno (ofp, ECTF_NOENUMNAM);
 }
 
 /* Given a type ID relating to a function type, return info on return types and
diff --git a/libctf/ctf-util.c b/libctf/ctf-util.c
index 9f83ab9ab0b..e0d412df390 100644
--- a/libctf/ctf-util.c
+++ b/libctf/ctf-util.c
@@ -255,16 +255,6 @@ ctf_set_open_errno (int *errp, int error)
   return NULL;
 }
 
-/* Store the specified error code into the CTF dict, and then return CTF_ERR /
-   -1 for the benefit of the caller. */
-
-unsigned long
-ctf_set_errno (ctf_dict_t *fp, int err)
-{
-  fp->ctf_errno = err;
-  return CTF_ERR;
-}
-
 /* Create a ctf_next_t.  */
 
 ctf_next_t *
-- 
2.25.1


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

* Re: [PATCH] libctf: check for problems with error returns
  2023-10-15 19:18                                               ` Nick Alcock
  2023-10-16 12:51                                                 ` [PATCH v8] libctf: Sanitize error types for PR 30836 Torbjörn SVENSSON
@ 2023-10-16 13:02                                                 ` Torbjorn SVENSSON
  2023-10-17 14:45                                                   ` Nick Alcock
  1 sibling, 1 reply; 41+ messages in thread
From: Torbjorn SVENSSON @ 2023-10-16 13:02 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils, yvan.roux



On 2023-10-15 21:18, Nick Alcock wrote:
> On 13 Oct 2023, Torbjorn SVENSSON told this:
> 
>> Hi Nick,
>>
>> Thanks for validating this patch!
>>
>> On 2023-10-13 16:01, Nick Alcock wrote:
>>> We do this as a writable test because the only known-affected platforms
>>> (with ssize_t longer than unsigned long) use PE, and we do not have support
>>> for CTF linkage in the PE linker yet.
>>
>> Is it visible in PE too or only PE32+? Maybe not important, but the
>> Arm built variant does not trigger the fault (same source tree as I
>> found the issue in, but they build 32-bit and I build 64-bit) when
>> I've executed the GCC testsuite.
> 
> The underlying fault is client-side and is visible in anything that does
> a ctf_member_next on a platform with sizeof(ssize_t) > sizeof(unsigned
> long). The specific instance you saw (a hanging linker) requires CTF in
> the input and a linker that deduplicates it, and right now that is ELF
> only (because it was painful enough to add that I didn't have the
> stamina to add anything else -- if anything else *is* added, it will
> probably be PE next, but right now linking PE just blindly concatenates
> CTF sections, which isn't very useful).

Right.

> 
>>> 	PR libctf/30836
>>> 	* libctf/testsuite/libctf-writable/libctf-errors.*: New test.
>>> ---
>>>    .../testsuite/libctf-writable/libctf-errors.c | 74 +++++++++++++++++++
>>>    .../libctf-writable/libctf-errors.lk          |  1 +
>>>    2 files changed, 75 insertions(+)
>>>    create mode 100644 libctf/testsuite/libctf-writable/libctf-errors.c
>>>    create mode 100644 libctf/testsuite/libctf-writable/libctf-errors.lk
>>> Your patch looks good, and passes every test I can throw at it. I think
>>> it can go in.  You cleaned up a bunch of outright errors in this area,
>>> too, especially in ctf-dedup: thanks!
>>
>> There is still some potential for cleanup as some functions are
>> returning "unsigned long", but think it should perhaps be ctf_id_t
>> instead.
> 
> The only one of those i can see is ctf_lookup_symbol_idx. That's
> returning a symbol index, not a type ID, so should definitely not be
> returning a ctf_id_t. Perhaps it should be an int, but I'm not sure how
> big symbol tables in the set of all executable formats can actually
> be...
> 
> Hm, actually, there is one bit you might want to adjust in ctf-lookup.c.
> You fixed one call to ctf_lookup_symbol_idx () in
> ctf_lookup_by_sym_or_name ():
> 
>      if ((symidx = ctf_lookup_symbol_idx (fp, symname)) == (unsigned long) -1)
>        goto try_parent;
> 
> but the other one, in ctf_lookup_symbol_idx () itself (doing a recursive
> call to check parent dicts), still says
> 
>        if ((psym = ctf_lookup_symbol_idx (fp->ctf_parent, symname))
>            != CTF_ERR)
> 
> Both symidx and psym are unsigned long variables, so probably both
> should be checking against (unsigned long) -1.

Thanks for the pointer. I found that I had replaced some (unsigned 
long)-1 with CTF_ERR that should be exactly that. V8 is reverting those 
chunks to be like they were before.

>>> (You probably want to adjust the commit log so that the version history
>>> is at the bottom rather than the top, or drop it entirely.)
>>
>> My plan was to drop that part.
> 
> Aha right.
> 
>> Do you think I should have a changelog entry for the commit and if so,
>> what should I write in it? Should I list every function that is
>> touched (more or less half of the ctf_* functions defined...) or is
>> there some better way to document this change?
> 
> You can just say
> 
> 	Affected functions adjusted.
> 
> or something. A giant list adds no value, I think.

I tried to compile an exhaustive list, but it was too big for my taste, 
so I went with your proposal (part of V8).

> 
>>> Here's a testcase that fails on mingw64 in the absence of your patch,
>>> without requiring a cross-build to an ELF arch.  (It also checks at
>>> least one instance of the other classes of error return in libctf.)
>>> I'll push this after your commit goes in.  (I can push it, with an
>>> adjusted commit log, if you want.
>>
>> Fine either way. Either reply to my question about changelog or just merge it with the correct answer :)
> 
> ... I think there's one more tiny change :/
> 
>>> +  /* Third error class: ssize_t return.  Create a type to iterate over first.  */
>>> +
>>> +  if ((itype = ctf_add_integer (fp, CTF_ADD_ROOT, "int", &encoding)) == CTF_ERR)
>>> +    fprintf (stderr, "cannot add int: %s\n", ctf_errmsg (ctf_errno (fp)));
>>> +  else if ((stype = ctf_add_struct (fp, CTF_ADD_ROOT, "foo")) == CTF_ERR)
>>> +    fprintf (stderr, "cannot add struct: %s\n", ctf_errmsg (ctf_errno (fp)));
>>> +  else if (ctf_add_member (fp, stype, "bar", itype) < 0)
>>> +    fprintf (stderr, "cannot add member: %s\n", ctf_errmsg (ctf_errno (fp)));
>>
>> Should these be if-else-if-else-if-statments like above or just 3 "free-standing" if-statements? I.e. should the 3 potential issue
>> be visible in the same run or should they require 3 consecutive runs if all of them are failing?
> 
> I was wondering if this was too clever (or unclear!) but the intent is
> to only do the later things if the earlier ones didn't fail, i.e. what
> would be foo || bar || baz in the shell. (Later operations will also
> fail if any of them fail, but the fprintf's from the first failure will
> suffice to make the whole test fail -- so maybe it's safe to just do
> them in sequence even if the earlier ones failed. Excessive paranoia on
> my part perhaps, given that we don't *expect* any of these to fail: it's
> just setting things up for the *actual* tests, of ctf_member_info and
> ctf_member_next.)
> 
>>> +  if (ctf_member_info (fp, stype, "bar", &mi) < 0)
>>> +    fprintf (stderr, "cannot get member info: %s\n", ctf_errmsg (ctf_errno (fp)));
>>> +
>>> +  /* Iteration should never produce an offset bigger than the offset just returned,
>>> +     and should quickly terminate.  */
>>> +
>>> +  while ((ret = ctf_member_next (fp, stype, &i, NULL, NULL, 0)) >= 0) {
>>> +    if (ret > mi.ctm_offset)
>>> +      fprintf (stderr, "ssize_t return: unexpected offset: %zi\n", ret);
> 
> (here.)

Ah, okay. In any case, I think it would be clearer if you get all the 
lines in one go that fails than just the first one (in case of multiple 
failures...). - But, that's only my 2 cents.


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

* Re: [PATCH] libctf: check for problems with error returns
  2023-10-16 13:02                                                 ` [PATCH] libctf: check for problems with error returns Torbjorn SVENSSON
@ 2023-10-17 14:45                                                   ` Nick Alcock
  0 siblings, 0 replies; 41+ messages in thread
From: Nick Alcock @ 2023-10-17 14:45 UTC (permalink / raw)
  To: Torbjorn SVENSSON; +Cc: binutils, yvan.roux

On 16 Oct 2023, Torbjorn SVENSSON told this:
> On 2023-10-15 21:18, Nick Alcock wrote:
>>>> +  if (ctf_member_info (fp, stype, "bar", &mi) < 0)
>>>> +    fprintf (stderr, "cannot get member info: %s\n", ctf_errmsg (ctf_errno (fp)));
>>>> +
>>>> +  /* Iteration should never produce an offset bigger than the offset just returned,
>>>> +     and should quickly terminate.  */
>>>> +
>>>> +  while ((ret = ctf_member_next (fp, stype, &i, NULL, NULL, 0)) >= 0) {
>>>> +    if (ret > mi.ctm_offset)
>>>> +      fprintf (stderr, "ssize_t return: unexpected offset: %zi\n", ret);
>> (here.)
>
> Ah, okay. In any case, I think it would be clearer if you get all the lines in one go that fails than just the first one (in case of
> multiple failures...). - But, that's only my 2 cents.

We do that for failures that actually relate to what's being tested, but
these lines are only setup, and each depends on the one before: if any
fail, all the ones after it are certain to.

I think I might change it to not do the actual tests if we can't do the
setup, though!

I'll give v8 a quick sanity check: more in about an hour.

-- 
NULL && (void)

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

* Re: [PATCH v8] libctf: Sanitize error types for PR 30836
  2023-10-16 12:51                                                 ` [PATCH v8] libctf: Sanitize error types for PR 30836 Torbjörn SVENSSON
@ 2023-10-17 15:15                                                   ` Nick Alcock
  2023-10-17 15:35                                                     ` Torbjorn SVENSSON
  0 siblings, 1 reply; 41+ messages in thread
From: Nick Alcock @ 2023-10-17 15:15 UTC (permalink / raw)
  To: Torbjörn SVENSSON; +Cc: binutils, nick.alcock, amodra, Yvan ROUX

On 16 Oct 2023, Torbjörn SVENSSON told this:

> Made sure there is no implicit conversion between signed and unsigned
> return value for functions setting the ctf_errno value.
> An example of the problem is that in ctf_member_next, the "offset" value
> is either 0L or (ctf_id_t)-1L, but it should have been 0L or -1L.
> The issue was discovered while building a 64 bit ld binary to be
> executed on the Windows platform.
> Example object file that demonstrates the issue is attached in the PR.
>
> libctf/
> 	Affected functions adjusted.
>
> Signed-off-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
> Co-Authored-By: Yvan ROUX <yvan.roux@foss.st.com>

Looks good to me! I'll push my test for this after your fix goes in.

-- 
NULL && (void)

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

* Re: [PATCH v8] libctf: Sanitize error types for PR 30836
  2023-10-17 15:15                                                   ` Nick Alcock
@ 2023-10-17 15:35                                                     ` Torbjorn SVENSSON
  2023-10-17 18:54                                                       ` [PATCH] libctf: Return CTF_ERR in ctf_type_resolve_unsliced " Torbjörn SVENSSON
  0 siblings, 1 reply; 41+ messages in thread
From: Torbjorn SVENSSON @ 2023-10-17 15:35 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils, amodra, Yvan ROUX



On 2023-10-17 17:15, Nick Alcock wrote:
> On 16 Oct 2023, Torbjörn SVENSSON told this:
> 
>> Made sure there is no implicit conversion between signed and unsigned
>> return value for functions setting the ctf_errno value.
>> An example of the problem is that in ctf_member_next, the "offset" value
>> is either 0L or (ctf_id_t)-1L, but it should have been 0L or -1L.
>> The issue was discovered while building a 64 bit ld binary to be
>> executed on the Windows platform.
>> Example object file that demonstrates the issue is attached in the PR.
>>
>> libctf/
>> 	Affected functions adjusted.
>>
>> Signed-off-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
>> Co-Authored-By: Yvan ROUX <yvan.roux@foss.st.com>
> 
> Looks good to me! I'll push my test for this after your fix goes in.
> 

Thanks Nick for your review and test effort.

Pushed.

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

* [PATCH] libctf: Return CTF_ERR in ctf_type_resolve_unsliced PR 30836
  2023-10-17 15:35                                                     ` Torbjorn SVENSSON
@ 2023-10-17 18:54                                                       ` Torbjörn SVENSSON
  2023-10-17 19:40                                                         ` Nick Alcock
  0 siblings, 1 reply; 41+ messages in thread
From: Torbjörn SVENSSON @ 2023-10-17 18:54 UTC (permalink / raw)
  To: binutils, nick.alcock; +Cc: Torbjörn SVENSSON

There were one more place where the incorrect return value was used.

@Nick: Ok for trunk? :)

--

In commit 998a4f589d68503f79695f180fdf1742eeb0a39d, all but one return
statement was updated to return the error proper value. This commit
rectifies that missed return statement.

libctf/
	ctf-types.c (ctf_type_resolve_unsliced): Return CTF_ERR on error.

Signed-off-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
---
 libctf/ctf-types.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index 694d6ea79e4..4d3c01dbbb4 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -602,7 +602,7 @@ ctf_type_resolve_unsliced (ctf_dict_t *fp, ctf_id_t type)
   const ctf_type_t *tp;
 
   if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
-    return -1;
+    return CTF_ERR;
 
   if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
     return CTF_ERR;		/* errno is set for us.  */
-- 
2.25.1


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

* Re: [PATCH] libctf: Return CTF_ERR in ctf_type_resolve_unsliced PR 30836
  2023-10-17 18:54                                                       ` [PATCH] libctf: Return CTF_ERR in ctf_type_resolve_unsliced " Torbjörn SVENSSON
@ 2023-10-17 19:40                                                         ` Nick Alcock
  2023-10-18  7:40                                                           ` Torbjorn SVENSSON
  0 siblings, 1 reply; 41+ messages in thread
From: Nick Alcock @ 2023-10-17 19:40 UTC (permalink / raw)
  To: Torbjörn SVENSSON; +Cc: binutils, nick.alcock

On 17 Oct 2023, Torbjörn SVENSSON uttered the following:

> There were one more place where the incorrect return value was used.
>
> @Nick: Ok for trunk? :)

By all means: push away. Dead obvious too, right above a correct one,
and I still overlooked it.

(I just checked for further instances of this in ctf-types.c and could
see none.)

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

* Re: [PATCH] libctf: Return CTF_ERR in ctf_type_resolve_unsliced PR 30836
  2023-10-17 19:40                                                         ` Nick Alcock
@ 2023-10-18  7:40                                                           ` Torbjorn SVENSSON
  2023-10-20 17:01                                                             ` Nick Alcock
  0 siblings, 1 reply; 41+ messages in thread
From: Torbjorn SVENSSON @ 2023-10-18  7:40 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils



On 2023-10-17 21:40, Nick Alcock wrote:
> On 17 Oct 2023, Torbjörn SVENSSON uttered the following:
> 
>> There were one more place where the incorrect return value was used.
>>
>> @Nick: Ok for trunk? :)
> 
> By all means: push away. Dead obvious too, right above a correct one,
> and I still overlooked it.
> 
> (I just checked for further instances of this in ctf-types.c and could
> see none.)

Pushed.

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

* Re: [PATCH] libctf: Return CTF_ERR in ctf_type_resolve_unsliced PR 30836
  2023-10-18  7:40                                                           ` Torbjorn SVENSSON
@ 2023-10-20 17:01                                                             ` Nick Alcock
  0 siblings, 0 replies; 41+ messages in thread
From: Nick Alcock @ 2023-10-20 17:01 UTC (permalink / raw)
  To: Torbjorn SVENSSON; +Cc: binutils

On 18 Oct 2023, Torbjorn SVENSSON stated:

>
>
> On 2023-10-17 21:40, Nick Alcock wrote:
>> On 17 Oct 2023, Torbjörn SVENSSON uttered the following:
>> 
>>> There were one more place where the incorrect return value was used.
>>>
>>> @Nick: Ok for trunk? :)
>> By all means: push away. Dead obvious too, right above a correct one,
>> and I still overlooked it.
>> (I just checked for further instances of this in ctf-types.c and could
>> see none.)
>
> Pushed.

... as is the testcase.

-- 
NULL && (void)

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

* Re: [PATCH] libctf: check for problems with error returns
  2023-10-13 14:01                                           ` [PATCH] libctf: check for problems with error returns Nick Alcock
  2023-10-13 18:31                                             ` Torbjorn SVENSSON
@ 2024-01-30 12:46                                             ` Andreas Schwab
  2024-01-30 14:22                                               ` Nick Alcock
  1 sibling, 1 reply; 41+ messages in thread
From: Andreas Schwab @ 2024-01-30 12:46 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils, torbjorn.svensson, yvan.roux

./libtool --quiet --tag=CC --mode=link gcc -fmessage-length=0 -grecord-gcc-switches -O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector-strong -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -g -Wno-error   -I../../libctf/../include -I../../libctf -I. -I./../bfd  /home/abuild/rpmbuild/BUILD/binutils-2.42/libctf/testsuite/libctf-writable/libctf-errors.c -o tmpdir/lookup libctf.la
/home/abuild/rpmbuild/BUILD/binutils-2.42/libctf/testsuite/libctf-writable/libctf-errors.c: In function 'main':
/home/abuild/rpmbuild/BUILD/binutils-2.42/libctf/testsuite/libctf-writable/libctf-errors.c:54:9: warning: 'stype' may be used uninitialized in this function [-Wmaybe-uninitialized]
   while ((ret = ctf_member_next (fp, stype, &i, NULL, NULL, 0)) >= 0) {
         ^
compilation of lookup program /home/abuild/rpmbuild/BUILD/binutils-2.42/libctf/testsuite/libctf-writable/libctf-errors.c failed with </home/abuild/rpmbuild/BUILD/binutils-2.42/libctf/testsuite/libctf-writable/libctf-errors.c: In function 'main':
/home/abuild/rpmbuild/BUILD/binutils-2.42/libctf/testsuite/libctf-writable/libctf-errors.c:54:9: warning: 'stype' may be used uninitialized in this function [-Wmaybe-uninitialized]
   while ((ret = ctf_member_next (fp, stype, &i, NULL, NULL, 0)) >= 0) {
         ^>ERROR: compilation of lookup program /home/abuild/rpmbuild/BUILD/binutils-2.42/libctf/testsuite/libctf-writable/libctf-errors.c failed
UNRESOLVED: /home/abuild/rpmbuild/BUILD/binutils-2.42/libctf/testsuite/libctf-writable/libctf-errors.c

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

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

* Re: [PATCH] libctf: check for problems with error returns
  2024-01-30 12:46                                             ` Andreas Schwab
@ 2024-01-30 14:22                                               ` Nick Alcock
  2024-01-30 14:27                                                 ` Andreas Schwab
  0 siblings, 1 reply; 41+ messages in thread
From: Nick Alcock @ 2024-01-30 14:22 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: binutils, torbjorn.svensson, yvan.roux

On 30 Jan 2024, Andreas Schwab said:

> ./libtool --quiet --tag=CC --mode=link gcc -fmessage-length=0 -grecord-gcc-switches -O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector-strong -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -g -Wno-error   -I../../libctf/../include -I../../libctf -I. -I./../bfd  /home/abuild/rpmbuild/BUILD/binutils-2.42/libctf/testsuite/libctf-writable/libctf-errors.c -o tmpdir/lookup libctf.la
> /home/abuild/rpmbuild/BUILD/binutils-2.42/libctf/testsuite/libctf-writable/libctf-errors.c: In function 'main':
> /home/abuild/rpmbuild/BUILD/binutils-2.42/libctf/testsuite/libctf-writable/libctf-errors.c:54:9: warning: 'stype' may be used uninitialized in this function [-Wmaybe-uninitialized]
>    while ((ret = ctf_member_next (fp, stype, &i, NULL, NULL, 0)) >= 0) {
>          ^

Thanks! I was being sloppy on error paths and the compiler has spotted
my sin... will push the attached fix shortly, if your compiler is happy
(none of my compilers spot this one).

------------- >8 -----------
From 78fd0d4e60e8aed4c7396837d64cf1d1114b8c24 Mon Sep 17 00:00:00 2001
From: Nick Alcock <nick.alcock@oracle.com>
Date: Tue, 30 Jan 2024 14:18:54 +0000
Subject: [PATCH] libctf: fix uninitialized variables in testsuite

Just because a path is an error path doesn't mean the program terminates
there if you don't ask it to. (And we don't want to -- but that means
we need to initialize the variables that are missed if an error happens to
*something*. Type ID 0 (unimplemented) will do: it'll induce further
ECTF_BADID errors, but that's no bad thing.)
---
 libctf/testsuite/libctf-writable/libctf-errors.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libctf/testsuite/libctf-writable/libctf-errors.c b/libctf/testsuite/libctf-writable/libctf-errors.c
index 71f8268cfad..2790b608396 100644
--- a/libctf/testsuite/libctf-writable/libctf-errors.c
+++ b/libctf/testsuite/libctf-writable/libctf-errors.c
@@ -12,7 +12,7 @@ main (int argc, char *argv[])
   ctf_dict_t *fp;
   ctf_next_t *i = NULL;
   size_t boom = 0;
-  ctf_id_t itype, stype;
+  ctf_id_t itype = 0, stype = 0;
   ctf_encoding_t encoding = {0};
   ctf_membinfo_t mi;
   ssize_t ret;

base-commit: b960445a45981873c5b1718824ea9d3b5749433a
-- 
2.43.0.272.gce700b77fd

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

* Re: [PATCH] libctf: check for problems with error returns
  2024-01-30 14:22                                               ` Nick Alcock
@ 2024-01-30 14:27                                                 ` Andreas Schwab
  0 siblings, 0 replies; 41+ messages in thread
From: Andreas Schwab @ 2024-01-30 14:27 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils, torbjorn.svensson, yvan.roux

On Jan 30 2024, Nick Alcock wrote:

> diff --git a/libctf/testsuite/libctf-writable/libctf-errors.c b/libctf/testsuite/libctf-writable/libctf-errors.c
> index 71f8268cfad..2790b608396 100644
> --- a/libctf/testsuite/libctf-writable/libctf-errors.c
> +++ b/libctf/testsuite/libctf-writable/libctf-errors.c
> @@ -12,7 +12,7 @@ main (int argc, char *argv[])
>    ctf_dict_t *fp;
>    ctf_next_t *i = NULL;
>    size_t boom = 0;
> -  ctf_id_t itype, stype;
> +  ctf_id_t itype = 0, stype = 0;
>    ctf_encoding_t encoding = {0};
>    ctf_membinfo_t mi;
>    ssize_t ret;

This silences the warnings and all dependent tests pass.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

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

end of thread, other threads:[~2024-01-30 14:27 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-24 11:32 [PATCH] libctf: ctf_member_next needs to return (ssize_t)-1 on error Torbjörn SVENSSON
2023-08-25  2:22 ` Alan Modra
2023-08-25 16:53   ` [PATCH v2] " Torbjörn SVENSSON
2023-08-30  8:34     ` Torbjorn SVENSSON
2023-08-30  9:39       ` Alan Modra
2023-09-07 12:10         ` Nick Alcock
2023-09-08 12:58           ` Torbjorn SVENSSON
2023-09-12 14:23             ` Nick Alcock
2023-09-12 18:44               ` Torbjorn SVENSSON
2023-09-13  9:57               ` [PATCH v3] " Torbjörn SVENSSON
2023-09-13 18:37                 ` Nick Alcock
2023-09-13 20:20                   ` Torbjorn SVENSSON
2023-09-20 17:44                     ` Torbjorn SVENSSON
2023-09-26 14:51                     ` Nick Alcock
2023-09-26 17:28                       ` [PATCH v4] " Torbjörn SVENSSON
2023-09-26 17:49                       ` [PATCH v3] " Torbjorn SVENSSON
2023-09-28 16:41                         ` Nick Alcock
2023-09-29 12:11                           ` Torbjorn SVENSSON
2023-10-02 10:57                             ` Nick Alcock
2023-10-03 12:59                               ` Torbjorn SVENSSON
2023-10-03 20:53                                 ` Nick Alcock
2023-10-05  8:39                                   ` [PATCH v5] libctf: Sanitize error types for PR 30836 Torbjörn SVENSSON
2023-10-09 10:27                                     ` Nick Alcock
2023-10-09 14:44                                       ` [PATCH v6] " Torbjörn SVENSSON
2023-10-09 15:11                                         ` [PATCH v7] " Torbjörn SVENSSON
2023-10-11 11:14                                           ` Nick Alcock
2023-10-13 14:01                                           ` [PATCH] libctf: check for problems with error returns Nick Alcock
2023-10-13 18:31                                             ` Torbjorn SVENSSON
2023-10-15 19:18                                               ` Nick Alcock
2023-10-16 12:51                                                 ` [PATCH v8] libctf: Sanitize error types for PR 30836 Torbjörn SVENSSON
2023-10-17 15:15                                                   ` Nick Alcock
2023-10-17 15:35                                                     ` Torbjorn SVENSSON
2023-10-17 18:54                                                       ` [PATCH] libctf: Return CTF_ERR in ctf_type_resolve_unsliced " Torbjörn SVENSSON
2023-10-17 19:40                                                         ` Nick Alcock
2023-10-18  7:40                                                           ` Torbjorn SVENSSON
2023-10-20 17:01                                                             ` Nick Alcock
2023-10-16 13:02                                                 ` [PATCH] libctf: check for problems with error returns Torbjorn SVENSSON
2023-10-17 14:45                                                   ` Nick Alcock
2024-01-30 12:46                                             ` Andreas Schwab
2024-01-30 14:22                                               ` Nick Alcock
2024-01-30 14:27                                                 ` Andreas Schwab

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