On Tue, Aug 14 2018 14:29:30 -0500, Scott Cheloha wrote:
> On Tue, Aug 14, 2018 at 08:55:14PM +0300, Lauri Tirkkonen wrote:
> > Hi,
> > 
> > On Tue, Aug 14 2018 12:08:54 -0500, Scott Cheloha wrote:
> > > > +               len = (size_t)linelen;
> > > > +               if (line[len - 1] == '\n')
> > > > +                       line[len - 1] = '\0';
> > > 
> > > You can just use linelen directly and skip the assignment.
> > 
> > I did it this way because this bit later
> > 
> >     if (base64)
> >             cmp = strncmp(checksum, digest, len);
> > 
> > could have been reached without assigning len (if the "could be GNU form"
> > branch is taken). It looks like checksum and digest will always be null
> > temrinated, but 'len' may be reduced to something less than linelen
> > (eg. in the case that the line starts with whitespace). Maybe there's
> > some reason to not use strcmp here?
> 
> base64 is only set in the BSD form case, and in that case len is set to
> the length of checksum before the comparison.

Thanks, I neglected to check when base64 is set. Your logic makes sense
in that case, so I applied your suggestion below.

> > But shouldn't we check *before* calling free to ensure errno is not
> > clobbered? (although, getline.3's example code certainly does err(1,
> > "getline"); after free()...)
> 
> free(3) doesn't set errno.  At least, not portably.  I definitely wouldn't
> worry about the possibility of there being a malloc implementation that
> clobbers errno.
> 
> The ordering (check or free first) doesn't matter in this case because you
> aren't returning from the function early if you have an error on listfp,
> but I think the intent of the example in the manpage is to prevent leaks
> in such cases, e.g.:
> 
>       if (ferror(listfp)) {
>               warn("getline");
>               return 1;
>       }
>       free(line);     /* leak */
> 
> I would just stick to the manpage example in this case and keep the free(3)
> as close as possible to the allocation (getline).

Thanks for the explanation. Maybe I'm too used to not trusting the
platform to do things that make sense (in the past I remember thinking
that even a pathological ferror could modify errno; its manpage says it
won't though so I could trust that).

> > +   while ((linelen = getline(&line, &linesize, listfp)) != -1) {
> > +           char *tmpline = line;
> 
> You're already modifying the stack variable declarations up above, so
> declare tmpline alongside the other char pointers.

fixed.

> > +   if (ferror(listfp))
> > +           warn("%s: getline", file);
> > +   free(line);
> 
> Set error = 1 in the ferror case, too.

fixed.

diff --git a/bin/md5/md5.c b/bin/md5/md5.c
index 84adbcf0989..1abf28cfa16 100644
--- a/bin/md5/md5.c
+++ b/bin/md5/md5.c
@@ -549,11 +549,11 @@ digest_filelist(const char *file, struct hash_function 
*defhash, int selcount,
        int found, base64, error, cmp, i;
        size_t algorithm_max, algorithm_min;
        const char *algorithm;
-       char *filename, *checksum, *buf, *p;
+       char *filename, *checksum, *line, *p, *tmpline;
        char digest[MAX_DIGEST_LEN + 1];
-       char *lbuf = NULL;
+       ssize_t linelen;
        FILE *listfp, *fp;
-       size_t len, nread;
+       size_t len, linesize, nread;
        int *sel_found = NULL;
        u_char data[32 * 1024];
        union ANY_CTX context;
@@ -580,20 +580,15 @@ digest_filelist(const char *file, struct hash_function 
*defhash, int selcount,
        }
 
        error = found = 0;
-       while ((buf = fgetln(listfp, &len))) {
+       line = NULL;
+       linesize = 0;
+       while ((linelen = getline(&line, &linesize, listfp)) != -1) {
+               tmpline = line;
                base64 = 0;
-               if (buf[len - 1] == '\n')
-                       buf[len - 1] = '\0';
-               else {
-                       if ((lbuf = malloc(len + 1)) == NULL)
-                               err(1, NULL);
-
-                       (void)memcpy(lbuf, buf, len);
-                       lbuf[len] = '\0';
-                       buf = lbuf;
-               }
-               while (isspace((unsigned char)*buf))
-                       buf++;
+               if (line[linelen - 1] == '\n')
+                       line[linelen - 1] = '\0';
+               while (isspace((unsigned char)*tmpline))
+                       tmpline++;
 
                /*
                 * Crack the line into an algorithm, filename, and checksum.
@@ -603,11 +598,11 @@ digest_filelist(const char *file, struct hash_function 
*defhash, int selcount,
                 * Fallback on GNU form:
                 *  CHECKSUM  FILENAME
                 */
-               p = strchr(buf, ' ');
+               p = strchr(tmpline, ' ');
                if (p != NULL && *(p + 1) == '(') {
                        /* BSD form */
                        *p = '\0';
-                       algorithm = buf;
+                       algorithm = tmpline;
                        len = strlen(algorithm);
                        if (len > algorithm_max || len < algorithm_min)
                                continue;
@@ -658,7 +653,7 @@ digest_filelist(const char *file, struct hash_function 
*defhash, int selcount,
                        if ((hf = defhash) == NULL)
                                continue;
                        algorithm = hf->name;
-                       checksum = buf;
+                       checksum = tmpline;
                        if ((p = strchr(checksum, ' ')) == NULL)
                                continue;
                        if (hf->style == STYLE_CKSUM) {
@@ -725,11 +720,15 @@ digest_filelist(const char *file, struct hash_function 
*defhash, int selcount,
                        error = 1;
                }
        }
+       free(line);
+       if (ferror(listfp)) {
+               warn("%s: getline", file);
+               error = 1;
+       }
        if (listfp != stdin)
                fclose(listfp);
        if (!found)
                warnx("%s: no properly formatted checksum lines found", file);
-       free(lbuf);
        if (sel_found != NULL) {
                /*
                 * Mark found files by setting them to NULL so that we can

-- 
Lauri Tirkkonen | lotheac @ IRCnet

Reply via email to