Browse Source

Fix various memory issues; pass partial tests.

Stefano Cossu 1 year ago
parent
commit
daa8f32d1e
7 changed files with 128 additions and 147 deletions
  1. 3 2
      include/codec.h
  2. 17 26
      src/codec/codec_nt.c
  3. 48 45
      src/codec/codec_ttl.c
  4. 48 61
      src/graph.c
  5. 3 3
      src/namespace.c
  6. 9 8
      src/term.c
  7. 0 2
      test/test_codec_nt.c

+ 3 - 2
include/codec.h

@@ -49,8 +49,9 @@ typedef struct parse_error_t {
  * @param[in] nsm Namespace map. May be NULL for no prefix shortening.
  *
  * @param[out] rep Pointer to a string to be filled with the encoded term. The
- *  caller is in charge of freeing the string after use. Returns undefined on
- *  error.
+ *  string is reallocated and, if reused for multiple calls to this function,
+ *  it only needs to be freed after the last call. It should be initialized to
+ *  NULL at the beginning.
  *
  * @return LSUP_OK on successful encoding; <0 for other errors.
  */

+ 17 - 26
src/codec/codec_nt.c

@@ -26,15 +26,12 @@ term_to_nt (const LSUP_Term *term, const LSUP_NSMap *nsm, char **out_p)
     const char *metadata = NULL;
     size_t buf_len;
 
-    // Free previous content if not NULL.
-    if (*out_p != NULL) out = realloc (*out_p, 0);
-
     char *data = term->data;
     switch (term->type) {
         case LSUP_TERM_NS_IRIREF:
             LSUP_nsmap_normalize_uri (nsm, term->data, &data);
         case LSUP_TERM_IRIREF:
-            out = realloc (out, strlen (data) + 3);
+            out = realloc (*out_p, strlen (data) + 3);
             if (UNLIKELY (!out)) return LSUP_MEM_ERR;
 
             sprintf (out, "<%s>", data);
@@ -57,7 +54,7 @@ term_to_nt (const LSUP_Term *term, const LSUP_NSMap *nsm, char **out_p)
                 buf_len += strlen (metadata) + 4; // Room for ^^<>
             }
 
-            out = realloc (out, buf_len);
+            out = realloc (*out_p, buf_len);
             if (UNLIKELY (!out)) return LSUP_MEM_ERR;
 
             sprintf (out, "\"%s\"", escaped);
@@ -82,7 +79,7 @@ term_to_nt (const LSUP_Term *term, const LSUP_NSMap *nsm, char **out_p)
                 buf_len += strlen (metadata) + 1; // Room for @
             }
 
-            out = realloc (out, buf_len);
+            out = realloc (*out_p, buf_len);
             if (UNLIKELY (!out)) return LSUP_MEM_ERR;
 
             sprintf (out, "\"%s\"", escaped);
@@ -96,7 +93,7 @@ term_to_nt (const LSUP_Term *term, const LSUP_NSMap *nsm, char **out_p)
             break;
 
         case LSUP_TERM_BNODE:
-            out = realloc (out, strlen (term->data) + 3);
+            out = realloc (*out_p, strlen (term->data) + 3);
             if (UNLIKELY (!out)) return LSUP_MEM_ERR;
 
             sprintf (out, "_:%s", term->data);
@@ -105,7 +102,7 @@ term_to_nt (const LSUP_Term *term, const LSUP_NSMap *nsm, char **out_p)
             break;
 
         default:
-            out = NULL;
+            out = *out_p;  // This is considered garbage.
             rc = LSUP_PARSE_ERR;
     }
 
@@ -115,7 +112,18 @@ term_to_nt (const LSUP_Term *term, const LSUP_NSMap *nsm, char **out_p)
 
 
 static void *
