INPUT PROGRAM: Avoid infinite loop for trivially empty input program.
authorBen Pfaff <blp@cs.stanford.edu>
Tue, 28 May 2013 04:28:32 +0000 (21:28 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Tue, 28 May 2013 04:28:32 +0000 (21:28 -0700)
Bug #38782.
Reported by John Darrington.

doc/data-io.texi
src/language/command.c
src/language/command.h
src/language/data-io/data-list.c
src/language/data-io/inpt-pgm.c
tests/language/data-io/inpt-pgm.at

index 313e543205a41f430ac864534ce22a132bfabecd..1316f603a6aa9d8c0ee832d460817ba645531570 100644 (file)
@@ -795,6 +795,9 @@ so an infinite loop results.  @cmd{END FILE}, when executed,
 stops the flow of input data and passes out of the @cmd{INPUT PROGRAM}
 structure.
 
+@cmd{INPUT PROGRAM} must contain at least one @cmd{DATA LIST} or
+@cmd{END FILE} command.
+
 All this is very confusing.  A few examples should help to clarify.
 
 @c If you change this example, change the regression test1 in
index 5b376629d48970ea0c55fae7f6a4707b727d3c1b..78fd5f00b00fe6cba1bd77806ac976c7fd2fedcd 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 static inline bool
 cmd_result_is_valid (enum cmd_result result)
 {
-  return (result == CMD_SUCCESS || result == CMD_EOF || result == CMD_FINISH
-          || (result >= CMD_PRIVATE_FIRST && result <= CMD_PRIVATE_LAST)
-          || result == CMD_FAILURE || result == CMD_NOT_IMPLEMENTED
-          || result == CMD_CASCADING_FAILURE);
+  switch (result)
+    {
+    case CMD_SUCCESS:
+    case CMD_EOF:
+    case CMD_FINISH:
+    case CMD_DATA_LIST:
+    case CMD_END_CASE:
+    case CMD_END_FILE:
+    case CMD_FAILURE:
+    case CMD_NOT_IMPLEMENTED:
+    case CMD_CASCADING_FAILURE:
+      return true;
+
+    default:
+      return false;
+    }
 }
 
 /* Returns true if RESULT indicates success,
index d99577c4d3151f931cf19d7ccc629ae13704a76b..ab133c25e7932cf60f5e4fd835353659231c21d6 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2010, 2013 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -27,11 +27,11 @@ enum cmd_result
     CMD_EOF = 2,                /* End of input. */
     CMD_FINISH = 3,             /* FINISH was executed. */
 
-    /* Range of successful return values available for use
-       by agreement between a command and the caller of
-       cmd_parse(). */
-    CMD_PRIVATE_FIRST = 4,
-    CMD_PRIVATE_LAST = 127,
+    /* Successful return values returned by specific commands to let INPUT
+       PROGRAM function properly. */
+    CMD_DATA_LIST,
+    CMD_END_CASE,
+    CMD_END_FILE,
 
     /* Various kinds of failures. */
     CMD_FAILURE = -1,           /* Not executed at all. */
index bc295a9aed7aa7939eb6f2f8141d82a4604d2053..834a2f8d7f7a1fe72b9970ba99c470c1b64a443b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -297,7 +297,7 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds)
   fh_unref (fh);
   free (encoding);
 
-  return CMD_SUCCESS;
+  return CMD_DATA_LIST;
 
  error:
   data_parser_destroy (parser);
index afeb832643f4cda772964aad6707652e07a9a0fe..7229d56d485ee164f5fc75ff96865c4a71f956b8 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-/* Private result codes for use within INPUT PROGRAM. */
-enum cmd_result_extensions
-  {
-    CMD_END_CASE = CMD_PRIVATE_FIRST
-  };
-
 /* Indicates how a `union value' should be initialized. */
 struct input_program_pgm
   {
@@ -91,6 +85,8 @@ cmd_input_program (struct lexer *lexer, struct dataset *ds)
 {
   struct input_program_pgm *inp;
   bool saw_END_CASE = false;
+  bool saw_END_FILE = false;
+  bool saw_DATA_LIST = false;
 
   dataset_clear (ds);
   if (!lex_match (lexer, T_ENDCMD))
@@ -107,27 +103,48 @@ cmd_input_program (struct lexer *lexer, struct dataset *ds)
       enum cmd_result result;
 
       result = cmd_parse_in_state (lexer, ds, CMD_STATE_INPUT_PROGRAM);
-      if (result == (enum cmd_result) CMD_END_CASE)
+      switch (result)
         {
+        case CMD_DATA_LIST:
+          saw_DATA_LIST = true;
+          break;
+
+        case CMD_END_CASE:
           emit_END_CASE (ds, inp);
           saw_END_CASE = true;
-        }
-      else if (cmd_result_is_failure (result)
-               && result != CMD_FAILURE
-               && lex_get_error_mode (lexer) != LEX_ERROR_INTERACTIVE)
-        {
-          if (result == CMD_EOF)
-            msg (SE, _("Unexpected end-of-file within INPUT PROGRAM."));
-          inside_input_program = false;
-          dataset_clear (ds);
-          destroy_input_program (inp);
-          return result;
+          break;
+
+        case CMD_END_FILE:
+          saw_END_FILE = true;
+          break;
+
+        case CMD_FAILURE:
+          break;
+
+        default:
+          if (cmd_result_is_failure (result)
+              && lex_get_error_mode (lexer) != LEX_ERROR_INTERACTIVE)
+            {
+              if (result == CMD_EOF)
+                msg (SE, _("Unexpected end-of-file within INPUT PROGRAM."));
+              inside_input_program = false;
+              dataset_clear (ds);
+              destroy_input_program (inp);
+              return result;
+            }
         }
     }
   if (!saw_END_CASE)
     emit_END_CASE (ds, inp);
   inside_input_program = false;
 
+  if (!saw_DATA_LIST && !saw_END_FILE)
+    {
+      msg (SE, _("Input program must contain DATA LIST or END FILE."));
+      dataset_clear (ds);
+      destroy_input_program (inp);
+      return CMD_FAILURE;
+    }
   if (dict_get_next_value_idx (dataset_dict (ds)) == 0)
     {
       msg (SE, _("Input program did not create any variables."));
@@ -371,7 +388,7 @@ cmd_end_file (struct lexer *lexer UNUSED, struct dataset *ds)
 
   add_transformation (ds, end_file_trns_proc, NULL, NULL);
 
-  return CMD_SUCCESS;
+  return CMD_END_FILE;
 }
 
 /* Executes an END FILE transformation. */
index 03f9a2a5108def99ab98bee502287d58631f316c..480c83f1b12b48c39225ba938d42b52950ae561d 100644 (file)
@@ -31,3 +31,18 @@ AT_CHECK([pspp -O format=csv input-program.sps], [1], [dnl
 error: DESCRIPTIVES: Syntax error at end of input: expecting BEGIN.
 ])
 AT_CLEANUP
+
+dnl Tests for bug #38782, an infinite loop processing an empty input program.
+AT_SETUP([INPUT PROGRAM infinite loop])
+AT_DATA([input-program.sps], [dnl
+INPUT PROGRAM.
+STRING firstname lastname (a24) / address (a80).
+END INPUT PROGRAM.
+EXECUTE.
+])
+AT_CHECK([pspp -O format=csv input-program.sps], [1], [dnl
+input-program.sps:3: error: Input program must contain DATA LIST or END FILE.
+
+input-program.sps:4: error: EXECUTE: EXECUTE is allowed only after the active dataset has been defined.
+])
+AT_CLEANUP