Browse Source

Resolve all memory issues; decoder is complete.

Stefano Cossu 2 years ago
parent
commit
a89a43c502
6 changed files with 113 additions and 88 deletions
  1. 6 3
      include/codec.h
  2. 10 0
      src/codec.c
  3. 83 77
      src/codec/grammar_ttl.y
  4. 2 2
      src/codec/lexer_ttl.re
  5. 6 6
      src/term.c
  6. 6 0
      test/test_codec_ttl.c

+ 6 - 3
include/codec.h

@@ -310,7 +310,8 @@ uint8_t *unescape_unicode (const uint8_t *esc_str, size_t size);
  *  handle should no longer be used. On failure, it remains unchanged and may
  *  be reused.
  *
- * @param[in] o Object to be added to the list.
+ * @param[in] o Object to be added to the list. The object list will take
+ *  ownership of the term.
  *
  * @return Reallocated list on success; NULL on failure.
  */
@@ -340,10 +341,12 @@ LSUP_pred_obj_list_free (LSUP_PredObjList *pol);
  * @param[in] pol Predicate-object list handle obtained with
  *  #LSUP_pred_obj_list_new().
  *
- *  @param[in] p Predicate to be associated with the given object list.
+ *  @param[in] p Predicate to be associated with the given object list. The
+ *   PO structure takes ownership of the term.
  *
  *  @param[in] o NULL-terminated array of object term handles to be associated
- *   with the given predicate. 
+ *   with the given predicate. The PO structire takes ownership of the whole
+ *   term array.
  *
  * @return LSUP_OK on success; LSUP_MEM_ERR on allocation error.
  */

+ 10 - 0
src/codec.c

@@ -76,6 +76,7 @@ LSUP_obj_list_add (LSUP_Term **ol, LSUP_Term *o)
     while (ol[i++]); // Count includes sentinel.
     LSUP_Term **ret = realloc (ol, sizeof (*ol) * (i + 1));
     if (!ret) return NULL;
+
     ret[i - 1] = o;
     ret[i] = NULL;
 
@@ -103,15 +104,24 @@ LSUP_pred_obj_list_new (void)
 void
 LSUP_pred_obj_list_free (LSUP_PredObjList *po)
 {
+    log_debug ("Freeing predicate object list.");
     for (size_t i = 0; po->p[i]; i++) {
+        // Free individual predicate handles.
         LSUP_term_free (po->p[i]);
     }
+    // Free pred list.
+    free (po->p);
 
     for (size_t i = 0; po->o[i]; i++) {
         for (size_t j = 0; po->o[i][j]; j++) {
+            // Free individual term handles.
             LSUP_term_free (po->o[i][j]);
         }
+        // Free object list.
+        free (po->o[i]);
     }
+    // Free list of object lists.
+    free (po->o);
 
     free (po);
 }

+ 83 - 77
src/codec/grammar_ttl.y

@@ -35,14 +35,6 @@
 %token_type { char * }
 %token_destructor { (void) state; free ($$); }
 
-/* NULL-terminated array of object term handles. */
-%type objList           { LSUP_Term ** }
-%destructor objList     {
-    for (size_t i = 0; $$[i]; i++) {
-        LSUP_term_free ($$[i]);
-    }
-}
-
 %default_type           { char * }
 
 %extra_argument         { LSUP_TTLParserState *state }