-gr_to_nt_init (const LSUP_Graph *gr);
+gr_to_nt_init (const LSUP_Graph *gr)
+{
+    LSUP_NTCodecIterator *it;
+    CALLOC_GUARD (it, NULL);
+
+    it->codec = &nt_codec;
+    it->gr_it = LSUP_graph_lookup(gr, NULL, NULL, NULL, &it->cur);
+    it->nsm = LSUP_graph_namespace (gr);
+    it->trp = TRP_DUMMY;
+
+    return it;
+}
 
 
 static LSUP_rc
@@ -179,20 +187,3 @@ const LSUP_Codec nt_codec = {
     .decode_term        = LSUP_nt_parse_term,
     .decode_graph       = LSUP_nt_parse_doc,
 };
-
-
-/* * * Other static functions. * * */
-
-static void *
-gr_to_nt_init (const LSUP_Graph *gr)
-{
-    LSUP_NTCodecIterator *it;
-    CALLOC_GUARD (it, NULL);
-
-    it->codec = &nt_codec;
-    it->gr_it = LSUP_graph_lookup(gr, NULL, NULL, NULL, &it->cur);
-    it->nsm = LSUP_graph_namespace (gr);
-    it->trp = TRP_DUMMY;
-
-    return it;
-}

+ 48 - 45
src/codec/codec_ttl.c

@@ -23,36 +23,38 @@ static LSUP_rc
 term_to_ttl (const LSUP_Term *term, const LSUP_NSMap *nsm, char **out_p)
 {
     LSUP_rc rc;
-    char *out = NULL, *escaped;
+    char *tmp = NULL, *out;
     char *metadata = NULL;
     size_t buf_len;
 
-    LSUP_rc md_rc;
+    LSUP_rc md_rc = LSUP_NORESULT;
     switch (term->type) {
         case LSUP_TERM_IRIREF:
-            md_rc = LSUP_nsmap_denormalize_uri (nsm, term->data, &out);
+            md_rc = LSUP_nsmap_denormalize_uri (nsm, term->data, &tmp);
             PRCCK (md_rc);
             if (md_rc == LSUP_NORESULT) {
                 // If URI counld not be shortened, add `<>`
-                char *tmp = realloc (out, strlen (out) + 2);
-                if (UNLIKELY (!tmp)) return LSUP_MEM_ERR;
-                out = tmp;
-                out = strcat (strcat (strcat (tmp, "<"), tmp), ">");
-            }
+                out = realloc (*out_p, strlen (tmp) + 3);
+                if (UNLIKELY (!out)) return LSUP_MEM_ERR;
+                sprintf (out, "<%s>", tmp);
+                free (tmp);
+
+            } else out = tmp;
             rc = LSUP_OK;
             break;
 
         case LSUP_TERM_NS_IRIREF:
-            out = strdup (term->data);
+            out = realloc (*out_p, strlen (term->data) + 1);
             if (UNLIKELY (!out)) return LSUP_MEM_ERR;
+            strcpy (out, term->data);
             rc = LSUP_OK;
             break;
 
         case LSUP_TERM_LITERAL:
             // Calculate string length.
-            if (escape_lit (term->data, &escaped) != LSUP_OK)
+            if (escape_lit (term->data, &tmp) != LSUP_OK)
                 return LSUP_ERROR;
-            buf_len = strlen (escaped) + 3; // Room for "" and terminator
+            buf_len = strlen (tmp) + 3; // Room for "" and terminator
 
             if (
                 term->datatype != 0
@@ -66,15 +68,17 @@ term_to_ttl (const LSUP_Term *term, const LSUP_NSMap *nsm, char **out_p)
                 buf_len += strlen (metadata) + padding;
             }
 
-            out = realloc (out, buf_len);
+            out = realloc (*out_p, buf_len);
             if (UNLIKELY (!out)) return LSUP_MEM_ERR;
 
-            sprintf (out, "\"%s\"", escaped);
-            free (escaped);
-
-            // Add datatype.
-            if (metadata)
-                out = strcat (strcat (strcat (out, "^^<"), metadata), ">");
+            if (metadata) {
+                char *fmt = (
+                        md_rc == LSUP_NORESULT ? "\"%s\"^^<%s>"
+                        : "\"%s\"^^%s");
+                sprintf (out, fmt, tmp, metadata);
+            }
+            else sprintf (out, "\"%s\"", tmp);
+            free (tmp);
 
             rc = LSUP_OK;
 
@@ -82,20 +86,20 @@ term_to_ttl (const LSUP_Term *term, const LSUP_NSMap *nsm, char **out_p)
 
         case LSUP_TERM_LT_LITERAL:
             // Calculate string length.
-            if (escape_lit (term->data, &escaped) != LSUP_OK)
+            if (escape_lit (term->data, &tmp) != LSUP_OK)
                 return LSUP_ERROR;
-            buf_len = strlen (escaped) + 3; // Room for "" and terminator
+            buf_len = strlen (tmp) + 3; // Room for "" and terminator
 
             if (term->lang[0] != '\0') {
                 metadata = strndup (term->lang, sizeof (LSUP_LangTag));
                 buf_len += strlen (metadata) + 1; // Room for @
             }
 
-            out = realloc (out, buf_len);
+            out = realloc (*out_p, buf_len);
             if (UNLIKELY (!out)) return LSUP_MEM_ERR;
 
-            sprintf (out, "\"%s\"", escaped);
-            free (escaped);
+            sprintf (out, "\"%s\"", tmp);
+            free (tmp);
 
             // Add lang.
             if (metadata) out = strcat (strcat (out, "@"), metadata);
@@ -105,7 +109,7 @@ term_to_ttl (const LSUP_Term *term, const LSUP_NSMap *nsm, char **out_p)
             break;
 
         case LSUP_TERM_BNODE:
-            out = realloc (out, strlen (term->data) + 3);
+            out = realloc (*out_p, strlen (term->data) + 3);
             if (UNLIKELY (!out)) return LSUP_MEM_ERR;
 
             sprintf (out, "_:%s", term->data);
@@ -114,7 +118,7 @@ term_to_ttl (const LSUP_Term *term, const LSUP_NSMap *nsm, char **out_p)
             break;
 
         default:
-            out = NULL;
+            out = *out_p;  // This is considered garbage.
             rc = LSUP_PARSE_ERR;
     }
     free (metadata);
