From c91f650b47f33cfbd4b7ed45dbfa7eb012c7e6fb Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 27 May 2013 21:28:32 -0700 Subject: [PATCH] INPUT PROGRAM: Avoid infinite loop for trivially empty input program. Bug #38782. Reported by John Darrington. --- doc/data-io.texi | 3 ++ src/language/command.c | 22 +++++++++--- src/language/command.h | 12 +++---- src/language/data-io/data-list.c | 4 +-- src/language/data-io/inpt-pgm.c | 57 +++++++++++++++++++----------- tests/language/data-io/inpt-pgm.at | 15 ++++++++ 6 files changed, 80 insertions(+), 33 deletions(-) diff --git a/doc/data-io.texi b/doc/data-io.texi index 313e543205..1316f603a6 100644 --- a/doc/data-io.texi +++ b/doc/data-io.texi @@ -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 diff --git a/src/language/command.c b/src/language/command.c index 5b376629d4..78fd5f00b0 100644 --- a/src/language/command.c +++ b/src/language/command.c @@ -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 @@ -50,10 +50,22 @@ 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, diff --git a/src/language/command.h b/src/language/command.h index d99577c4d3..ab133c25e7 100644 --- a/src/language/command.h +++ b/src/language/command.h @@ -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. */ diff --git a/src/language/data-io/data-list.c b/src/language/data-io/data-list.c index bc295a9aed..834a2f8d7f 100644 --- a/src/language/data-io/data-list.c +++ b/src/language/data-io/data-list.c @@ -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); diff --git a/src/language/data-io/inpt-pgm.c b/src/language/data-io/inpt-pgm.c index afeb832643..7229d56d48 100644 --- a/src/language/data-io/inpt-pgm.c +++ b/src/language/data-io/inpt-pgm.c @@ -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 @@ -43,12 +43,6 @@ #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. */ diff --git a/tests/language/data-io/inpt-pgm.at b/tests/language/data-io/inpt-pgm.at index 03f9a2a510..480c83f1b1 100644 --- a/tests/language/data-io/inpt-pgm.at +++ b/tests/language/data-io/inpt-pgm.at @@ -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 -- 2.30.2