@@ -69,11 +61,21 @@ statement   ::= triples .
 statement   ::= WS .
 
 prefixID    ::= PREFIX(P) WS IRIREF(N) PERIOD . {
-                LSUP_nsmap_add (state->nsm, P, N);
+                LSUP_nsmap_add (
+                    LSUP_graph_namespace (
+                        LSUP_graph_iter_graph (state->it)
+                    ), P, N
+                );
+
+                free (P);
+                free (N);
             }
 
 base        ::= BASE WS IRIREF(D) PERIOD . {
+                LSUP_term_free (state->base);
                 state->base = LSUP_iriref_new (D, NULL);
+
+                free (D);
             }
 
 triples 	::= subject(S) ows predObjList(L) PERIOD . {
@@ -81,6 +83,7 @@ triples 	::= subject(S) ows predObjList(L) PERIOD . {
                 state->ct += ct;
                 state->rc = LSUP_OK;
                 log_trace ("Added %lu triples.", ct);
+
                 LSUP_term_free (S);
                 LSUP_pred_obj_list_free (L);
             }
@@ -89,6 +92,7 @@ triples 	::= subject(S) ows predObjList(L) SEMICOLON PERIOD . [PERIOD] {
                 state->ct += ct;
                 state->rc = LSUP_OK;
                 log_trace ("Added %lu triples.", ct);
+
                 LSUP_term_free (S);
                 LSUP_pred_obj_list_free (L);
             }
@@ -105,6 +109,12 @@ predObjList(A) ::= predObjList(L) SEMICOLON predicate(P) ows objectList(O) . {
             }
 
 %type objectList { LSUP_Term ** }
+%destructor objectList {
+    log_debug ("Freeing object list.");
+    size_t i = 0;
+    while ($$[i]) LSUP_term_free ($$[i++]);
+    free ($$);
+}
 objectList(A) ::= objectList(L) COMMA object(O) . {
                 A = LSUP_obj_list_add (L, O);
             }
@@ -114,57 +124,94 @@ objectList(A) ::= object(O) . [IRIREF] {
             }
 
 %type subject { LSUP_Term * }
+%destructor subject { LSUP_term_free ($$); }
 subject 	::= resource .
 subject 	::= blank .
 
 %type predicate { LSUP_Term * }
-// Leading WS is counted as part of the RDF_TYPE ('a') token.
+%destructor predicate { LSUP_term_free ($$); }
 predicate   ::= resource .
-predicate(A)::= RDF_TYPE . { A = LSUP_iriref_new ("rdf:type", state->nsm); }
+predicate(A)::= RDF_TYPE . {
+                A = LSUP_iriref_new (
+                        "rdf:type",
+                        LSUP_graph_namespace (LSUP_graph_iter_graph (state->it)));
+                }
 
 %type object { LSUP_Term * }
+%destructor object { LSUP_term_free ($$); }
 object 	    ::= resource .
 object 	    ::= blank .
 object 	    ::= literal .
 
 %type literal { LSUP_Term * }
+%destructor literal { LSUP_term_free ($$); }
 literal(A)  ::= STRING(D) . {
                 A = LSUP_term_new (LSUP_TERM_LITERAL, D, NULL);
                 log_trace ("Created plain literal: \"%s\"", A->data);
+                free (D);
             }
 literal(A)  ::= STRING(D) LANGTAG(L) . {
                 A = LSUP_term_new (LSUP_TERM_LT_LITERAL, D, L);
                 log_trace ("Created LT-literal: \"%s\"@%s", A->data, A->lang);
+                free (D);
+                free (L);
             }
 literal(A)  ::= STRING(D) DTYPE_MARKER resource(M) . {
                 A = LSUP_term_new (LSUP_TERM_LITERAL, D, M);
-                log_trace ("Created DT-literal: \"%s\"^^%s", A->data, A->datatype);
+                log_trace (
+                        "Created DT-literal: \"%s\"^^%s",
+                        A->data, A->datatype);
+                free (D);
             }
 literal(A)  ::= INTEGER(D) . {
                 A = LSUP_term_new (
                     LSUP_TERM_LITERAL, D,
-                    LSUP_iriref_new ("xsd:integer", state->nsm));
+                    LSUP_iriref_new (
+                        "xsd:integer", 
+                        LSUP_graph_namespace (LSUP_graph_iter_graph (state->it))
+                    )
+                );
+
+                free (D);
             }
 literal(A)  ::= DOUBLE(D) . {
                 A = LSUP_term_new (
                     LSUP_TERM_LITERAL, D,
-                    LSUP_iriref_new ("xsd:double", state->nsm));
+                    LSUP_iriref_new (
+                        "xsd:double", 
+                        LSUP_graph_namespace (LSUP_graph_iter_graph (state->it))
+                    )
+                );
+                free (D);
             }
 literal(A)  ::= DECIMAL(D) . {
                 A = LSUP_term_new (
                     LSUP_TERM_LITERAL, D,
-                    LSUP_iriref_new ("xsd:decimal", state->nsm));
+                    LSUP_iriref_new (
+                        "xsd:decimal", 
+                        LSUP_graph_namespace (LSUP_graph_iter_graph (state->it))
+                    )
+                );
+                free (D);
             }
 literal(A)  ::= BOOLEAN(D) . {
                 A = LSUP_term_new (
                     LSUP_TERM_LITERAL, D,
-                    LSUP_iriref_new ("xsd:boolean", state->nsm));
+                    LSUP_iriref_new (
+                        "xsd:boolean", 
+                        LSUP_graph_namespace (LSUP_graph_iter_graph (state->it))
+                    )
+                );
+                free (D);
             }
 
 %type blank { LSUP_Term * }