@@ -148,22 +152,24 @@ build_prolog (LSUP_TTLCodecIterator *it, char **res_p)
     char *res = fmt_header ("# ");
 
     const char ***nsm = LSUP_nsmap_dump (LSUP_graph_namespace (it->gr));
-    const char *ns_tpl = "@prefix %s: <%s> .\n";
+    char *ns_tpl = "@prefix %s: <%s> .\n";
 
     // Prefix map.
     for (size_t i = 0; nsm[i]; i++) {
         const char **ns = nsm[i];
         size_t old_len = strlen (res);
         size_t ns_len = strlen (ns[0]) + strlen (ns[1]) + strlen (ns_tpl);
-        char *tmp = realloc (res, old_len + ns_len);
+        char *tmp = realloc (res, old_len + ns_len + 1);
         if (UNLIKELY (!tmp)) return LSUP_MEM_ERR;
         res = tmp;
 
         sprintf (res + old_len, ns_tpl, ns[0], ns[1]);
+        free (ns);
     }
+    free (nsm);
 
     // Base.
-    char *base_uri_str;
+    char *base_uri_str = NULL;
     LSUP_rc rc = LSUP_nsmap_denormalize_uri (
             LSUP_graph_namespace (it->gr), LSUP_graph_uri (it->gr)->data,
             &base_uri_str);
@@ -172,9 +178,11 @@ build_prolog (LSUP_TTLCodecIterator *it, char **res_p)
     char *base_stmt = malloc (strlen (base_stmt_tpl) + strlen (base_uri_str));
     if (!UNLIKELY (base_stmt)) return LSUP_MEM_ERR;
     sprintf (base_stmt, base_stmt_tpl, base_uri_str);
