Subject: Re: nbsed broken on Solaris?
To: None <tech-pkg@netbsd.org>
From: Urban Boquist <urban@boquist.net>
List: tech-pkg
Date: 09/09/2004 16:43:28
Urban> I'm seeing a problem where nbsed built (by pkgsrc/bootstrap) on
Urban> Solaris seems unable to handle really long lines in files,
Urban> after 1024 chars it adds an extra zero char.

I found the problem. Unless I am mistaken it is a bug in the
implementation of fgetln() in the version that is in pkgsrc
libnbcompat. And it is not really Solaris specific, it should affect
all systems that use libnbcompat and does not have a native fgetln().

I've included the faulty version below. It is a simple off-by-one
error, the code does not account for that fgets() always
zero-terminates its result (in the case where a line is longer than a
single call to fgets() will read). In the code below, if you have
called fgetln() on a line that is 1024 or longer, at return from the
function "buf[1023]" will always be '\0' . The char that should have
been at offset 1023 will be in buf[1024]. Same for offset 2047 etc.

What confuses me a little is that the commit log for fgetln.c from
libnbcompat says that it is imported from src HEAD, but the actual
implementation does not look at all like the version that is in NetBSD
libc. Not even like the 1.12 version of fgetln.c, before the fgetstr()
generalization. But maybe I am misreading something.

Best regards,
     -- Urban

char *
fgetln(fp, len)
	FILE *fp;
	size_t *len;
{
	static char *buf = NULL;
	static size_t bufsiz = 0;
	char *ptr;


	if (buf == NULL) {
		bufsiz = BUFSIZ;
		if ((buf = malloc(bufsiz)) == NULL)
			return NULL;
	}

	if (fgets(buf, bufsiz, fp) == NULL)
		return NULL;
	*len = 0;

	while ((ptr = strchr(&buf[*len], '\n')) == NULL) {
		size_t nbufsiz = bufsiz + BUFSIZ;
		char *nbuf = realloc(buf, nbufsiz);

		if (nbuf == NULL) {
			int oerrno = errno;
			free(buf);
			errno = oerrno;
			buf = NULL;
			return NULL;
		} else
			buf = nbuf;

		*len = bufsiz;
		if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL)
			return buf;

		bufsiz = nbufsiz;
	}

	*len = (ptr - buf) + 1;
	return buf;
}