[net.news.b] bugs in news 2.10.1, advice to authors

geoff@utcsstat.UUCP (Geoffrey Collyer) (01/05/84)

I have recently found and fixed two readnews 2.10.1 bugs that
cause core dumps on v7, in the undigestifier H command and
the function findngsize.

The undigestifier (invoked by the d command to readnews) takes an
H subcommand which called hprint with an extra argument *in the
middle of the argument list*, which eventually caused a Bus Error
in fprintf.

Diffs of digest.c follow:

201c201
< 			hprint(h, !cflag, ofp, 1);
---
> 			hprint(h, ofp, 1);
209c209
< 				hprint(h, !cflag, ofp, 0);
---
> 				hprint(h, ofp, 0);

(Lines numbers are approximate; actual line numbers may vary.)

Two days later, after I had read roughly one hundred articles,
readnews took a Memory Fault and dumped core, for the third
time in three days.  Of course, by now I was getting used to it.
I dug through the core dump, and since I had wisely not stripped
my readnews binary determined that the global long ngsize had been
trashed, causing selectn() to try to zero far, far beyond the end
of bitmap[].  This happened shortly after I had deleted the most
recent round of dead news groups from /usr/lib/news/active,
which naturally made me suspect findngsize().

This is the vile swill that used to be findngsize (in rfuncs.c):

	/*
	 * Figure out the number of the largest article in newsgroup ng,
	 * and return that value.
	 */
	long
	findngsize(ng)
	char *ng;
	{
		FILE *af;
		long s;
		char buf[100], n[100];
	
		af = xfopen(ACTIVE, "r");
		while (fgets(buf, sizeof buf, af)) {
			sscanf(buf, "%s %ld", n, &s);
			if (strcmp(n, ng) == 0) {
				fclose(af);
				return s;
			}
		}
		return 0;
	}

This foul, evil-smelling excuse for a function failed to close
ACTIVE (/usr/lib/news/active) if the newsgroup ng was not found
*and* returned utter trash (whatever was on the stack) if ACTIVE
was malformed, since it failed to check that sscanf actual read
two items from buf.  I replaced it with this function:

	long
	findngsize(ng)
	char *ng;
	{
		FILE *af;
		long s, ret = 0;
		char buf[100], n[100];
	
		af = xfopen(ACTIVE, "r");
		while (fgets(buf, sizeof buf, af) != NULL)
			if (sscanf(buf, "%s %ld", n, &s) == 2 && strcmp(n, ng) == 0) {
				ret = s;
				break;
			}
		fclose(af);
		return ret;
	}

There is a further minor bug in inews.c.
At the start of localize(), the line

	actfp = fopen(ACTIVE, "r+");

appears, and actfp is never tested to see if fopen succeeded.
This particular bug hasn't bitten me, but if inews
ever can't read and write the ACTIVE file, it will start
fprintfing on NULL, which can produce bizarre results.
fcloseing NULL produces a core dump on utcsstat (a v7 system).
There are many other such unchecked system calls and function calls
throughout B news and trying to chase them all down would be an
endless task.

System calls *do* fail, even when *you* think they shouldn't or
can't or won't.  I wish people would assume the worst when writing
programs: system calls will always fail, at the most inconvenient
times, when you are least able to deal with them, for reasons that
you can't foresee.  If you at least try to do something reasonable,
rather than just ``knowing'' that nothing can possibly go wrong,
your program won't go berserk when faced with the unusual!
All right, officer, I'll go peacefully...

Geoff Collyer, U. of Toronto

rees@apollo.UUCP (Jim Rees) (01/09/84)

    There is a further minor bug in inews.c.
    At the start of localize(), the line

	actfp = fopen(ACTIVE, "r+");

    appears, and actfp is never tested to see if fopen succeeded.

Yes, I fixed that one here a while ago.  There isn't any really
sane thing to do at that point, so I made it an xerror().

In the same routine, there are two places where the function
will return without fcloseing ACTIVE, either.  Try submitting an
article with the following "Newsgroups:" line to rnews:

Newsgroups: general,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z

Each of those invalid groups will leave a hanging FILE pointer, and
you will run out after just a few of them.  Granted this is a
pathological case, but I don't think it is wise to leave these
things open after they are needed.

The fix is to put a "fclose(actfp)" before each of the two "return FALSE"
statements.