+2021-03-02  Nick Alcock  <nick.alcock@oracle.com>
+
+       * ctf-dedup.c (ctf_dedup): Pass on errors from ctf_dedup_hash_type.
+       Call ctf_dedup_fini properly on other errors.
+       (ctf_dedup_emit_type): Set the errno on dynhash insertion failure.
+       * ctf-link.c (ctf_link_deduplicating_per_cu): Close outputs beyond
+       output 0 when asserting because >1 output is found.
+       (ctf_link_deduplicating): Likewise, when asserting because the
+       shared output is not the same as the passed-in fp.
+
 2021-03-02  Nick Alcock  <nick.alcock@oracle.com>
 
        * ctf-impl.h (ctf_dict_t) <ctf_link_type_mapping>: No longer used
 
 
       while ((id = ctf_type_next (inputs[i], &it, NULL, 1)) != CTF_ERR)
        {
-         ctf_dedup_hash_type (output, inputs[i], inputs, parents,
-                              i, id, 0, 0, ctf_dedup_populate_mappings);
+         if (ctf_dedup_hash_type (output, inputs[i], inputs,
+                                  parents, i, id, 0, 0,
+                                  ctf_dedup_populate_mappings) == NULL)
+           goto err;                           /* errno is set for us.  */
        }
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
        {
          ctf_set_errno (output, ctf_errno (inputs[i]));
          ctf_err_warn (output, 0, 0, _("iteration failure "
                                        "computing type hashes"));
-         return -1;
+         goto err;
        }
     }
 
 
   ctf_dprintf ("Detecting type name ambiguity\n");
   if (ctf_dedup_detect_name_ambiguity (output, inputs) < 0)
-    return -1;                                 /* errno is set for us.  */
+      goto err;                                        /* errno is set for us.  */
 
   /* If the link mode is CTF_LINK_SHARE_DUPLICATED, we change any unconflicting
      types whose output mapping references only one input dict into a
     {
       ctf_dprintf ("Conflictifying unshared types\n");
       if (ctf_dedup_conflictify_unshared (output, inputs) < 0)
-       return -1;                              /* errno is set for us.  */
+       goto err;                               /* errno is set for us.  */
     }
   return 0;
 
                     id, out_id);
        /* Record the need to emit the members of this structure later.  */
        if (ctf_dynhash_insert (d->cd_emission_struct_members, id, out_id) < 0)
-         goto err_target;
+         {
+           ctf_set_errno (target, errno);
+           goto err_target;
+         }
        break;
       }
     default:
 
          goto err_inputs;
        }
       if (!ctf_assert (fp, noutputs == 1))
-       goto err_inputs_outputs;
+       {
+         size_t j;
+         for (j = 1; j < noutputs; j++)
+           ctf_dict_close (outputs[j]);
+         goto err_inputs_outputs;
+       }
 
       if (!(fp->ctf_link_flags & CTF_LINK_OMIT_VARIABLES_SECTION)
          && ctf_link_deduplicating_variables (out, inputs, ninputs, 1) < 0)
     }
 
   if (!ctf_assert (fp, outputs[0] == fp))
-    goto err;
+    {
+      for (i = 1; i < noutputs; i++)
+       ctf_dict_close (outputs[i]);
+      goto err;
+    }
 
   for (i = 0; i < noutputs; i++)
     {