From 38e6de480f30185dce6be3ad39668f4bfd5fd15d Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sat, 25 Jul 2015 12:41:44 -0700 Subject: [PATCH] sys-file-reader: Avoid hanging forever if a system file has no variables. --- doc/dev/system-file-format.texi | 4 ++++ src/data/sys-file-reader.c | 2 +- src/language/data-io/get.c | 10 ++++++++- tests/data/pc+-file-reader.at | 2 ++ tests/data/sys-file-reader.at | 37 +++++++++++++++++++++++++++++++++ 5 files changed, 53 insertions(+), 2 deletions(-) diff --git a/doc/dev/system-file-format.texi b/doc/dev/system-file-format.texi index d100aa9d24..4eb061580d 100644 --- a/doc/dev/system-file-format.texi +++ b/doc/dev/system-file-format.texi @@ -262,6 +262,10 @@ wider than 255 bytes. Such very long string variables are represented by a number of narrower string variables. @xref{Very Long String Record}, for details. +A system file should contain at least one variable and thus at least +one variable record, but system files have been observed in the wild +without any variables (thus, no data either). + @example int32 rec_type; int32 type; diff --git a/src/data/sys-file-reader.c b/src/data/sys-file-reader.c index caab3d9b15..2607369ea8 100644 --- a/src/data/sys-file-reader.c +++ b/src/data/sys-file-reader.c @@ -2660,7 +2660,7 @@ sys_file_casereader_read (struct casereader *reader, void *r_) int retval; int i; - if (r->error) + if (r->error || !r->sfm_var_cnt) return NULL; c = case_create (r->proto); diff --git a/src/language/data-io/get.c b/src/language/data-io/get.c index 9a788a01e3..2440bd900b 100644 --- a/src/language/data-io/get.c +++ b/src/language/data-io/get.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2007, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006-2007, 2010-15 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 @@ -31,6 +31,7 @@ #include "language/lexer/lexer.h" #include "libpspp/compiler.h" #include "libpspp/misc.h" +#include "libpspp/message.h" #include "libpspp/str.h" #include "gl/xalloc.h" @@ -126,6 +127,13 @@ parse_read_command (struct lexer *lexer, struct dataset *ds, if (reader == NULL) goto error; + if (dict_get_var_cnt (dict) == 0) + { + msg (SE, _("%s: Data file dictionary has no variables."), + fh_get_name (fh)); + goto error; + } + stage = case_map_stage_create (dict); while (lex_token (lexer) != T_ENDCMD) diff --git a/tests/data/pc+-file-reader.at b/tests/data/pc+-file-reader.at index 7b88ef4adb..a968e5dac0 100644 --- a/tests/data/pc+-file-reader.at +++ b/tests/data/pc+-file-reader.at @@ -928,6 +928,8 @@ GET FILE='pc+-file.sav' ENCODING='us-ascii'. ]) AT_CHECK([pspp -O format=csv pc+-file.sps], [1], [dnl error: `pc+-file.sav' near offset 0x1b0: Record 1 has length 192 (expected 224). + +pc+-file.sps:1: error: GET: `pc+-file.sav': Data file dictionary has no variables. ]) AT_CLEANUP diff --git a/tests/data/sys-file-reader.at b/tests/data/sys-file-reader.at index e9b262e864..019d873081 100644 --- a/tests/data/sys-file-reader.at +++ b/tests/data/sys-file-reader.at @@ -1557,6 +1557,43 @@ AT_CLEANUP AT_BANNER([system file reader - negative]) +AT_SETUP([no variables]) +AT_KEYWORDS([sack synthetic system file negative]) +AT_DATA([sys-file.sack], [dnl +dnl File header. +"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file"; +2; dnl Layout code +0; dnl Nominal case size (empty) +0; dnl Not compressed +0; dnl Not weighted +0; dnl 0 cases. +100.0; dnl Bias. +"01 Jan 11"; "20:53:52"; s64 "PSPP synthetic test file"; +i8 0 *3; + +dnl Character encoding record. +7; 20; 1; 12; "windows-1252"; + +dnl Dictionary termination record. +999; 0; +]) +for variant in be le; do + AT_CHECK([sack --$variant sys-file.sack > sys-file.sav]) + AT_DATA([sys-file.sps], [dnl +GET FILE='sys-file.sav'. +]) + AT_CHECK([pspp -O format=csv sys-file.sps], [1], [dnl +sys-file.sps:1: error: GET: `sys-file.sav': Data file dictionary has no variables. +]) + + dnl At one point pspp-convert would hang forever if there were no variables, + dnl so check against regression. + AT_CHECK([pspp-convert sys-file.sav sys-file.txt]) + AT_CHECK([cat sys-file.txt], [0], [ +]) +done +AT_CLEANUP + AT_SETUP([unspecified character encoding]) AT_KEYWORDS([sack synthetic system file positive]) AT_DATA([sys-file.sack], [dnl -- 2.30.2