[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#948363: marked as done (buster-pu: package fig2dev/1:3.2.7a-5+deb10u2)



Your message dated Sat, 08 Feb 2020 14:21:36 +0000
with message-id <cf1cb2f35981916a86b98b83609df15c95aa378b.camel@adam-barratt.org.uk>
and subject line Closing requests included in 10.3 point release
has caused the Debian Bug report #948363,
regarding buster-pu: package fig2dev/1:3.2.7a-5+deb10u2
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
948363: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=948363
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: buster
User: release.debian.org@packages.debian.org
Usertags: pu

While 3.2.7a-5+deb10u2 is currently in proposed-updates I prepared
another update (deb10u3) fixing CVE-2019-19746 and CVE-2019-19797 as
well as 6 further segfaults, which are only in upstream tracker and
don't have a CVE:
https://sourceforge.net/p/mcj/tickets/58
https://sourceforge.net/p/mcj/tickets/59
https://sourceforge.net/p/mcj/tickets/61
https://sourceforge.net/p/mcj/tickets/62
https://sourceforge.net/p/mcj/tickets/78
https://sourceforge.net/p/mcj/tickets/79

According to security-tracker CVE-2019-19746 is "unimportant" and
CVE-2019-19797 is tagged "no DSA", so I didn't send this to the
security team, but request a point release update.

Hopefully the second patch isn't too big for a point release, but
since upstream fixed several segfaults with this, it won't be a good
idea to extract only parts from it to fix only CVE-2019-19797 but keep
the root cause of all these segfaults...

Attached you'll find a patch agains 3.2.7a-5+deb10u2.

Greetings
Roland
diff -Nru fig2dev-3.2.7a/debian/changelog fig2dev-3.2.7a/debian/changelog
--- fig2dev-3.2.7a/debian/changelog	2019-12-04 22:12:49.000000000 +0100
+++ fig2dev-3.2.7a/debian/changelog	2020-01-07 19:53:09.000000000 +0100
@@ -1,3 +1,13 @@
+fig2dev (1:3.2.7a-5+deb10u3) buster; urgency=medium
+
+  * 42_CVE-2019-19746: Reject huge arrow types causing integer overflow.
+    This fixes CVE-2019-19746 (Closes: #946628).
+  * 43_fgets2getline: Replace most calls to fgets() by getline() in
+     read.c.  This fixes CVE-2019-19797 and several other segfaults
+    (Closes: #946866).
+
+ -- Roland Rosenfeld <roland@debian.org>  Tue, 07 Jan 2020 19:53:09 +0100
+
 fig2dev (1:3.2.7a-5+deb10u2) buster; urgency=medium
 
   * 41_CVE-2019-19555: Allow Fig v2 text strings ending with multiple ^A.
diff -Nru fig2dev-3.2.7a/debian/patches/42_CVE-2019-19746.patch fig2dev-3.2.7a/debian/patches/42_CVE-2019-19746.patch
--- fig2dev-3.2.7a/debian/patches/42_CVE-2019-19746.patch	1970-01-01 01:00:00.000000000 +0100
+++ fig2dev-3.2.7a/debian/patches/42_CVE-2019-19746.patch	2020-01-07 19:53:09.000000000 +0100
@@ -0,0 +1,44 @@
+From: Thomas Loimer <thomas.loimer@tuwien.ac.at>
+Date: Tue Dec 10 13:17:36 2019 +0100
+Bug: https://sourceforge.net/p/mcj/tickets/57
+Bug-Debian: https://bugs.debian.org/946628
+Origin: https://sourceforge.net/p/mcj/fig2dev/ci/3065abc7b4f740ed6532322843531317de782a26/
+Subject: Reject huge arrow types causing integer overflow.
+ This fixes CVE-2019-19746
+
+--- a/fig2dev/arrow.c
++++ b/fig2dev/arrow.c
+@@ -1,9 +1,10 @@
+ /*
+  * Fig2dev: Translate Fig code to various Devices
+- * Copyright (c) 1985 by Supoj Sutantavibul
+  * Copyright (c) 1991 by Micah Beck
+- * Parts Copyright (c) 1989-2002 by Brian V. Smith
+- * Parts Copyright (c) 2015-2018 by Thomas Loimer
++ * Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
++ * Parts Copyright (c) 1989-2015 by Brian V. Smith
++ * Parts Copyright (c) 2015-2019 by Thomas Loimer
++ *
+  *
+  * Any party obtaining a copy of these files is granted, free of charge, a
+  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
+@@ -78,7 +79,9 @@ make_arrow(int type, int style, double t
+ {
+ 	F_arrow		*a;
+ 
+-	if (style < 0 || style > 1 || type < 0 || (type + 1) * 2 > NUMARROWS)
++	if (style < 0 || style > 1 || type < 0 ||
++			/* beware of int overflow */
++			type > NUMARROWS || (type + 1) * 2 > NUMARROWS)
+ 		return NULL;
+ 	if (NULL == (Arrow_malloc(a))) {
+ 		put_msg(Err_mem);
+@@ -90,7 +93,7 @@ make_arrow(int type, int style, double t
+ 
+ 	a->type = type;
+ 	a->style = style;
+-	a->thickness = thickness*THICK_SCALE;
++	a->thickness = thickness * THICK_SCALE;
+ 	a->wid = wid;
+ 	a->ht = ht;
+ 	return a;
diff -Nru fig2dev-3.2.7a/debian/patches/43_fgets2getline.patch fig2dev-3.2.7a/debian/patches/43_fgets2getline.patch
--- fig2dev-3.2.7a/debian/patches/43_fgets2getline.patch	1970-01-01 01:00:00.000000000 +0100
+++ fig2dev-3.2.7a/debian/patches/43_fgets2getline.patch	2020-01-07 19:53:09.000000000 +0100
@@ -0,0 +1,1717 @@
+From: Thomas Loimer <thomas.loimer@tuwien.ac.at>
+Date: Sun Jan 5 19:22:12 2020 +0100
+Bug: https://sourceforge.net/p/mcj/tickets/58
+Bug: https://sourceforge.net/p/mcj/tickets/59
+Bug: https://sourceforge.net/p/mcj/tickets/61
+Bug: https://sourceforge.net/p/mcj/tickets/62
+Bug: https://sourceforge.net/p/mcj/tickets/67
+Bug: https://sourceforge.net/p/mcj/tickets/78
+Bug: https://sourceforge.net/p/mcj/tickets/79
+Bug-Debian: https://bugs.debian.org/946866
+Origin: https://sourceforge.net/p/mcj/fig2dev/ci/41b9bb838a3d544539f6e68aa4f87d70ef7d45ce/
+Subject: Replace most calls to fgets() by getline() in read.c
+ Also, fig files version 1.4 must begin with `#FIG 1.4`. Previously, a `#` in the
+ first line was sufficient to detect at least a version 1.4 fig file.
+ Move some variables with file scope into functions.
+
+ This commit fixes tickets #58, #59, #61, #62, #67, #78 and #79.
+
+In fig2dev/lib/, replacements are provided for some library functions used in
+ fig2dev, e.g., strncasecmp(), strrchr(), etc. The getline() function was
+ introduced more recently than any of the functions provided in fig2dev/lib.
+ Nevertheless, for getline() a replacement function is not provided. It seems,
+ that all the replacement functions do not work, but nobody noticed. Therefore,
+ only provide a replacement function for getline() if that turns out to
+ be useful.
+ The replacement functions do not work, because a header file providing the
+ necessary function declarations is missing.
+
+ This fixes CVE-2019-19797
+
+--- a/fig2dev/fig2dev.c
++++ b/fig2dev/fig2dev.c
+@@ -81,7 +81,7 @@ bool	bgspec = false;		/* flag to say -g
+ bool support_i18n = false;
+ #endif
+ char	gif_transparent[20]="\0"; /* GIF transp color hex name (e.g. #ff00dd) */
+-char	papersize[20];		/* paper size */
++char	papersize[];		/* paper size */
+ char	boundingbox[64];	/* boundingbox */
+ char	lang[40];		/* selected output language */
+ RGB	background;		/* background (if specified by -g) */
+--- a/fig2dev/fig2dev.h
++++ b/fig2dev/fig2dev.h
+@@ -95,7 +95,7 @@ extern bool	bgspec;		/* flag to say -g w
+ extern bool support_i18n;
+ #endif
+ extern char	gif_transparent[];/* GIF transp color hex name (e.g. #ff00dd) */
+-extern char	papersize[];	/* paper size */
++extern char	papersize[16];	/* paper size */
+ extern char	boundingbox[];	/* boundingbox */
+ extern char	lang[];		/* selected output language */
+ extern char	*Fig_color_names[]; /* hex names for Fig colors */
+--- a/fig2dev/read.c
++++ b/fig2dev/read.c
+@@ -3,7 +3,7 @@
+  * Copyright (c) 1991 by Micah Beck
+  * Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
+  * Parts Copyright (c) 1989-2015 by Brian V. Smith
+- * Parts Copyright (c) 2015-2019 by Thomas Loimer
++ * Parts Copyright (c) 2015-2020 by Thomas Loimer
+  *
+  * Any party obtaining a copy of these files is granted, free of charge, a
+  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
+@@ -45,28 +45,34 @@ extern F_arrow	*make_arrow(int type, int
+ User_color	 user_colors[MAX_USR_COLS];		/* fig2dev.h */
+ int		 user_col_indx[MAX_USR_COLS];		/* fig2dev.h */
+ int		 num_usr_cols;				/* fig2dev.h */
+-int		 num_object;		/* read1_3.c */
+ 					/* flags, psfonts.h, genps.c */
+ int		 v2_flag;		/* Protocol V2.0 or higher */
+ int		 v21_flag;		/* Protocol V2.1 or higher */
+ int		 v30_flag;		/* Protocol V3.0 or higher */
+ int		 v32_flag;		/* Protocol V3.2 or higher */
+ 
+-static void		 read_colordef(void);
+-static F_ellipse	*read_ellipseobject(void);
+-static F_line		*read_lineobject(FILE *fp);
+-static F_text		*read_textobject(FILE *fp);
+-static F_spline		*read_splineobject(FILE *fp);
+-static F_arc		*read_arcobject(FILE *fp);
+-static F_compound	*read_compoundobject(FILE *fp);
++static void		 read_colordef(char *line, int line_no);
++static F_ellipse	*read_ellipseobject(char *line, int line_no);
++static F_line		*read_lineobject(FILE *fp, char **restrict line,
++					size_t *line_len, int *line_no);
++static F_text		*read_textobject(FILE *fp, char **restrict line,
++					size_t *line_len, int *line_no);
++static F_spline		*read_splineobject(FILE *fp, char **restrict line,
++					size_t *line_len, int *line_no);
++static F_arc		*read_arcobject(FILE *fp, char **restrict line,
++					size_t *line_len, int *line_no);
++static F_compound	*read_compoundobject(FILE *fp, char **restrict line,
++					size_t *line_len, int *line_no);
+ static F_comment	*attach_comments(void);
+-static void		 count_lines_correctly(FILE *fp);
+-static void		 init_pats_used(void);
+-static int		 read_objects(FILE *fp, F_compound *obj);
+-static int		 get_line(FILE *fp);
+-static void		 skip_line(FILE *fp);
+-static int		 backslash_count(char cp[], int start);
+-static int		 save_comment(void);
++static void		count_lines_correctly(FILE *fp, int *line_no);
++static void		init_pats_used(void);
++static int		read_objects(FILE *fp, F_compound *obj);
++static ssize_t		get_line(FILE *fp, char **restrict line,
++					size_t *line_len, int *line_no);
++static void		skip_line(FILE *fp);
++static ptrdiff_t	backslash_count(const char *restrict cp,
++					ptrdiff_t start);
++
+ static char	Err_incomp[] = "Incomplete %s object at line %d.";
+ static char	Err_invalid[] = "Invalid %s object at line %d.";
+ static char	Err_arrow[] = "Invalid %s arrow at line %d.";
+@@ -77,9 +83,6 @@ static char	Err_arrow[] = "Invalid %s ar
+ /* max number of comments that can be stored with each object */
+ #define		MAXCOMMENTS	100
+ 
+-static int	 gif_colnum = 0;
+-static char	 buf[BUFSIZ];
+-static int	 line_no = 0;
+ static char	*comments[MAXCOMMENTS];	/* comments saved for current object */
+ static int	 numcom;		/* current comment index */
+ static bool	 com_alloc = false;	/* whether or not the comment array
+@@ -148,7 +151,6 @@ readfp_fig(FILE *fp, F_compound *obj)
+ 	char	c;
+ 	int	i, status;
+ 
+-	num_object = 0;
+ 	num_usr_cols = 0;
+ 	init_pats_used();
+ 
+@@ -157,15 +159,14 @@ readfp_fig(FILE *fp, F_compound *obj)
+ 	/* initialize the comment array */
+ 	if (!com_alloc)
+ 		for (i = 0; i < MAXCOMMENTS; ++i)
+-			comments[i] = (char *) NULL;
++			comments[i] = (char *)NULL;
+ 	com_alloc = true;
+-	memset((char*)obj, '\0', COMOBJ_SIZE);
++	memset((void *)obj, '\0', COMOBJ_SIZE);
+ 
+ 	/* read first character to see if it is "#" (#FIG 1.4 and newer) */
+ 	c = fgetc(fp);
+ 	if (feof(fp))
+ 		return -2;
+-	memset((char*)obj, '\0', COMOBJ_SIZE);
+ 	/* put the character back */
+ 	ungetc(c, fp);
+ 	if (c == '#')
+@@ -185,25 +186,30 @@ read_objects(FILE *fp, F_compound *obj)
+ 	F_spline	*s, *ls = NULL;
+ 	F_arc		*a, *la = NULL;
+ 	F_compound	*c, *lc = NULL;
+-	int		object, coord_sys, len;
+-
+-	memset((char*)obj, '\0', COMOBJ_SIZE);
+-
+-	(void) fgets(buf, BUFSIZ, fp);	/* get the version line */
+-	if (strncmp(buf, "#FIG ", 5)) {
+-		put_msg("Incorrect format string in first line of input file.");
++	bool		objects = false;
++	int		object, coord_sys;
++	int		line_no;
++	int		gif_colnum = 0;
++	char		*line;
++	char		buf[16];
++	size_t		line_len = 256;
++
++	/* Get the 15 chars of the first line.
++	   Use fgets(), because get_line() would store the line as a comment */
++	if (fgets(buf, sizeof buf, fp) == NULL) {
++		put_msg("Could not read input file.");
+ 		return -1;
+ 	}
++	/* seek to the end of the first line */
++	if (strchr(buf, '\n') == NULL) {
++		int	c;
++		do
++			c = fgetc(fp);
++		while (c != '\n' && c != EOF);
++	}
+ 
+-	/* remove newline and any carriage return (from a PC, perhaps) */
+-	len = strlen(buf);
+-	if (buf[len-1] == '\n') {
+-		if (buf[len-2] == '\r')
+-			buf[len-2] = '\0';
+-		else
+-			buf[len-1] = '\0';
+-	} else {	/* fgets() only stops at newline and end-of-file */
+-		put_msg("File is truncated at first line.");
++	if (strncmp(buf, "#FIG ", 5)) {
++		put_msg("Incorrect format string in first line of input file.");
+ 		return -1;
+ 	}
+ 
+@@ -211,49 +217,65 @@ read_objects(FILE *fp, F_compound *obj)
+ 	v2_flag = (!strncmp(buf, "#FIG 2", 6) || !strncmp(buf, "#FIG 3", 6));
+ 	/* v21_flag is for version 2.1 or higher */
+ 	v21_flag = (!strncmp(buf, "#FIG 2.1", 8) || !strncmp(buf, "#FIG 3", 6));
+-	/* version 2.2 was only beta - 3.0 is the official release (they are identical) */
++	/* version 2.2 was only beta - 3.0 is the official release
++	   (they are identical) */
+ 	v30_flag = (!strncmp(buf, "#FIG 3", 6) || !strncmp(buf, "#FIG 2.2", 8));
+-	/* version 3.2 contains paper size, magnif, multiple page and transparent color
+-	   in Fig file */
++	/* version 3.2 contains paper size, magnif, multiple page
++	   and transparent color in Fig file */
+ 	v32_flag = (!strncmp(buf, "#FIG 3.2", 8));
+ 	if (strncmp(&buf[5], PACKAGE_VERSION, 3) > 0) {
+-	    put_msg("Fig file format (%s) newer than this version of fig2dev (%s), exiting",
+-			&buf[5], PACKAGE_VERSION);
+-	    exit(1);
++		put_msg("Fig file format (%s) newer than this version of fig2dev (%s), exiting",
++				&buf[5], PACKAGE_VERSION);
++		exit(EXIT_FAILURE);
++	}
++
++	if ((v2_flag | v21_flag | v30_flag | v32_flag) == 0 &&
++					strncmp(buf, "#FIG 1.4", 8)) {
++		put_msg("Cannot determine fig file format from string '%s'.",
++				&buf[5]);
++		exit(EXIT_FAILURE);
++	}
++
++	if ((line = malloc(line_len)) == NULL) {
++		put_msg(Err_mem);
++		return -1;
+ 	}
+ 
++	line_no = 1;
+ 	if (v30_flag) {
+ 	    /* read the orientation spec (landscape/portrait) */
+-	    line_no=1;
+-	    if (get_line(fp) < 0) {
++	    if (get_line(fp, &line, &line_len, &line_no) < 0) {
+ 		put_msg("File is truncated at landscape/portrait specification.");
++		free(line);
+ 		return -1;
+ 	    }
+ 	    /* but set only if the user didn't specify the orientation
+ 	       on the command line */
+ 	    if (!orientspec)
+-		landscape = !strncasecmp(buf,"land",4);
++		landscape = !strncasecmp(line, "land", 4);
+ 
+ 	    /* now read the metric/inches spec OR centering spec */
+-	    if (get_line(fp) < 0) {
++	    if (get_line(fp, &line, &line_len, &line_no) < 0) {
+ 		put_msg("File is truncated at metric/inches or centering specification.");
++		free(line);
+ 		return -1;
+ 	    }
+ 	    /* read justification spec */
+-	    if ((strncasecmp(buf,"center",6) == 0) ||
+-		(strncasecmp(buf,"flush",5) == 0)) {
++	    if ((strncasecmp(line, "center", 6) == 0) ||
++		(strncasecmp(line, "flush", 5) == 0)) {
+ 		/* but set only if user didn't specify it */
+ 		if (!centerspec)
+-		    center = strncasecmp(buf,"flush",5);
++		    center = strncasecmp(line, "flush", 5);
+ 		/* now read metric/inches spec */
+-		if (get_line(fp) < 0) {
++		if (get_line(fp, &line, &line_len, &line_no) < 0) {
+ 		    put_msg("File is truncated at metric/inches specification.");
++		    free(line);
+ 		    return -1;
+ 		}
+ 	    }
+ 	    /* read metric/inches spec */
+ 	    /* if metric, scale magnification to correct for xfig display error */
+-	    if (strncasecmp(buf,"metric", 6) == 0) {
++	    if (strncasecmp(line, "metric", 6) == 0) {
+ 		metric = 1;
+ 	    } else {
+ 		metric = 0;
+@@ -261,56 +283,67 @@ read_objects(FILE *fp, F_compound *obj)
+ 
+ 	    /* new stuff in 3.2 */
+ 	    if (v32_flag) {
+-		char *p;
+ 		/* read the paper size */
+-		if (get_line(fp) < 0) {
++		if (get_line(fp, &line, &line_len, &line_no) < 0) {
+ 		    put_msg("File is truncated at paper size specification.");
++		    free(line);
+ 		    return -1;
+ 		}
+ 		if (!paperspec) {
+-		    strcpy(papersize,buf);
+-		    /* and truncate at first blank, if any */
+-		    if ((p=strchr(papersize,' ')))
++		    char *p;
++		    /* truncate at first blank, if any */
++		    if ((p = strchr(line, ' ')))
+ 			*p = '\0';
++		    if (strlen(line) + 1 > sizeof papersize) {
++			put_msg("Invalid paper size specification at line %d: %s",
++					line_no, line);
++			free(line);
++			return -1;
++		    }
++		    strcpy(papersize, line);
+ 		}
+ 
+ 		/* read the magnification */
+-		if (get_line(fp) < 0) {
++		if (get_line(fp, &line, &line_len, &line_no) < 0) {
+ 		    put_msg("File is truncated at magnification specification.");
++		    free(line);
+ 		    return -1;
+ 		}
+-		/* if the users hasn't specified a magnification on the command line,
+-		   use the one in the file */
++		/* if the users hasn't specified a magnification on
++		   the command line, use the one in the file */
+ 		if (!magspec) {
+-		    mag = atof(buf)/100.0;
++		    mag = atof(line)/100.0;
+ 		    if (mag <= 0.)
+ 			mag = 1.;
+ 		    fontmag = mag;
+ 		}
+ 
+ 		/* read the multiple page flag */
+-		if (get_line(fp) < 0) {
++		if (get_line(fp, &line, &line_len, &line_no) < 0) {
+ 		    put_msg("File is truncated at multiple page specification.");
++		    free(line);
+ 		    return -1;
+ 		}
+ 		if (!multispec)
+-		    multi_page = (strncasecmp(buf,"multiple",8) == 0);
++		    multi_page = (strncasecmp(line, "multiple", 8) == 0);
+ 
+ 		/* Read the GIF transparent color. */
+-		if (get_line(fp) < 0) {
++		if (get_line(fp, &line, &line_len, &line_no) < 0) {
+ 		    put_msg("File is truncated at transparent color specification.");
++		    free(line);
+ 		    return -1;
+ 		}
+ 		if (!transspec) {
+-		    gif_colnum = atoi(buf);
++		    gif_colnum = atoi(line);
+ 		    if (gif_colnum < -3) {
+ 			put_msg("Invalid color number for transparent color.");
++			free(line);
+ 			return -1;
+ 		    }
+ 		    /* if standard color, get the name from the array */
+ 		    /* for user colors, wait till we've read in the file to get the value */
+ 		    if (gif_colnum < NUM_STD_COLS && gif_colnum >= 0)
+-			strcpy(gif_transparent,Fig_color_names[gif_colnum]);
++			strcpy(gif_transparent, Fig_color_names[gif_colnum]);
+ 		}
+ 	    }
+ 	} else {
+@@ -329,17 +362,20 @@ read_objects(FILE *fp, F_compound *obj)
+ 	}
+ 
+ 	/* now read for resolution and coord_sys (coord_sys is not used) */
+-	if (get_line(fp) < 0) {
++	if (get_line(fp, &line, &line_len, &line_no) < 0) {
+ 	    put_msg("File is truncated at resolution specification.");
++	    free(line);
+ 	    return -1;
+ 	}
+-	if (sscanf(buf,"%lf%d\n", &ppi, &coord_sys) != 2) {
++	if (sscanf(line, "%lf%d", &ppi, &coord_sys) != 2) {
+ 	    put_msg("Incomplete resolution information at line %d.", line_no);
++	    free(line);
+ 	    return -1;
+ 	}
+ 	if (ppi <= 0.) {
+ 	    put_msg("Invalid resolution information (%g) at line %d.",
+ 		    ppi, line_no);
++	    free(line);
+ 	    return -1;
+ 	}
+ 
+@@ -349,24 +385,28 @@ read_objects(FILE *fp, F_compound *obj)
+ 	/* attach any comments found thus far to the whole figure */
+ 	obj->comments = attach_comments();
+ 
+-	while (get_line(fp) > 0) {
+-	    if (sscanf(buf, "%d", &object) != 1) {
++	while (get_line(fp, &line, &line_len, &line_no) > 0) {
++	    if (sscanf(line, "%d", &object) != 1) {
+ 		put_msg("Incorrect format at line %d.", line_no);
++		free(line);
+ 		return -1;
+ 	    }
+ 	    switch (object) {
+ 		case OBJ_COLOR_DEF:
+-		    read_colordef();
+-		    if (num_object) {
++		    if (objects) {
+ 			put_msg("Color definitions must come before other objects (line %d).",
+ 				line_no);
+-			return (-1);
++			free(line);
++			return -1;
+ 		    }
+-		    ++num_usr_cols;
++		    read_colordef(line, line_no);
+ 		    break;
+ 		case OBJ_POLYLINE :
+-		    if ((l = read_lineobject(fp)) == NULL)
++		    if ((l = read_lineobject(fp, &line, &line_len, &line_no)) ==
++				NULL) {
++			free(line);
+ 			return -1;
++		    }
+ #ifdef V4_0
+ 		    if ((l->pic != NULL) && (l->pic->figure != NULL)) {
+ 			if (lc)
+@@ -388,79 +428,97 @@ read_objects(FILE *fp, F_compound *obj)
+ 			ll = (ll->next = l);
+ 		    else
+ 			ll = obj->lines = l;
+-		    num_object++;
++		    objects = true;
+ 		    break;
+ #endif /* V4_0 */
+ 		case OBJ_SPLINE :
+-		    if ((s = read_splineobject(fp)) == NULL) {
++		    if ((s = read_splineobject(fp, &line, &line_len, &line_no))
++				== NULL) {
++			free(line);
+ 			return -1;
+-			}
++		    }
+ 		    if (v32_flag){ /* s is a line */
+ 		      if (ll)
+ 			ll = (ll->next = (F_line *) s);
+ 		      else
+ 			ll = obj->lines = (F_line *) s;
+-		      num_object++;
++		      objects = true;
+ 		      break;
+ 		    }
+ 		    if (ls)
+ 			ls = (ls->next = s);
+ 		    else
+ 			ls = obj->splines = s;
+-		    num_object++;
++		    objects = true;
+ 		    break;
+ 		case OBJ_ELLIPSE :
+-		    if ((e = read_ellipseobject()) == NULL)
++		    if ((e = read_ellipseobject(line, line_no)) == NULL) {
++			free(line);
+ 			return -1;
++		    }
+ 		    if (le)
+ 			le = (le->next = e);
+ 		    else
+ 			le = obj->ellipses = e;
+-		    num_object++;
++		    objects = true;
+ 		    break;
+ 		case OBJ_ARC :
+-		    if ((a = read_arcobject(fp)) == NULL)
++		    if ((a = read_arcobject(fp, &line, &line_len, &line_no)) ==
++				NULL) {
++			free(line);
+ 			return -1;
++		    }
+ 		    if (la)
+ 			la = (la->next = a);
+ 		    else
+ 			la = obj->arcs = a;
+-		    num_object++;
++		    objects = true;
+ 		    break;
+ 		case OBJ_TEXT :
+-		    if ((t = read_textobject(fp)) == NULL)
++		    if ((t = read_textobject(fp, &line, &line_len, &line_no)) ==
++				NULL) {
++			free(line);
+ 			return -1;
++		    }
+ 		    if (lt)
+ 			lt = (lt->next = t);
+ 		    else
+ 			lt = obj->texts = t;
+-		    num_object++;
++		    objects = true;
+ 		    break;
+ 		case OBJ_COMPOUND :
+-		    if ((c = read_compoundobject(fp)) == NULL)
++		    if ((c = read_compoundobject(fp, &line, &line_len,&line_no))
++				== NULL) {
++			free(line);
+ 			return -1;
++		    }
+ 		    if (lc)
+ 			lc = (lc->next = c);
+ 		    else
+ 			lc = obj->compounds = c;
+-		    num_object++;
++		    objects = true;
+ 		    break;
+ 		default :
+ 		    put_msg("Incorrect object code at line %d.", line_no);
++		    free(line);
+ 		    return -1;
+ 		} /*  switch */
+-	} /*  while (get_line(fp)) */
++	} /*  while (get_line(...)) */
++	free(line);
+ 
+ 	/* if user color was requested for GIF transparent color, get the
+ 	   rgb values from the user color array now that we've read them in */
+ 	if (gif_colnum >= NUM_STD_COLS) {
+ 	    int i;
+-	    for (i=0; i<num_usr_cols; ++i)
++	    /* read_colordef() counted, but ignored too many user colors */
++	    if (num_usr_cols > MAX_USR_COLS)
++		    num_usr_cols = MAX_USR_COLS;
++	    for (i=0; i < num_usr_cols; ++i)
+ 		if (user_col_indx[i] == gif_colnum)
+ 		    break;
+ 	    if (i < num_usr_cols)
+-		sprintf(gif_transparent,"#%2x%2x%2x",
+-				user_colors[i].r,user_colors[i].g,user_colors[i].b);
++		sprintf(gif_transparent, "#%2x%2x%2x",
++			user_colors[i].r, user_colors[i].g, user_colors[i].b);
+ 	}
+ 
+ 	if (feof(fp))
+@@ -474,55 +532,72 @@ read_objects(FILE *fp, F_compound *obj)
+ } /*  read_objects */
+ 
+ static void
+-read_colordef(void)
++read_colordef(char *line, int line_no)
+ {
+-    int			c;
+-    unsigned int	r,g,b;
++	int		c;
++	unsigned int	r,g,b;
+ 
+-    if ((sscanf(buf, "%*d %d #%2x%2x%2x", &c, &r, &g, &b) != 4) ||
+-		(c < NUM_STD_COLS)) {
+-	buf[strlen(buf)-1]='\0';	/* remove the newline */
+-	put_msg("Invalid color definition: %s, setting to black (#00000).",buf);
+-	r=g=b=0;
+-    }
+-    user_col_indx[num_usr_cols] = c;
+-    user_colors[num_usr_cols].r = r;
+-    user_colors[num_usr_cols].g = g;
+-    user_colors[num_usr_cols].b = b;
++	if (num_usr_cols >= MAX_USR_COLS) {
++		if (num_usr_cols == MAX_USR_COLS) {
++			put_msg("Maximum number of color definitions (%d) exceeded at line %d.",
++					MAX_USR_COLS, line_no);
++			++num_usr_cols;
++		}
++		/* ignore additional colors */
++		return;
++	}
++	if (sscanf(line, "%*d %d #%2x%2x%2x", &c, &r, &g, &b) != 4) {
++		if (c >= NUM_STD_COLS && c < NUM_STD_COLS + MAX_USR_COLS) {
++			put_msg("Invalid color definition at line %d: %s, setting to black (#00000).",
++					line_no, line);
++			r = g = b = 0;
++		} else {
++			put_msg("User color number at line %d out of range (%d), should be between %d and %d.",
++					line_no, c, NUM_STD_COLS,
++					NUM_STD_COLS + MAX_USR_COLS - 1);
++			return;
++		}
++	}
++	user_col_indx[num_usr_cols] = c;
++	user_colors[num_usr_cols].r = r;
++	user_colors[num_usr_cols].g = g;
++	user_colors[num_usr_cols].b = b;
++	++num_usr_cols;
+ }
+ 
+ static void
+-fix_and_note_color(int *color)
++fix_and_note_color(int *color, int line_no)
+ {
+-    int		    i;
+-    if (*color < DEFAULT) {
+-	put_msg("Invalid color number %d at line %d, using default color.",
+-			*color, line_no);
+-	*color = DEFAULT;
+-	return;
+-    }
+-    if (*color < NUM_STD_COLS) {
+-	if (*color >= BLACK_COLOR) {
+-	    std_color_used[*color] = true;
++	int	i;
++
++	if (*color < DEFAULT) {
++		put_msg("Invalid color number %d at line %d, using default color.",
++				*color, line_no);
++		*color = DEFAULT;
++		return;
+ 	}
+-	return;
+-    }
+-    for (i=0; i<num_usr_cols; ++i)
+-	if (*color == user_col_indx[i]) {
+-		*color = i + NUM_STD_COLS;
++	if (*color < NUM_STD_COLS) {
++		if (*color >= BLACK_COLOR) {
++			std_color_used[*color] = true;
++		}
+ 		return;
+ 	}
+-    put_msg("Cannot locate user color %d, using default color at line %d.",
+-		*color, line_no);
+-    *color = DEFAULT;
+-    return;
++	for (i = 0; i < MIN(num_usr_cols, MAX_USR_COLS); ++i)
++		if (*color == user_col_indx[i]) {
++			*color = i + NUM_STD_COLS;
++			return;
++		}
++	put_msg("Cannot locate user color %d, using default color at line %d.",
++			*color, line_no);
++	*color = DEFAULT;
++	return;
+ }
+ 
+ static void
+-note_fill(int fill, int *color)
++note_fill(int fill, int *color, int line_no)
+ {
+ 	if (fill != UNFILLED) {
+-		fix_and_note_color(color);
++		fix_and_note_color(color, line_no);
+ 		if (fill >= NUMSHADES + NUMTINTS) {
+ 			pattern_used[fill - NUMSHADES - NUMTINTS] = true;
+ 			pats_used = true;
+@@ -531,7 +606,7 @@ note_fill(int fill, int *color)
+ }
+ 
+ static F_arc *
+-read_arcobject(FILE *fp)
++read_arcobject(FILE *fp, char **restrict line, size_t *line_len, int *line_no)
+ {
+ 	F_arc	*a;
+ 	int	n, fa, ba;
+@@ -548,7 +623,7 @@ read_arcobject(FILE *fp)
+ 	a->back_arrow = NULL;
+ 	a->next = NULL;
+ 	if (v30_flag) {
+-	    n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d%lf%lf%d%d%d%d%d%d\n",
++	    n = sscanf(*line,"%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d%lf%lf%d%d%d%d%d%d",
+ 		&a->type, &a->style, &a->thickness,
+ 		&a->pen_color, &a->fill_color, &a->depth, &a->pen, &a->fill_style,
+ 		&a->style_val, &a->cap_style,
+@@ -558,7 +633,7 @@ read_arcobject(FILE *fp)
+ 		&a->point[1].x, &a->point[1].y,
+ 		&a->point[2].x, &a->point[2].y);
+ 	} else {
+-	    n = sscanf(buf, "%*d%d%d%d%d%d%d%d%lf%d%d%d%lf%lf%d%d%d%d%d%d\n",
++	    n = sscanf(*line, "%*d%d%d%d%d%d%d%d%lf%d%d%d%lf%lf%d%d%d%d%d%d",
+ 		&a->type, &a->style, &a->thickness,
+ 		&a->pen_color, &a->depth, &a->pen, &a->fill_style,
+ 		&a->style_val, &a->direction, &fa, &ba,
+@@ -570,45 +645,45 @@ read_arcobject(FILE *fp)
+ 	    a->cap_style = 0;        /* butt line cap */
+ 	}
+ 	if ((v30_flag && n != 21) || (!v30_flag && n != 19)) {
+-	    put_msg(Err_incomp, "arc", line_no);
++	    put_msg(Err_incomp, "arc", *line_no);
+ 	    free(a);
+ 	    return NULL;
+ 	}
+ 	a->thickness *= round(THICK_SCALE);
+ 	a->fill_style = FILL_CONVERT(a->fill_style);
+ 	if (INVALID_ARC(a)) {
+-		put_msg(Err_invalid, "arc", line_no);
++		put_msg(Err_invalid, "arc", *line_no);
+ 		free(a);
+ 		return NULL;
+ 	}
+-	fix_and_note_color(&a->pen_color);
+-	note_fill(a->fill_style, &a->fill_color);
++	fix_and_note_color(&a->pen_color, *line_no);
++	note_fill(a->fill_style, &a->fill_color, *line_no);
+ 	if (fa) {
+-	    if (get_line(fp) < 0 ||
+-	        sscanf(buf, "%d%d%lf%lf%lf",
++	    if (get_line(fp, line, line_len, line_no) < 0 ||
++	        sscanf(*line, "%d%d%lf%lf%lf",
+ 				&type, &style, &thickness, &wid, &ht) != 5) {
+-		    put_msg(Err_incomp, "arc", line_no);
++		    put_msg(Err_incomp, "arc", *line_no);
+ 		    free(a);
+ 		    return NULL;
+ 	    }
+ 	    if ((a->for_arrow = make_arrow(type, style, thickness, wid, ht))
+ 			    == NULL) {
+-		    put_msg(Err_arrow, "forward", line_no);
++		    put_msg(Err_arrow, "forward", *line_no);
+ 		    free(a);
+ 		    return NULL;
+ 	    }
+ 	}
+ 	if (ba) {
+-	    if (get_line(fp) < 0 ||
+-	        sscanf(buf, "%d%d%lf%lf%lf",
++	    if (get_line(fp, line, line_len, line_no) < 0 ||
++	        sscanf(*line, "%d%d%lf%lf%lf",
+ 				&type, &style, &thickness, &wid, &ht) != 5) {
+-		    put_msg(Err_incomp, "arc", line_no);
++		    put_msg(Err_incomp, "arc", *line_no);
+ 		    free(a);
+ 		    return NULL;
+ 	    }
+ 	    if ((a->back_arrow = make_arrow(type, style, thickness, wid, ht))
+ 			    == NULL) {
+-		    put_msg(Err_arrow, "backward", line_no);
++		    put_msg(Err_arrow, "backward", *line_no);
+ 		    free(a);
+ 		    return NULL;
+ 	    }
+@@ -618,7 +693,8 @@ read_arcobject(FILE *fp)
+ }
+ 
+ static F_compound *
+-read_compoundobject(FILE *fp)
++read_compoundobject(FILE *fp, char **restrict line, size_t *line_len,
++		int *line_no)
+ {
+ 	F_arc		*a, *la = NULL;
+ 	F_ellipse	*e, *le = NULL;
+@@ -638,22 +714,23 @@ read_compoundobject(FILE *fp)
+ 	com->next = NULL;
+ 	com->comments = attach_comments();	/* attach any comments */
+ 
+-	n = sscanf(buf, "%*d%d%d%d%d\n", &com->nwcorner.x, &com->nwcorner.y,
++	n = sscanf(*line, "%*d%d%d%d%d", &com->nwcorner.x, &com->nwcorner.y,
+ 		&com->secorner.x, &com->secorner.y);
+ 	if (n != 4) {
+-	    put_msg(Err_incomp, "compound", line_no);
++	    put_msg(Err_incomp, "compound", *line_no);
+ 	    free(com);
+ 	    return NULL;
+ 	    }
+-	while (get_line(fp) > 0) {
+-	    if (sscanf(buf, "%d", &object) != 1) {
+-		put_msg(Err_incomp, "compound", line_no);
++	while (get_line(fp, line, line_len, line_no) > 0) {
++	    if (sscanf(*line, "%d", &object) != 1) {
++		put_msg(Err_incomp, "compound", *line_no);
+ 		free_compound(&com);
+ 		return NULL;
+-		}
++	    }
+ 	    switch (object) {
+ 		case OBJ_POLYLINE :
+-		    if ((l = read_lineobject(fp)) == NULL) {
++		    if ((l = read_lineobject(fp, line, line_len, line_no)) ==
++				    NULL) {
+ 			return NULL;
+ 			}
+ #ifdef V4_0
+@@ -674,7 +751,8 @@ read_compoundobject(FILE *fp)
+ #endif /* V4_0 */
+ 		    break;
+ 		case OBJ_SPLINE :
+-		    if ((s = read_splineobject(fp)) == NULL) {
++		    if ((s = read_splineobject(fp, line, line_len, line_no)) ==
++				    NULL) {
+ 			return NULL;
+ 			}
+ 		    if (v32_flag){ /* s is a line */
+@@ -690,7 +768,7 @@ read_compoundobject(FILE *fp)
+ 			ls = com->splines = s;
+ 		    break;
+ 		case OBJ_ELLIPSE :
+-		    if ((e = read_ellipseobject()) == NULL) {
++		    if ((e = read_ellipseobject(*line, *line_no)) == NULL) {
+ 			return NULL;
+ 			}
+ 		    if (le)
+@@ -699,7 +777,8 @@ read_compoundobject(FILE *fp)
+ 			le = com->ellipses = e;
+ 		    break;
+ 		case OBJ_ARC :
+-		    if ((a = read_arcobject(fp)) == NULL) {
++		    if ((a = read_arcobject(fp, line, line_len, line_no)) ==
++				    NULL) {
+ 			return NULL;
+ 			}
+ 		    if (la)
+@@ -708,7 +787,8 @@ read_compoundobject(FILE *fp)
+ 			la = com->arcs = a;
+ 		    break;
+ 		case OBJ_TEXT :
+-		    if ((t = read_textobject(fp)) == NULL) {
++		    if ((t = read_textobject(fp, line, line_len, line_no)) ==
++				    NULL) {
+ 			return NULL;
+ 			}
+ 		    if (lt)
+@@ -717,7 +797,8 @@ read_compoundobject(FILE *fp)
+ 			lt = com->texts = t;
+ 		    break;
+ 		case OBJ_COMPOUND :
+-		    if ((c = read_compoundobject(fp)) == NULL) {
++		    if ((c = read_compoundobject(fp, line, line_len, line_no))
++				    == NULL) {
+ 			return NULL;
+ 			}
+ 		    if (lc)
+@@ -728,7 +809,7 @@ read_compoundobject(FILE *fp)
+ 		case OBJ_END_COMPOUND :
+ 		    return com;
+ 		default :
+-		    put_msg("Wrong object code at line %d", line_no);
++		    put_msg("Wrong object code at line %d", *line_no);
+ 		    return NULL;
+ 		} /*  switch */
+ 	    }
+@@ -739,7 +820,7 @@ read_compoundobject(FILE *fp)
+ 	}
+ 
+ static F_ellipse *
+-read_ellipseobject(void)
++read_ellipseobject(char *line, int line_no)
+ {
+ 	F_ellipse	*e;
+ 	int		n;
+@@ -749,7 +830,7 @@ read_ellipseobject(void)
+ 	e->pen = 0;
+ 	e->next = NULL;
+ 	if (v30_flag) {
+-	    n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%lf%d%lf%d%d%d%d%d%d%d%d\n",
++	    n = sscanf(line, "%*d%d%d%d%d%d%d%d%d%lf%d%lf%d%d%d%d%d%d%d%d",
+ 		&e->type, &e->style, &e->thickness,
+ 		&e->pen_color, &e->fill_color, &e->depth, &e->pen, &e->fill_style,
+ 		&e->style_val, &e->direction, &e->angle,
+@@ -758,7 +839,7 @@ read_ellipseobject(void)
+ 		&e->start.x, &e->start.y,
+ 		&e->end.x, &e->end.y);
+ 	} else {
+-	    n = sscanf(buf, "%*d%d%d%d%d%d%d%d%lf%d%lf%d%d%d%d%d%d%d%d\n",
++	    n = sscanf(line, "%*d%d%d%d%d%d%d%d%lf%d%lf%d%d%d%d%d%d%d%d",
+ 		&e->type, &e->style, &e->thickness,
+ 		&e->pen_color, &e->depth, &e->pen, &e->fill_style,
+ 		&e->style_val, &e->direction, &e->angle,
+@@ -773,7 +854,7 @@ read_ellipseobject(void)
+ 	    free(e);
+ 	    return NULL;
+ 	    }
+-	fix_and_note_color(&e->pen_color);
++	fix_and_note_color(&e->pen_color, line_no);
+ 	e->thickness *= round(THICK_SCALE);
+ 	e->fill_style = FILL_CONVERT(e->fill_style);
+ 	if (INVALID_ELLIPSE(e)) {
+@@ -781,7 +862,7 @@ read_ellipseobject(void)
+ 		free(e);
+ 		return NULL;
+ 	}
+-	note_fill(e->fill_style, &e->fill_color);
++	note_fill(e->fill_style, &e->fill_color, line_no);
+ 	e->comments = attach_comments();	/* attach any comments */
+ 	return e;
+ }
+@@ -798,8 +879,9 @@ read_ellipseobject(void)
+  */
+ static int
+ sanitize_lineobject(
+-	F_line *l,	/* the line */
+-	F_point *p	/* the last point of the line */
++	F_line	*l,	/* the line */
++	F_point	*p,	/* the last point of the line */
++	int	line_no
+ 	)
+ {
+ 	F_point	*q;
+@@ -886,7 +968,7 @@ sanitize_lineobject(
+ }
+ 
+ static F_line *
+-read_lineobject(FILE *fp)
++read_lineobject(FILE *fp, char **restrict line, size_t *line_len, int *line_no)
+ {
+ 	F_line	*l;
+ 	F_point	*o = NULL, *p, *q;
+@@ -907,40 +989,38 @@ read_lineobject(FILE *fp)
+ 	l->pic = NULL;
+ 	l->comments = NULL;
+ 
+-	sscanf(buf,"%*d%d",&l->type);	/* get the line type */
++	sscanf(*line, "%*d%d", &l->type);	/* get the line type */
+ 
+ 	radius_flag = v30_flag || v21_flag || (v2_flag && l->type == T_ARC_BOX);
+ 	if (radius_flag) {
+ 	    if (v30_flag) {
+-		n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d%d%d",
++		n = sscanf(*line, "%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d%d%d",
+ 		&l->type,&l->style,&l->thickness,&l->pen_color,&l->fill_color,
+ 		&l->depth,&l->pen,&l->fill_style,&l->style_val,
+ 		&l->join_style,&l->cap_style,
+ 		&l->radius,&fa,&ba,&npts);
+ 	    } else {
+-		n = sscanf(buf, "%*d%d%d%d%d%d%d%d%lf%d%d%d",
+-		&l->type,&l->style,&l->thickness,&l->pen_color,
+-		&l->depth,&l->pen,&l->fill_style,&l->style_val,&l->radius,&fa, &ba);
++		n = sscanf(*line, "%*d%d%d%d%d%d%d%d%lf%d%d%d",
++		&l->type,&l->style,&l->thickness,&l->pen_color,&l->depth,
++		&l->pen,&l->fill_style,&l->style_val,&l->radius,&fa, &ba);
+ 		l->fill_color = l->pen_color;
+ 	    }
+ 	}
+ 	/* old format uses pen for radius of arc-box corners */
+ 	else {
+-	    n = sscanf(buf, "%*d%d%d%d%d%d%d%d%lf%d%d",
++	    n = sscanf(*line, "%*d%d%d%d%d%d%d%d%lf%d%d",
+ 			&l->type,&l->style,&l->thickness,&l->pen_color,
+ 			&l->depth,&l->pen,&l->fill_style,&l->style_val,&fa,&ba);
+ 	    l->fill_color = l->pen_color;
+-	    if (l->type == T_ARC_BOX)
+-		{
+-		l->radius = (int) l->pen;
++	    if (l->type == T_ARC_BOX) {
++		l->radius = l->pen;
+ 		l->pen = 0;
+-		}
+-	    else
++	    } else
+ 		l->radius = 0;
+ 	}
+ 	if ((!radius_flag && n!=10) ||
+ 	     (radius_flag && ((!v30_flag && n!=11)||(v30_flag && n!=15)))) {
+-	    put_msg(Err_incomp, "line", line_no);
++	    put_msg(Err_incomp, "line", *line_no);
+ 	    free(l);
+ 	    return NULL;
+ 	}
+@@ -948,45 +1028,47 @@ read_lineobject(FILE *fp)
+ 	l->thickness *= round(THICK_SCALE);
+ 	l->fill_style = FILL_CONVERT(l->fill_style);
+ 	if (INVALID_LINE(l)) {
+-		put_msg(Err_invalid, "line", line_no);
++		put_msg(Err_invalid, "line", *line_no);
+ 		free(l);
+ 		return NULL;
+ 	}
+-	note_fill(l->fill_style, &l->fill_color);
+-	fix_and_note_color(&l->pen_color);
++	note_fill(l->fill_style, &l->fill_color, *line_no);
++	fix_and_note_color(&l->pen_color, *line_no);
+ 	if (fa) {
+-	    if (get_line(fp) < 0 ||
+-			sscanf(buf, "%d%d%lf%lf%lf",
++	    if (get_line(fp, line, line_len, line_no) < 0 ||
++			sscanf(*line, "%d%d%lf%lf%lf",
+ 				&type, &style, &thickness, &wid, &ht) != 5) {
+-		put_msg(Err_incomp, "line", line_no);
++		put_msg(Err_incomp, "line", *line_no);
+ 		free(l);
+ 		return NULL;
+ 	    }
+ 	    if ((l->for_arrow = make_arrow(type, style, thickness, wid, ht))
+ 			    == NULL) {
+-		    put_msg(Err_arrow, "forward", line_no);
++		    put_msg(Err_arrow, "forward", *line_no);
+ 		    free(l);
+ 		    return NULL;
+ 	    }
+ 	}
+ 	if (ba) {
+-	    if (get_line(fp) < 0 ||
+-			sscanf(buf, "%d%d%lf%lf%lf",
++	    if (get_line(fp, line, line_len, line_no) < 0 ||
++			sscanf(*line, "%d%d%lf%lf%lf",
+ 				&type, &style, &thickness, &wid, &ht) != 5) {
+-		put_msg(Err_incomp, "line", line_no);
++		put_msg(Err_incomp, "line", *line_no);
+ 		free_linestorage(l);
+ 		return NULL;
+ 	    }
+ 	    if ((l->back_arrow = make_arrow(type, style, thickness, wid, ht))
+ 			    == NULL) {
+-		    put_msg(Err_arrow, "backward", line_no);
++		    put_msg(Err_arrow, "backward", *line_no);
+ 		    free_linestorage(l);
+ 		    return NULL;
+ 	    }
+ 	}
+ 	if (l->type == T_PIC_BOX) {
+-	    char	file[BUFSIZ], *c;
++	    char	*file, *c;
++	    int		pos;
+ 	    size_t	len;
++	    ssize_t	chars;
+ 
+ 	    if ((Pic_malloc(l->pic)) == NULL) {
+ 		free(l);
+@@ -1000,21 +1082,22 @@ read_lineobject(FILE *fp)
+ 	    XpmCreateXpmImageFromBuffer("", &l->pic->xpmimage, NULL);
+ #endif
+ 
+-			/* %[^\n]: really, read until first '\0' in buf */
+-	    if (get_line(fp) < 0 || sscanf(buf, "%d %[^\n]",
+-					&l->pic->flipped, file) != 2) {
+-	        put_msg(Err_incomp, "picture", line_no);
+-		free(l);
+-	        return NULL;
++	    if ((chars = get_line(fp, line, line_len, line_no)) < 0 ||
++			  sscanf(*line, "%d %n", &l->pic->flipped, &pos) != 1) {
++		    put_msg(Err_incomp, "picture", *line_no);
++		    free(l);
++		    return NULL;
+ 	    }
++	    file = *line + pos;
++	    len = chars - pos;	/* strlen(file) */
++
+ 	    /* if there is a path in the .fig filename, and the path of the
+ 	     * imported picture filename is NOT absolute, prepend the
+ 	     * .fig file path to it
+ 	     */
+ 	    if (from && (c = strrchr(from, '/')) && file[0] != '/') {
+-		if ((l->pic->file = malloc((size_t)(c - from + 2) +
+-				    (len = strlen(file)))) ==
+-			NULL) {
++		if ((l->pic->file = malloc((size_t)(c - from + 2) + len)) ==
++				NULL) {
+ 		    put_msg(Err_mem);
+ 		    free(l);	/* Points not read yet. */
+ 		    return NULL;
+@@ -1023,8 +1106,8 @@ read_lineobject(FILE *fp)
+ 		memcpy(l->pic->file + (c - from + 1), file, len + 1);
+ 	    } else {
+ 		/* either absolute picture path or no path in .fig filename */
+-		l->pic->file = malloc(len = strlen(file) + 1);
+-		memcpy(l->pic->file, file, len);
++		l->pic->file = malloc(len + 1);
++		memcpy(l->pic->file, file, len + 1);
+ 	    }
+ 	}
+ 
+@@ -1036,9 +1119,9 @@ read_lineobject(FILE *fp)
+ 	p->next = NULL;
+ 
+ 	/* read first point of line */
+-	++line_no;
++	++(*line_no);
+ 	if (fscanf(fp, "%d%d", &p->x, &p->y) != 2) {
+-	    put_msg(Err_incomp, "line", line_no);
++	    put_msg(Err_incomp, "line", *line_no);
+ 	    free_linestorage(l);
+ 	    return NULL;
+ 	}
+@@ -1046,9 +1129,9 @@ read_lineobject(FILE *fp)
+ 	if (!v30_flag)
+ 	    npts = 1000000;
+ 	for (--npts; npts > 0; --npts) {
+-	    count_lines_correctly(fp);
++	    count_lines_correctly(fp, line_no);
+ 	    if (fscanf(fp, "%d%d", &x, &y) != 2) {
+-		put_msg(Err_incomp, "line", line_no);
++		put_msg(Err_incomp, "line", *line_no);
+ 		free_linestorage(l);
+ 		return NULL;
+ 	    }
+@@ -1077,7 +1160,7 @@ read_lineobject(FILE *fp)
+ 	    l->last[1].y = o->y;
+ 	}
+ 
+-	if (sanitize_lineobject(l, p)) {
++	if (sanitize_lineobject(l, p, *line_no)) {
+ 	    free_linestorage(l);
+ 	    return NULL;
+ 	}
+@@ -1089,7 +1172,8 @@ read_lineobject(FILE *fp)
+ }
+ 
+ static F_spline *
+-read_splineobject(FILE *fp)
++read_splineobject(FILE *fp, char **restrict line, size_t *line_len,
++		int *line_no)
+ {
+ 	F_spline	*s;
+ 	F_line          *l;
+@@ -1111,58 +1195,58 @@ read_splineobject(FILE *fp)
+ 	s->next = NULL;
+ 
+ 	if (v30_flag) {
+-	    n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d",
++	    n = sscanf(*line, "%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d",
+ 		&s->type, &s->style, &s->thickness,
+ 		&s->pen_color, &s->fill_color,
+ 		&s->depth, &s->pen, &s->fill_style, &s->style_val,
+ 		&s->cap_style, &fa, &ba, &npts);
+ 	} else {
+-	    n = sscanf(buf, "%*d%d%d%d%d%d%d%d%lf%d%d",
++	    n = sscanf(*line, "%*d%d%d%d%d%d%d%d%lf%d%d",
+ 		&s->type, &s->style, &s->thickness, &s->pen_color,
+ 		&s->depth, &s->pen, &s->fill_style, &s->style_val, &fa, &ba);
+ 	    s->fill_color = s->pen_color;
+ 	    s->cap_style = 0;        /* butt line cap */
+ 	}
+ 	if ((v30_flag && n != 13) || (!v30_flag && n != 10)) {
+-	    put_msg(Err_incomp, "spline", line_no);
++	    put_msg(Err_incomp, "spline", *line_no);
+ 	    free(s);
+ 	    return NULL;
+ 	    }
+ 	s->thickness *= round(THICK_SCALE);
+ 	s->fill_style = FILL_CONVERT(s->fill_style);
+ 	if (INVALID_SPLINE(s)) {
+-		put_msg(Err_invalid, "spline", line_no);
++		put_msg(Err_invalid, "spline", *line_no);
+ 		free(s);
+ 		return NULL;
+ 	}
+-	note_fill(s->fill_style, &s->fill_color);
+-	fix_and_note_color(&s->pen_color);
++	note_fill(s->fill_style, &s->fill_color, *line_no);
++	fix_and_note_color(&s->pen_color, *line_no);
+ 	if (fa) {
+-	    if (get_line(fp) < 0 ||
+-			    sscanf(buf, "%d%d%lf%lf%lf",
++	    if (get_line(fp, line, line_len, line_no) < 0 ||
++			    sscanf(*line, "%d%d%lf%lf%lf",
+ 				    &type, &style, &thickness, &wid, &ht) != 5) {
+-		    put_msg(Err_incomp, "spline", line_no);
++		    put_msg(Err_incomp, "spline", *line_no);
+ 		    free(s);
+ 		    return NULL;
+ 	    }
+ 	    if ((s->for_arrow = make_arrow(type, style, thickness, wid, ht))
+ 			    == NULL) {
+-		    put_msg(Err_arrow, "forward", line_no);
++		    put_msg(Err_arrow, "forward", *line_no);
+ 		    free(s);
+ 		    return NULL;
+ 	    }
+ 	}
+ 	if (ba) {
+-	    if (get_line(fp) < 0 ||
+-			    sscanf(buf, "%d%d%lf%lf%lf",
++	    if (get_line(fp, line, line_len, line_no) < 0 ||
++			    sscanf(*line, "%d%d%lf%lf%lf",
+ 				    &type, &style, &thickness, &wid, &ht) != 5) {
+-		    put_msg(Err_incomp, "spline", line_no);
++		    put_msg(Err_incomp, "spline", *line_no);
+ 		    free_splinestorage(s);
+ 		    return NULL;
+ 	    }
+ 	    if ((s->back_arrow = make_arrow(type, style, thickness, wid, ht))
+ 			    == NULL) {
+-		    put_msg(Err_arrow, "backward", line_no);
++		    put_msg(Err_arrow, "backward", *line_no);
+ 		    free_splinestorage(s);
+ 		    return NULL;
+ 	    }
+@@ -1170,9 +1254,9 @@ read_splineobject(FILE *fp)
+ 
+ 	/* Read points */
+ 	/* read first point of line */
+-	++line_no;
++	++(*line_no);
+ 	if ((n = fscanf(fp, "%d%d", &x, &y)) != 2) {
+-	    put_msg(Err_incomp, "spline", line_no);
++	    put_msg(Err_incomp, "spline", *line_no);
+ 	    free_splinestorage(s);
+ 	    return NULL;
+ 	    };
+@@ -1186,15 +1270,15 @@ read_splineobject(FILE *fp)
+ 	if (!v30_flag)
+ 		npts = 1000000;
+ 	if (npts < 2) {
+-		put_msg(Err_incomp, "spline", line_no);
++		put_msg(Err_incomp, "spline", *line_no);
+ 		free_splinestorage(s);
+ 		return NULL;
+ 	}
+ 	for (--npts; npts > 0; --npts) {
+ 	    /* keep track of newlines for line counter */
+-	    count_lines_correctly(fp);
++	    count_lines_correctly(fp, line_no);
+ 	    if (fscanf(fp, "%d%d", &x, &y) != 2) {
+-		put_msg(Err_incomp, "spline", line_no);
++		put_msg(Err_incomp, "spline", *line_no);
+ 		free_splinestorage(s);
+ 		return NULL;
+ 		};
+@@ -1224,9 +1308,9 @@ read_splineobject(FILE *fp)
+ 	    ptr = s->controls;
+ 	    while (ptr) {    /* read controls */
+ 		/* keep track of newlines for line counter */
+-		count_lines_correctly(fp);
++		count_lines_correctly(fp, line_no);
+ 		if ((n = fscanf(fp, "%lf", &control_s)) != 1) {
+-		  put_msg(Err_incomp, "spline", line_no);
++		  put_msg(Err_incomp, "spline", *line_no);
+ 		  free_splinestorage(s);
+ 		  return NULL;
+ 		}
+@@ -1249,9 +1333,9 @@ read_splineobject(FILE *fp)
+ 	}
+ 	/* Read controls from older versions */
+ 	/* keep track of newlines for line counter */
+-	count_lines_correctly(fp);
++	count_lines_correctly(fp, line_no);
+ 	if ((n = fscanf(fp, "%lf%lf%lf%lf", &lx, &ly, &rx, &ry)) != 4) {
+-	    put_msg(Err_incomp, "spline", line_no);
++	    put_msg(Err_incomp, "spline", *line_no);
+ 	    free_splinestorage(s);
+ 	    return NULL;
+ 	}
+@@ -1264,9 +1348,9 @@ read_splineobject(FILE *fp)
+ 	cp->rx = rx; cp->ry = ry;
+ 	while (--c) {
+ 	    /* keep track of newlines for line counter */
+-	    count_lines_correctly(fp);
++	    count_lines_correctly(fp, line_no);
+ 	    if (fscanf(fp, "%lf%lf%lf%lf", &lx, &ly, &rx, &ry) != 4) {
+-		put_msg(Err_incomp, "spline", line_no);
++		put_msg(Err_incomp, "spline", *line_no);
+ 		cp->next = NULL;
+ 		free_splinestorage(s);
+ 		return NULL;
+@@ -1289,13 +1373,37 @@ read_splineobject(FILE *fp)
+ 	return s;
+ }
+ 
++static char *
++find_end(const char *str, int v30flag)
++{
++	const char	endmark[] = "\\001";
++	char		*end;
++
++	if (v30flag) {
++		/* A string is terminated with the literal '\001',
++		   and 8-bit characters may be represented as \xxx */
++		end = strstr(str, endmark);
++		/* is this not '\\001', or '\\\\001', etc? */
++		while (end && backslash_count(str, end - str) % 2 == 0)
++			end = strstr(end + 3, endmark);
++	} else {
++		/* The text object is terminated by a CONTROL-A.
++		   If there is no CONTROL-A on this line, then this
++		   must be a multi-line text object. */
++		end = strchr(str, '\1');
++	}
++	return end;
++}
++
++
+ static F_text *
+-read_textobject(FILE *fp)
++read_textobject(FILE *fp, char **restrict line, size_t *line_len, int *line_no)
+ {
+ 	F_text	*t;
+-	int	n, ignore = 0;
+-	char	s[BUFSIZ], s_temp[BUFSIZ], junk[2];
+-	int	more, len, l;
++	bool	freestart = false;
++	int	i, n;
++	char	*end, *start;
++	size_t	len;
+ 
+ 	Text_malloc(t);
+ 	t->font = 0;
+@@ -1303,32 +1411,101 @@ read_textobject(FILE *fp)
+ 	t->comments = NULL;
+ 	t->next = NULL;
+ 
+-	if (v30_flag) {	/* order of parms is more like other objects now,
+-			   string is now terminated with the literal '\001',
+-			   and 8-bit characters are represented as \xxx */
+-
+-	    n = sscanf(buf, "%*d%d%d%d%d%d%lf%lf%d%lf%lf%d%d%[^\n]",
+-		&t->type, &t->color, &t->depth, &t->pen,
+-		&t->font, &t->size, &t->angle,
+-		&t->flags, &t->height, &t->length,
+-		&t->base_x, &t->base_y, s);
++	n = sscanf(*line, "%*d%d%d%d%d%d%lf%lf%d%lf%lf%d%d %n",
++			&t->type, &t->color, &t->depth, &t->pen, &t->font,
++			&t->size, &t->angle, &t->flags, &t->height, &t->length,
++			&t->base_x, &t->base_y, &i);
++	if (n != 12) {
++		put_msg(Err_incomp, "text", *line_no);
++		free(t);
++		return NULL;
++	}
++	start = *line + i;
++	end = find_end(start, v30_flag);
++
++	if (end) {
++		*end = '\0';
++		len = end - start;
+ 	} else {
+-	    /* The text object is terminated by a CONTROL-A, so we read
+-		everything up to the CONTROL-A and then read that character.
+-		If we do not find the CONTROL-A on this line then this must
+-		be a multi-line text object and we will have to read more. */
+-
+-	    n = sscanf(buf,"%*d%d%d%lf%d%d%d%lf%d%lf%lf%d%d%[^\1]%1[\1]",
+-		&t->type, &t->font, &t->size, &t->pen,
+-		&t->color, &t->depth, &t->angle,
+-		&t->flags, &t->height, &t->length,
+-		&t->base_x, &t->base_y, s, junk);
+-	}
+-	if ((n != 14) && (n != 13)) {
+-	  put_msg(Err_incomp, "text", line_no);
+-	  free(t);
+-	  return NULL;
++		ssize_t	chars;
++		char	*next;
++
++		len = strlen(start);
++		start[len++] = '\n';	/* put back the newline */
++
++		/* allocate plenty of space */
++		next = malloc(len + BUFSIZ);
++		if (next == NULL) {
++			put_msg(Err_mem);
++			free(t);
++			return NULL;
++		}
++		memcpy(next, start, len);
++
++		while ((chars = getline(line, line_len, fp)) != -1) {
++			++(*line_no);
++			end = find_end(*line, v30_flag);
++			if (end) {
++				*end = '\0';
++				next = realloc(next, len + end - *line + 1);
++				memcpy(next + len, *line, end - *line + 1);
++				len += end - *line;
++				break;
++			} else {
++				if (**line + chars - 1 == '\n' && chars > 1 &&
++						**line + chars - 2 == '\r')
++					(*line)[chars-- - 2] = '\n';
++				next = realloc(next, len + chars + 1);
++				memcpy(next + len, *line, chars + 1);
++				len += chars;
++			}
++		}
++		start = next;
++		freestart = true;
++	}
++
++	/* convert any \xxx to characters */
++	if (v30_flag && (end = strchr(start, '\\'))) {
++		unsigned char	num;
++		char		*c = start;
++		size_t		l;
++
++		len = end - start;
++		l = len;
++		while (c[l] != '\0') {
++			if (c[l] == '\\') {
++				/* convert 3 digit octal value */
++				if (isdigit(c[l+1]) && c[l+2] != '\0' &&
++							c[l+3] != '\0') {
++					if (sscanf(c+l+1, "%3hho", &num) != 1) {
++						put_msg("Error in parsing text string on line %d",
++								*line_no);
++						return NULL;
++					}
++					/* no check of unsigned char overflow */
++					c[len++] = num;
++					l += 3;
++				} else {
++					/* an escaped char is un-escaped */
++					c[len++] = c[++l];
++				}
++			} else {
++				c[len++] = c[l];
++			}
++			++l;
++		}
++		c[len] = '\0';		/* terminate */
++	}
++
++	t->cstring = malloc(len + 1);
++	if (t->cstring == NULL) {
++		put_msg(Err_mem);
++		free(t);
++		return NULL;
+ 	}
++	memcpy(t->cstring, start, len + 1);
++	if (freestart)
++		free(start);
+ 
+ 	if (font_size != 0.0) {
+ 	    /* scale length/height of text by ratio of requested font size to actual size */
+@@ -1338,89 +1515,6 @@ read_textobject(FILE *fp)
+ 	}
+ 	if (t->size <= 0.0)
+ 	    t->size = (float) DEFAULT_FONT_SIZE;
+-	more = 0;
+-	if (!v30_flag && n == 13)
+-	    more = 1;  /* in older xfig there is more if ^A wasn't found yet */
+-	else if (v30_flag) {	/* in 3.0 there is more if \001 wasn't found */
+-	    len = strlen(s);
+-	    if ((strcmp(&s[len-4],"\\001") == 0) &&	/* if we find '\000' */
+-	        !(backslash_count(s, len-5) % 2)) {	/* and not '\\000' */
+-		    more = 0;				/* then there are no more lines */
+-		    s[len-4]='\0';			/* and get rid of the '\001' */
+-	    } else {
+-		more = 1;
+-		s[len++]='\n';				/* put back the end of line char */
+-		s[len] = '\0';				/* and terminate it */
+-	    }
+-	}
+-	if (more) {
+-	  /* Read in the subsequent lines of the text if there are more */
+-	  do {
+-	    ++line_no;				/* As is done in get_line */
+-	    if (fgets(s_temp, BUFSIZ, fp) == NULL)
+-		break;
+-	    len = strlen(s_temp)-1;		/* ignore newline */
+-	    if (len > 0 && s_temp[len-1] == '\r') { /* strip any trailing CR */
+-		s_temp[len-1] = '\0';
+-		len--;
+-	    }
+-	    if (v30_flag) {
+-		if ((strncmp(&s_temp[len-4],"\\001",4) == 0) &&
+-		    !(backslash_count(s_temp, len-5) % 2)) {
+-			n=0;			/* found the '\001', set n to stop */
+-			s_temp[len-4]='\0';	/* and get rid of the '\001' */
+-		} else {
+-			n=1;			/* keep going (more lines) */
+-		}
+-	    } else {
+-		n = sscanf(buf, "%[^\1]%[\1]", s_temp, junk);
+-	    }
+-	    /* Safety check */
+-	    if (strlen(s)+1 + strlen(s_temp)+1 > BUFSIZ) {
+-	      /* Too many characters.  Ignore the rest. */
+-	      ignore = 1;
+-	    }
+-	    if (!ignore)
+-	      strcat(s, s_temp);
+-	  } while (n == 1);
+-	}
+-
+-	if (v30_flag) {		/* now convert any \xxx to ascii characters */
+-	    if (strchr(s,'\\')) {
+-		unsigned int num;
+-		len = strlen(s);
+-		for (l=0,n=0; l < len; ++l) {
+-		    if (s[l]=='\\') {
+-			/* a backslash, see if a digit follows */
+-			if (l < len && isdigit(s[l+1])) {
+-			    /* yes, scan for 3 digit octal value */
+-			    if (sscanf(&s[l+1],"%3o",&num)!=1) {
+-				put_msg("Error in parsing text string on line %d",
+-						line_no);
+-				return NULL;
+-			    }
+-			    buf[n++]= (unsigned char) num;	/* put char in */
+-			    l += 3;			/* skip over digits */
+-			} else {
+-			    buf[n++] = s[++l];		/* some other escaped character */
+-			}
+-		    } else {
+-			buf[n++] = s[l];		/* ordinary character */
+-		    }
+-		}
+-		buf[n]='\0';		/* terminate */
+-		strcpy(s,buf);		/* copy back to s */
+-	    }
+-	}
+-	if (strlen(s) == 0)
+-		(void)strcpy(s, " ");
+-	t->cstring = calloc((unsigned)(strlen(s)), sizeof(char));
+-	if (NULL == t->cstring) {
+-	    put_msg(Err_mem);
+-	    free(t);
+-	    return NULL;
+-	}
+-	(void)strcpy(t->cstring, s+1);
+ 
+ 	if (!v21_flag && (t->font == 0 || t->font == DEFAULT))
+ 		t->flags = ((t->flags != DEFAULT) ? t->flags : 0)
+@@ -1431,11 +1525,11 @@ read_textobject(FILE *fp)
+ 				| PSFONT_TEXT;
+ 
+ 	if (INVALID_TEXT(t)) {
+-		put_msg(Err_invalid, "text", line_no);
++		put_msg(Err_invalid, "text", *line_no);
+ 		free_text(&t);
+ 		return NULL;
+ 	}
+-	fix_and_note_color(&t->color);
++	fix_and_note_color(&t->color, *line_no);
+ 	t->comments = attach_comments();	/* attach any comments */
+ 	return t;
+ }
+@@ -1443,18 +1537,19 @@ read_textobject(FILE *fp)
+ 
+ /* count consecutive backslashes backwards */
+ 
+-static int
+-backslash_count(char cp[], int start)
++static ptrdiff_t
++backslash_count(const char *restrict cp, ptrdiff_t start)
+ {
+-  int i, count = 0;
++	ptrdiff_t	i;
++	ptrdiff_t	count = 0;
+ 
+-  for(i=start; i>=0; i--) {
+-    if (cp[i] == '\\')
+-	count++;
+-    else
+-	break;
+-  }
+-  return count;
++	for(i = start; i >= 0; --i) {
++		if (cp[i] == '\\')
++			++count;
++		else
++			break;
++	}
++	return count;
+ }
+ 
+ /* attach comments in linked list */
+@@ -1483,55 +1578,64 @@ attach_comments(void)
+     return icomp;
+ }
+ 
++/* save a comment line to be stored with the *subsequent* object */
++
+ static int
+-get_line(FILE *fp)
++save_comment(char *restrict line, size_t len)
+ {
+-	int	len;
+-	while (1) {
+-		if (NULL == fgets(buf, BUFSIZ, fp)) {
+-			return -1;
+-		}
+-		++line_no;
+-		if (*buf == '#') {			/* save any comments */
+-			if (save_comment() < 0)
+-				return -1;
+-			/* skip empty lines */
+-		} else if (*buf != '\n' || !(*buf == '\r' && buf[1] == '\n')) {
+-			len = strlen(buf);
+-			/* remove newline and possibly a carriage return */
+-			if (buf[len-1] == '\n')
+-				buf[len - (buf[len-2] == '\r' ? 2 : 1)] = '\0';
+-			return 1;
+-		}
+-	}
+-}
++	int	i;
+ 
+-/* save a comment line to be stored with the *subsequent* object */
++	/* skip too many comment lines */
++	if (numcom == MAXCOMMENTS)
++		return 2;
++
++	/* remove one leading blank from the comment, if there is one */
++	i = 1;
++	if (line[i] == ' ')
++		i = 2;
++
++	/* see if we've allocated space for this comment */
++	if (comments[numcom])
++		free(comments[numcom]);
++	if ((comments[numcom] = malloc(len + (1 - i))) == NULL)
++		return -1;
+ 
+-static int
+-save_comment(void)
++	strcpy(comments[numcom++], &line[i]);
++	return 1;
++}
++
++static ssize_t
++get_line(FILE *fp, char **restrict line, size_t *line_len, int *line_no)
+ {
+-    int		    i;
++	ssize_t	chars;
+ 
+-    /* skip too many comment lines */
+-    if (numcom == MAXCOMMENTS)
+-	return 2;
+-    i=strlen(buf);
+-    /* see if we've allocated space for this comment */
+-    if (comments[numcom])
+-	free(comments[numcom]);
+-    if ((comments[numcom] = malloc(i+1)) == NULL)
+-	    return -1;
+-    /* remove any newline */
+-    if (buf[i-1] == '\n')
+-	buf[i-1] = '\0';
+-    i=1;
+-    if (buf[1] == ' ')	/* remove one leading blank from the comment, if there is one */
+-	i=2;
+-    strcpy(comments[numcom++], &buf[i]);
+-    return 1;
++	while ((chars = getline(line, line_len, fp)) != -1) {
++		++(*line_no);
++		/* skip empty lines */
++		if (**line == '\n' || (**line == '\r' &&
++					chars == 2 && (*line)[1] == '\n'))
++			continue;
++		/* remove newline and possibly a carriage return */
++		if ((*line)[chars-1] == '\n') {
++			chars -= (*line)[chars - 2] == '\r' ? 2 : 1;
++			(*line)[chars] = '\0';
++		}
++		/* save any comments */
++		if (**line == '#') {
++			if (save_comment(*line, (size_t)chars) < 0)
++				return -1;
++			continue;
++		}
++		/* return the line */
++		return chars;
++	}
++	/* chars == -1 */
++	return chars;
++	/* getline() only fails with EINVAL, and probably ENOMEM from malloc().
++	   No use to check for errno. */
+ }
+ 
++
+ /* skip to the end of the current line and any subsequent blank lines */
+ 
+ static void
+@@ -1688,15 +1792,15 @@ static int pop() {
+  */
+ 
+ static void
+-count_lines_correctly(FILE *fp)
++count_lines_correctly(FILE *fp, int *line_no)
+ {
+ 	int cc;
+ 	do {
+-	    cc = getc(fp);
+-	    if (cc == '\n') {
+-		++line_no;
+-		cc=getc(fp);
+-	    }
++		cc = getc(fp);
++		if (cc == '\n') {
++			++(*line_no);
++			cc=getc(fp);
++		}
+ 	} while (cc == ' ' || cc == '\t');
+ 	ungetc(cc,fp);
+ }
+--- a/fig2dev/read1_3.c
++++ b/fig2dev/read1_3.c
+@@ -51,8 +51,6 @@
+ 
+ extern F_arrow		*forward_arrow(void), *backward_arrow(void);
+ extern int		figure_modified;
+-//extern int		line_no;
+-extern int		num_object;
+ 
+ static F_ellipse	*read_ellipseobject(FILE *fp);
+ static F_line		*read_lineobject(FILE *fp);
+@@ -103,7 +101,6 @@ read_1_3_objects(FILE *fp, F_compound *o
+ 			ll = (ll->next = l);
+ 		    else
+ 			ll = obj->lines = l;
+-		    num_object++;
+ 		    break;
+ 		case OBJ_SPLINE :
+ 		    if ((s = read_splineobject(fp)) == NULL) return(-1);
+@@ -111,7 +108,6 @@ read_1_3_objects(FILE *fp, F_compound *o
+ 			ls = (ls->next = s);
+ 		    else
+ 			ls = obj->splines = s;
+-		    num_object++;
+ 		    break;
+ 		case OBJ_ELLIPSE :
+ 		    if ((e = read_ellipseobject(fp)) == NULL) return(-1);
+@@ -119,7 +115,6 @@ read_1_3_objects(FILE *fp, F_compound *o
+ 			le = (le->next = e);
+ 		    else
+ 			le = obj->ellipses = e;
+-		    num_object++;
+ 		    break;
+ 		case OBJ_ARC :
+ 		    if ((a = read_arcobject(fp)) == NULL) return(-1);
+@@ -127,7 +122,6 @@ read_1_3_objects(FILE *fp, F_compound *o
+ 			la = (la->next = a);
+ 		    else
+ 			la = obj->arcs = a;
+-		    num_object++;
+ 		    break;
+ 		case OBJ_TEXT :
+ 		    if ((t = read_textobject(fp)) == NULL) return(-1);
+@@ -135,7 +129,6 @@ read_1_3_objects(FILE *fp, F_compound *o
+ 			lt = (lt->next = t);
+ 		    else
+ 			lt = obj->texts = t;
+-		    num_object++;
+ 		    break;
+ 		case OBJ_COMPOUND :
+ 		    if ((c = read_compoundobject(fp)) == NULL) return(-1);
+@@ -143,7 +136,6 @@ read_1_3_objects(FILE *fp, F_compound *o
+ 			lc = (lc->next = c);
+ 		    else
+ 			lc = obj->compounds = c;
+-		    num_object++;
+ 		    break;
+ 		default:
+ 		    put_msg("Incorrect object code %d", object);
diff -Nru fig2dev-3.2.7a/debian/patches/series fig2dev-3.2.7a/debian/patches/series
--- fig2dev-3.2.7a/debian/patches/series	2019-12-04 22:12:49.000000000 +0100
+++ fig2dev-3.2.7a/debian/patches/series	2020-01-07 19:53:09.000000000 +0100
@@ -13,3 +13,5 @@
 38_omit_showpage.patch
 40_circle_arrowhead.patch
 41_CVE-2019-19555.patch
+42_CVE-2019-19746.patch
+43_fgets2getline.patch

Attachment: signature.asc
Description: PGP signature


--- End Message ---
--- Begin Message ---
Package: release.debian.org
Version: 10.3

Hi,

Each of the uploads referred to by these bugs was included in today's
stable point release.

Regards,

Adam

--- End Message ---

Reply to: