Fix memory leak in MRSETS
[pspp] / src / data / sys-file-reader.c
index d2b105c0255ea7da523463f7c7caa232950f63c6..b92f42a96c6e159e13bb8c2f0d8a3cf419798923 100644 (file)
@@ -42,7 +42,6 @@
 #include "libpspp/array.h"
 #include "libpspp/assertion.h"
 #include "libpspp/compiler.h"
-#include "libpspp/hash.h"
 #include "libpspp/i18n.h"
 #include "libpspp/message.h"
 #include "libpspp/misc.h"
@@ -133,6 +132,10 @@ static void text_warn (struct sfm_reader *r, struct text_record *text,
 static char *text_get_token (struct text_record *,
                              struct substring delimiters, char *delimiter);
 static bool text_match (struct text_record *, char c);
+static bool text_read_variable_name (struct sfm_reader *, struct dictionary *,
+                                     struct text_record *,
+                                     struct substring delimiters,
+                                     struct variable **);
 static bool text_read_short_name (struct sfm_reader *, struct dictionary *,
                                   struct text_record *,
                                   struct substring delimiters,
@@ -614,16 +617,20 @@ read_variable_record (struct sfm_reader *r, struct dictionary *dict,
     sys_error (r, _("Variable label indicator field is not 0 or 1."));
   if (has_variable_label == 1)
     {
-      size_t len;
+      size_t len, read_len;
       char label[255 + 1];
 
       len = read_int (r);
-      if (len >= sizeof label)
-        sys_error (r, _("Variable %s has label of invalid length %zu."),
-                   name, len);
-      read_string (r, label, len + 1);
+
+      /* Read up to 255 bytes of label. */
+      read_len = MIN (sizeof label - 1, len);
+      read_string (r, label, read_len + 1);
       var_set_label (var, label);
 
+      /* Skip unread label bytes. */
+      skip_bytes (r, len - read_len);
+
+      /* Skip label padding up to multiple of 4 bytes. */
       skip_bytes (r, ROUND_UP (len, 4) - len);
     }
 
@@ -1165,6 +1172,7 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count,
 
       dict_add_mrset (dict, mrset);
       mrset = NULL;
+      stringi_set_destroy (&var_names);
     }
   mrset_destroy (mrset);
   close_text_record (r, text);
@@ -1671,7 +1679,7 @@ read_long_string_value_labels (struct sfm_reader *r,
                  first 255 bytes.  The maximum documented length
                  of a label is 120 bytes so this is more than
                  generous. */
-              skip_bytes (r, sizeof label - (label_length + 1));
+              skip_bytes (r, (label_length + 1) - sizeof label);
             }
 
           if (!skip && !var_add_value_label (v, &value, label))
@@ -1693,7 +1701,7 @@ read_variable_attributes (struct sfm_reader *r,
   for (;;) 
     {
       struct variable *var;
-      if (!text_read_short_name (r, dict, text, ss_cstr (":"), &var))
+      if (!text_read_variable_name (r, dict, text, ss_cstr (":"), &var))
         break;
       read_attributes (r, text, var != NULL ? var_get_attributes (var) : NULL);
     }
@@ -2127,6 +2135,27 @@ read_variable_to_value_pair (struct sfm_reader *r, struct dictionary *dict,
     }
 }
 
+static bool
+text_read_variable_name (struct sfm_reader *r, struct dictionary *dict,
+                         struct text_record *text, struct substring delimiters,
+                         struct variable **var)
+{
+  char *name;
+
+  name = text_get_token (text, delimiters, NULL);
+  if (name == NULL)
+    return false;
+
+  *var = dict_lookup_var (dict, name);
+  if (*var != NULL)
+    return true;
+
+  text_warn (r, text, _("Dictionary record refers to unknown variable %s."),
+             name);
+  return false;
+}
+
+
 static bool
 text_read_short_name (struct sfm_reader *r, struct dictionary *dict,
                       struct text_record *text, struct substring delimiters,