+%destructor blank { LSUP_term_free ($$); }
 blank(A)    ::= BNODE_ID(D) . {
                 A = LSUP_term_new (LSUP_TERM_BNODE, D, NULL);
                 log_trace ("Created blank node: _:%s", A->data);
+
+                free (D);
             }
 blank(A)    ::= LBRACKET RBRACKET . [BNODE_ID] {
                 A = LSUP_term_new (LSUP_TERM_BNODE, NULL, NULL);
@@ -179,20 +226,32 @@ blank(A)    ::= LBRACKET predObjList(L) RBRACKET . [BNODE_ID] {
             }
 blank       ::= collection . [BNODE_ID]
 blank(A)    ::= LPAREN RPAREN . [BNODE_ID] {
-                A = LSUP_iriref_new ("rdf:nil", state->nsm);
+                A = LSUP_iriref_new (
+                    "rdf:nil",
+                    LSUP_graph_namespace (LSUP_graph_iter_graph (state->it))
+                );
                 log_trace ("Created list terminator: %s", A->data);
             }
 
 // "collection" is the subject of the first collection item.
 %type collection { LSUP_Term * }
+%destructor collection { LSUP_term_free ($$); }
 // Collection triples are added here to the graph.
 collection(A) ::= LPAREN itemList(L) RPAREN . {
                 A = LSUP_bnode_add_collection (state->it, L);
+                // Free the item list.
+                size_t i = 0;
+                while (L[i]) LSUP_term_free (L[i++]);
+                free (L);
             }
 
 %type itemList { LSUP_Term ** }
-// Freed when the item list in the collection gets added to the graph.
-%destructor itemList {}
+%destructor itemList {
+    log_debug ("Freeing item list.");
+    size_t i = 0;
+    while ($$[i]) LSUP_term_free ($$[i++]);
+    free ($$);
+}
 itemList(A) ::= itemList(L) ows object(O) . { A = LSUP_obj_list_add (L, O); }
 itemList(A) ::= object(O) . {
                 A = calloc (sizeof (*A), 2);
@@ -200,6 +259,7 @@ itemList(A) ::= object(O) . {
             }
 
 %type resource { LSUP_Term * }
+%destructor resource { LSUP_term_free ($$); }
 resource(A) ::= IRIREF(D) . {
                 LSUP_Term *rel_iri = LSUP_iriref_new (D, NULL);
                 free (D);
@@ -212,66 +272,12 @@ resource(A) ::= IRIREF(D) . {
                 log_trace ("Created IRI: <%s>", A->data);
             }
 resource(A) ::= QNAME(D) . {
-                A = LSUP_iriref_new (D, state->nsm);
+                A = LSUP_iriref_new (
+                    D, LSUP_graph_namespace (LSUP_graph_iter_graph (state->it))
+                );
                 log_trace ("Created IRI: %s", A->data);
+                free (D);
             }
 
 ows         ::= WS .
 ows         ::= .
-
-
-/*
- * This has been adapted from
- * https://www.w3.org/TeamSubmission/turtle/#sec-grammar-grammar :
-
-
-[1]	turtleDoc 	::= 	statement*
-[2]	statement 	::= 	directive '.' | triples '.' | ws+
-[3]	directive 	::= 	prefixID | base
-[4]	prefixID 	::= 	'@prefix' ws+ prefixName? ':' uriref
-[5]	base 	::= 	'@base' ws+ uriref
-[6]	triples 	::= 	subject predicateObjectList
-[7]	predicateObjectList 	::= 	verb objectList ( ';' verb objectList )* ( ';')?
-[8]	objectList 	::= 	object ( ',' object)*
-[9]	verb 	::= 	predicate | 'a'
-[10]	comment 	::= 	'#' ( [^#xA#xD] )*
-[11]	subject 	::= 	resource | blank
-[12]	predicate 	::= 	resource
-[13]	object 	::= 	resource | blank | literal
-[14]	literal 	::= 	quotedString ( '@' language )? | datatypeString | integer | double | decimal | boolean
-[15]	datatypeString 	::= 	quotedString '^^' resource
-[16]	integer 	::= 	('-' | '+') ? [0-9]+
-[17]	double 	::= 	('-' | '+') ? ( [0-9]+ '.' [0-9]* exponent | '.' ([0-9])+ exponent | ([0-9])+ exponent )
-[18]	decimal 	::= 	('-' | '+')? ( [0-9]+ '.' [0-9]* | '.' ([0-9])+ | ([0-9])+ )
-[19]	exponent 	::= 	[eE] ('-' | '+')? [0-9]+
-[20]	boolean 	::= 	'true' | 'false'
-[21]	blank 	::= 	nodeID | '[]' | '[' predicateObjectList ']' | collection
-[22]	itemList 	::= 	object+
-[23]	collection 	::= 	'(' itemList? ')'
-[24]	ws 	::= 	#x9 | #xA | #xD | #x20 | comment
-[25]	resource 	::= 	uriref | qname
-[26]	nodeID 	::= 	'_:' name
-[27]	qname 	::= 	prefixName? ':' name?
-[28]	uriref 	::= 	'<' relativeURI '>'
-[29]	language 	::= 	[a-z]+ ('-' [a-z0-9]+ )*
-[30]	nameStartChar 	::= 	[A-Z] | "_" | [a-z] | [#x00C0-#x00D6] | [#x00D8-#x00F6] | [#x00F8-#x02FF] | [#x0370-#x037D] | [#x037F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
-[31]	nameChar 	::= 	nameStartChar | '-' | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040]
-[32]	name 	::= 	nameStartChar nameChar*
-[33]	prefixName 	::= 	( nameStartChar - '_' ) nameChar*
-[34]	relativeURI 	::= 	ucharacter*
-[35]	quotedString 	::= 	string | longString
-[36]	string 	::= 	#x22 scharacter* #x22
-[37]	longString 	::= 	#x22 #x22 #x22 lcharacter* #x22 #x22 #x22
-[38]	character 	::= 	'\u' hex hex hex hex |
-'\U' hex hex hex hex hex hex hex hex |
-'\\' |
-[#x20-#x5B] | [#x5D-#x10FFFF]
-[39]	echaracter 	::= 	character | '\t' | '\n' | '\r'
-[40]	hex 	::= 	[#x30-#x39] | [#x41-#x46]
-[41]	ucharacter 	::= 	( character - #x3E ) | '\>'
-[42]	scharacter 	::= 	( echaracter - #x22 ) | '\"'
-[43]	lcharacter 	::= 	echaracter | '\"' | #x9 | #xA | #xD 
-
-
-
-*/

+ 2 - 2
src/codec/lexer_ttl.re

@@ -373,10 +373,9 @@ LSUP_ttl_parse_doc (FILE *fh, LSUP_Graph **gr_p, size_t *ct, char **err_p)
 
     void *parser = TTLParseAlloc (malloc);
 
-    state->nsm = LSUP_nsmap_new();
     // TODO add basic NS, critically xsd: and rdf:
     LSUP_Graph *gr = LSUP_graph_new (
-            LSUP_iriref_new (NULL, NULL), LSUP_STORE_HTABLE, NULL, state->nsm, 0);
+            LSUP_iriref_new (NULL, NULL), LSUP_STORE_HTABLE, NULL, NULL, 0);
     if (UNLIKELY (!gr)) return LSUP_MEM_ERR;
 
     state->it = LSUP_graph_add_init (gr);
@@ -435,6 +434,7 @@ finally:
     TTLParseFree (parser, free);
 
     LSUP_graph_add_done (state->it);
+    LSUP_term_free (state->base);
     free (state);
 
     if (rc < 0) LSUP_graph_free (gr);

+ 6 - 6
src/term.c

@@ -98,7 +98,7 @@ LSUP_term_new_from_buffer (const LSUP_Buffer *sterm)
     if (UNLIKELY (!sterm)) return NULL;
 
     LSUP_Term *term = NULL;
-    LSUP_TermType type;
+    LSUP_TermType type = LSUP_TERM_UNDEFINED;
     char *data = NULL;
     void *metadata;
 
@@ -268,11 +268,11 @@ LSUP_term_hash (const LSUP_Term *term)
 void
 LSUP_term_free (LSUP_Term *term)
 {
-    if (LIKELY (term != NULL)) {
-        if (LSUP_IS_IRI (term)) free (term->iri_info);
-        free (term->data);
-        free (term);
-    }
+    if (UNLIKELY (!term)) return;
+
+    if (LSUP_IS_IRI (term)) free (term->iri_info);
+    free (term->data);
+    free (term);
 }
 
 

+ 6 - 0
test/test_codec_ttl.c

@@ -37,6 +37,10 @@ test_w3c_pos()
 
         EXPECT_PASS (codec.decode_graph (test_stream, &gr, &ct, &err));
         EXPECT_INT_EQ (LSUP_graph_size (gr), nt_ct); // Just count NT lines.
+        LSUP_graph_free (gr);
+        fclose (test_stream);
+        fclose (out_stream);
+        free (err);
     }
 
     return 0;
@@ -60,6 +64,8 @@ test_w3c_neg()
         LSUP_rc rc = codec.decode_graph (test_stream, &gr, &ct, &err);
         log_info ("rc: %d", rc);
         ASSERT (rc == LSUP_PARSE_ERR, "Bad test did not raise a parse error!");
+        fclose (test_stream);
+        free (err);
     }
 
     return 0;