-    res = realloc (res, strlen (res) + strlen (base_stmt));
+    free (base_uri_str);
+    res = realloc (res, strlen (res) + strlen (base_stmt) + 1);
     if (!UNLIKELY (res)) return LSUP_MEM_ERR;
     res = strcat (res, base_stmt);
+    free (base_stmt);
 
     *res_p = res;
     it->rc = LSUP_OK;
@@ -191,7 +199,7 @@ gr_to_ttl_iter (void *h, char **res_p) {
     if (it->rc == LSUP_NORESULT) return build_prolog (it, res_p);
 
     LSUP_Term *s = NULL;
-    char *res = NULL;  // Result string.
+    char *res = *res_p;  // Result string will be reallocated.
     RCCK (LSUP_term_set_next (it->subjects, &it->s_cur, &s));
 
     term_to_ttl (s, LSUP_graph_namespace (it->gr), &res);
@@ -210,10 +218,7 @@ gr_to_ttl_iter (void *h, char **res_p) {
         RCCK (term_to_ttl (p, LSUP_graph_namespace (it->gr), &p_str));
         char *tmp = realloc (
                 res, strlen (res) + strlen (p_str) + strlen (p_join) + 1);
-        if (UNLIKELY (!tmp)) {
-            it->rc = LSUP_MEM_ERR;
-            goto finally;
-        }
+        if (UNLIKELY (!tmp)) goto memfail;
         res = strcat (strcat (tmp, p_join), p_str);
 
         free (p_str);
@@ -229,10 +234,7 @@ gr_to_ttl_iter (void *h, char **res_p) {
             RCCK (it->rc);
             char *tmp = realloc (
                     res, strlen (res) + strlen (o_str) + strlen (o_join) + 1);
-            if (UNLIKELY (!tmp)) {
-                it->rc = LSUP_MEM_ERR;
-                goto finally;
-            }
+            if (UNLIKELY (!tmp)) goto memfail;
             res = strcat (strcat (tmp, o_join), o_str);
             o_join = ", ";
         }
@@ -241,18 +243,19 @@ gr_to_ttl_iter (void *h, char **res_p) {
 
     char *s_sep = ".\n";
     char *tmp = realloc (res, strlen (res) + strlen (s_sep) + 1);
-    if (UNLIKELY (!tmp)) {
-        res = NULL;
-        it->rc = LSUP_MEM_ERR;
-        goto finally;
-    }
+    if (UNLIKELY (!tmp)) goto memfail;
 
-    *res_p = strcat (res, s_sep);
+    *res_p = strcat (tmp, s_sep);
 
-finally:
     LSUP_link_map_iter_free (lmit);
+    LSUP_link_map_free (lmap);
 
     return it->rc;
+
+memfail:
+    free (res);
+    *res_p = NULL;
+    return LSUP_MEM_ERR;
 }
 
 

+ 48 - 61
src/graph.c

@@ -19,6 +19,7 @@ struct graph_iter_t {
     const LSUP_Graph *      graph;          ///< Parent graph.
     void *                  data;           ///< Iterator state.
     size_t                  ct;             ///< Total lookup matches.
+    LSUP_BufferTriple *     sspo;           ///< Buffer triple for temp values.
 };
 
 
@@ -27,10 +28,10 @@ struct graph_iter_t {
  */
 
 inline static LSUP_rc
-graph_iter_next_buffer (LSUP_GraphIterator *it, LSUP_BufferTriple *sspo);
+graph_iter_next_buffer (LSUP_GraphIterator *it);
 
-inline static void
-graph_iter_free_buffer (LSUP_GraphIterator *it, LSUP_BufferTriple *sspo);
+inline static LSUP_rc
+graph_iter_alloc_buffers (LSUP_GraphIterator *it);
 
 
 #define ENTRY(a, b) (be) == (LSUP_STORE_##a) ||
@@ -413,6 +414,7 @@ LSUP_graph_lookup (
     }
 
     it->graph = gr;
+    RCNL (graph_iter_alloc_buffers (it));
 
     return it;
 }
@@ -421,21 +423,18 @@ LSUP_graph_lookup (
 LSUP_rc
 LSUP_graph_iter_next (LSUP_GraphIterator *it, LSUP_Triple *spo)
 {
-    LSUP_BufferTriple *sspo = BTRP_DUMMY;
-    LSUP_rc rc = graph_iter_next_buffer (it, sspo);
-
-    if (rc == LSUP_OK) {
-        spo->s = LSUP_term_new_from_buffer (sspo->s);
-        if (!spo->s) return LSUP_ERROR;
-        spo->p = LSUP_term_new_from_buffer (sspo->p);
-        if (!spo->p) return LSUP_ERROR;
-        spo->o = LSUP_term_new_from_buffer (sspo->o);
-        if (!spo->o) return LSUP_ERROR;
-    }
+    LSUP_rc rc = graph_iter_next_buffer (it);
+    PRCCK (rc);
+    if (rc != LSUP_OK) return rc;
 
-    graph_iter_free_buffer (it, sspo);
+    spo->s = LSUP_term_new_from_buffer (it->sspo->s);
+    if (!spo->s) return LSUP_ERROR;
+    spo->p = LSUP_term_new_from_buffer (it->sspo->p);
+    if (!spo->p) return LSUP_ERROR;
+    spo->o = LSUP_term_new_from_buffer (it->sspo->o);
+    if (!spo->o) return LSUP_ERROR;
 
-    return rc;
+    return LSUP_OK;
 }
 
 const LSUP_Graph *
@@ -447,6 +446,17 @@ void
 LSUP_graph_iter_free (LSUP_GraphIterator *it)
 {
     it->graph->store->sif->lu_free_fn (it->data);
+
+    /*
+     * This deallocates resources properly by preserving borrowed pointers from
+     * the store in case of LSUP_STORE_COW stores.
+     */
+    if (it->graph->store->sif->features & LSUP_STORE_COW) {
+        LSUP_btriple_free_shallow (it->sspo);
+    } else {
+        // TODO copy-on-retrieval stores. None yet.
+    }
+
     free (it);
 }
 
@@ -523,29 +533,18 @@ LSUP_graph_connections (
         return NULL;
     }
 
-    LSUP_GraphIterator *it = LSUP_graph_lookup (gr, s, p, o, NULL);
-
-    LSUP_LinkMap *ret = LSUP_link_map_new (type);
-    LSUP_BufferTriple *sspo = BTRP_DUMMY;
     // Gather all linking terms in a set first.
-    LSUP_TermSet *lts = LSUP_term_set_new();
-    while (graph_iter_next_buffer (it, sspo) != LSUP_END) {
-        LSUP_Term
-            *ex = NULL,
-            *ins = LSUP_term_new_from_buffer (LSUP_btriple_pos (sspo, pos2));
-        LSUP_term_set_add (lts, ins, &ex);
-
-        if (ex) LSUP_term_free (ins);
-    }
-    graph_iter_free_buffer (it, sspo);
-    LSUP_graph_iter_free(it);
+    LSUP_TermSet *lts = LSUP_graph_unique_terms (gr, pos2);
 
+    LSUP_LinkMap *ret = LSUP_link_map_new (type);
     size_t i = 0;
     LSUP_Term *lt;
     while (LSUP_term_set_next (lts, &i, &lt) != LSUP_END) {
         LSUP_link_map_add (
-                ret, lt, LSUP_graph_term_set (gr, t, pos1, lt, pos2));
+                ret, LSUP_term_copy (lt),
+                LSUP_graph_term_set (gr, t, pos1, lt, pos2));
     }
+    LSUP_term_set_free (lts);
 
     return ret;
 }
@@ -572,15 +571,13 @@ LSUP_graph_term_set (
             gr, spo_l[0], spo_l[1], spo_l[2], NULL);
 
     LSUP_TermSet *ts = LSUP_term_set_new();
-    LSUP_BufferTriple *sspo = BTRP_DUMMY;
-    while (graph_iter_next_buffer (it, sspo) != LSUP_END) {
+    while (graph_iter_next_buffer (it) != LSUP_END) {
         // There cannot be duplicates in a 2-bound lookup.
         LSUP_term_set_add (
                 ts,
-                LSUP_term_new_from_buffer (LSUP_btriple_pos (sspo, rpos)),
+                LSUP_term_new_from_buffer (LSUP_btriple_pos (it->sspo, rpos)),
                 NULL);
     }
-    graph_iter_free_buffer (it, sspo);
     LSUP_graph_iter_free (it);
 
     return ts;
@@ -593,12 +590,11 @@ LSUP_graph_unique_terms (const LSUP_Graph *gr, LSUP_TriplePos pos)
     // TODO We should use spo indices for stores that have them...
     LSUP_GraphIterator *it = LSUP_graph_lookup (gr, NULL, NULL, NULL, NULL);
 
-    LSUP_BufferTriple *sspo = BTRP_DUMMY;
     LSUP_TermSet *ts = LSUP_term_set_new();
-    while (graph_iter_next_buffer (it, sspo) != LSUP_END) {
+    while (graph_iter_next_buffer (it) != LSUP_END) {
         LSUP_Term
             *ex = NULL,
-            *ins = LSUP_term_new_from_buffer (LSUP_btriple_pos (sspo, pos));
+            *ins = LSUP_term_new_from_buffer (LSUP_btriple_pos (it->sspo, pos));
         LSUP_term_set_add (ts, ins, &ex);
 
         if (ex) LSUP_term_free (ins);
@@ -680,41 +676,32 @@ LSUP_bnode_add_collection (LSUP_GraphIterator *it, LSUP_TermSet *ts)
  */
 
 /** @brief Advance an iterator and return a serialized triple.
- *
- * The passed triple should be a LSUP_BTRP_DUMMY and must be freed with
- * graph_iter_free_buffer().
  *
  * This is an internal function to pass raw buffers between higher-level
  * functions without serializing and deserializing triples.
+ *
+ * The results are stored in it->sspo.
  */
 inline static LSUP_rc
-graph_iter_next_buffer (LSUP_GraphIterator *it, LSUP_BufferTriple *sspo)
-{
-    if (it->graph->store->sif->features & LSUP_STORE_COW) {
-        CALLOC_GUARD (sspo->s, LSUP_MEM_ERR);
-        CALLOC_GUARD (sspo->p, LSUP_MEM_ERR);
-        CALLOC_GUARD (sspo->o, LSUP_MEM_ERR);
-    } else {
-        // TODO copy-on-retrieval stores. None yet.
-    }
-
-    return it->graph->store->sif->lu_next_fn (it->data, sspo, NULL);
-}
+graph_iter_next_buffer (LSUP_GraphIterator *it)
+{ return it->graph->store->sif->lu_next_fn (it->data, it->sspo, NULL); }
 
 
-/** @brief Free a buffer obtained with #graph_iter_next_buffer().
- *
- * This deallocates resources properly by preserving borrowed pointers from the
- * store in case of LSUP_STORE_COW stores.
+/** @brief Properly allocate temporary byte buffers in advance of iteration.
  */
-static void
-graph_iter_free_buffer (LSUP_GraphIterator *it, LSUP_BufferTriple *sspo)
+inline LSUP_rc
+graph_iter_alloc_buffers (LSUP_GraphIterator *it)
 {
     if (it->graph->store->sif->features & LSUP_STORE_COW) {
-        LSUP_btriple_free_shallow (sspo);
+        it->sspo = BTRP_DUMMY;
+        CALLOC_GUARD (it->sspo->s, LSUP_MEM_ERR);
+        CALLOC_GUARD (it->sspo->p, LSUP_MEM_ERR);
+        CALLOC_GUARD (it->sspo->o, LSUP_MEM_ERR);
     } else {
         // TODO copy-on-retrieval stores. None yet.
     }
+
+    return LSUP_OK;
 }
 
 

+ 3 - 3
src/namespace.c

@@ -73,7 +73,7 @@ LSUP_nsmap_free (NSMap *map)
 LSUP_rc
 LSUP_nsmap_add (NSMap *map, const char *pfx, const char *nsstr)
 {
-    NSEntry entry_s;
+    NSEntry entry_s = {};
 
     if (strlen(pfx) >= PFX_LEN)
         log_warn(
@@ -104,7 +104,7 @@ LSUP_nsmap_add (NSMap *map, const char *pfx, const char *nsstr)
 LSUP_rc
 LSUP_nsmap_remove (NSMap *map, const char *pfx)
 {
-    NSEntry entry_s;
+    NSEntry entry_s = {};
     strncpy (entry_s.pfx, pfx, PFX_LEN - 1);
     NSEntry *entry = hashmap_delete (map, &entry_s);
 
@@ -119,7 +119,7 @@ LSUP_nsmap_remove (NSMap *map, const char *pfx)
 const char *
 LSUP_nsmap_get_ns (const NSMap *map, const char *pfx)
 {
-    NSEntry entry_s;
+    NSEntry entry_s = {};
     strncpy (entry_s.pfx, pfx, PFX_LEN - 1);
     NSEntry *entry = hashmap_get ((NSMap *)map, &entry_s);
 

+ 9 - 8
src/term.c

@@ -16,11 +16,12 @@
  * Data structures.
  */
 
+/// Matching sub-patterns for IRI parts.
 struct iri_info_t {
-    LSUP_NSMap *        nsm;        // NSM handle for prefixed IRI.
-    regmatch_t          prefix;     // Matching group #1.
-    regmatch_t          path;       // Matching group #5.
-    regmatch_t          frag;       // Matching group #10.
+    LSUP_NSMap *        nsm;        ///< NSM handle for prefixed IRI.
+    regmatch_t          prefix;     ///< Matching group #1.
+    regmatch_t          path;       ///< Matching group #5.
+    regmatch_t          frag;       ///< Matching group #10.
 };
 
 
@@ -45,8 +46,8 @@ typedef struct link {
 /// Opaque link map iterator.
 struct link_map_iter {
     const LSUP_LinkMap *map;        ///< Link map to iterate.
-    size_t              i;          ///< External loop cursor.
-    size_t              j;          ///< Internal loop cursor.
+    size_t              i;          ///< Linking term loop cursor.
+    size_t              j;          ///< Term set loop cursor.
     LSUP_Term *         ext;        ///< External link to look for connections.
     Link *              link;       ///< Current link being retrieved.
 };
@@ -532,9 +533,9 @@ LSUP_triple_free (LSUP_Triple *spo)
 LSUP_TermSet *
 LSUP_term_set_new ()
 {
-    // Capacity of 8 is an arbitrary guess.
+    // Capacity of 4 is an arbitrary guess.
     LSUP_TermSet *ts = hashmap_new (
-            sizeof (KeyedTerm), 8, LSUP_HASH_SEED, 0,
+            sizeof (KeyedTerm), 4, LSUP_HASH_SEED, 0,
             tset_hash_fn, tset_cmp_fn, tset_free_fn, NULL);
     if (UNLIKELY (hashmap_oom (ts))) return NULL;
 

+ 0 - 2
test/test_codec_nt.c

@@ -146,10 +146,8 @@ test_encode_nt_term()
     }
 
     EXPECT_INT_EQ (codec.encode_term (terms[8], NULL, &out), LSUP_PARSE_ERR);
-    ASSERT (out == NULL, "Encoding of undefined term should be NULL!");
 
     EXPECT_INT_EQ (codec.encode_term (terms[9], NULL, &out), LSUP_PARSE_ERR);
-    ASSERT (out == NULL, "Encoding of undefined term should be NULL!");
 
     free (out);
     LSUP_nsmap_free (nsm);