[hackers] [sbase] sort: Fix line comparison when col buffer contains data from longer line || Michael Forney

From: <git_AT_suckless.org>
Date: Sat, 9 Jul 2016 11:09:58 +0200 (CEST)

commit a944b682a694b4e7900c94d6550845f8d52af574
Author: Michael Forney <mforney_AT_mforney.org>
AuthorDate: Sat May 14 18:56:54 2016 -0700
Commit: sin <sin_AT_2f30.org>
CommitDate: Sat Jul 9 10:09:50 2016 +0100

    sort: Fix line comparison when col buffer contains data from longer line
    
    I'm not sure if there are other implications of this or not, but
    the issue is that columns() uses len to store the allocated buffer
    size, but linecmp() compares up to len bytes. If those trailing
    bytes do not match, the line is considered not matching, even though
    the relevant parts of the buffer do match.
    
    To resolve this, also keep track of column capacity. Additionally,
    since there is no reason to keep the existing data when resizing,
    just use free and emalloc rather than erealloc.
    
    The simplest case I could reduce it to is this:
    
    if [ "$(printf '%s\n' a a xxb xxc | ./sort -u)" = "$(printf '%s\n' a xxb xxc)" ] ; then
            echo pass
    else
            echo fail
    fi

diff --git a/sort.c b/sort.c
index 90ee911..623b81e 100644
--- a/sort.c
+++ b/sort.c
_AT_@ -18,6 +18,11 @@ struct keydef {
         TAILQ_ENTRY(keydef) entry;
 };
 
+struct column {
+ struct line line;
+ size_t cap;
+};
+
 enum {
         MOD_N = 1 << 0,
         MOD_STARTB = 1 << 1,
_AT_@ -33,7 +38,7 @@ static TAILQ_HEAD(kdhead, keydef) kdhead = TAILQ_HEAD_INITIALIZER(kdhead);
 static int Cflag = 0, cflag = 0, uflag = 0;
 static char *fieldsep = NULL;
 static size_t fieldseplen = 0;
-static struct line col1, col2;
+static struct column col1, col2;
 
 static void
 skipblank(struct line *a)
_AT_@ -76,12 +81,12 @@ skipcolumn(struct line *a, int skip_to_next_col)
         }
 }
 
-static size_t
-columns(struct line *line, const struct keydef *kd, struct line *col)
+static void
+columns(struct line *line, const struct keydef *kd, struct column *col)
 {
         Rune r;
         struct line start, end;
- size_t len, utflen, rlen;
+ size_t utflen, rlen;
         int i;
 
         start.data = line->data;
_AT_@ -118,15 +123,13 @@ columns(struct line *line, const struct keydef *kd, struct line *col)
                 end.data += end.len - 1;
                 end.len = 1;
         }
- len = MAX(0, end.data - start.data);
- if (!(col->data) || col->len < len)
- col->data = erealloc(col->data, len + 1);
- memcpy(col->data, start.data, len);
- col->data[len] = '\0';
- if (col->len < len)
- col->len = len;
-
- return len;
+ col->line.len = MAX(0, end.data - start.data);
+ if (!(col->line.data) || col->cap < col->line.len + 1) {
+ free(col->line.data);
+ col->line.data = emalloc(col->line.len + 1);
+ }
+ memcpy(col->line.data, start.data, col->line.len);
+ col->line.data[col->line.len] = '\0';
 }
 
 static int
_AT_@ -187,13 +190,13 @@ slinecmp(struct line *a, struct line *b)
                     TAILQ_LAST(&kdhead, kdhead) != TAILQ_FIRST(&kdhead)) {
                         res = 0;
                 } else if (kd->flags & MOD_N) {
- x = strtold(col1.data, NULL);
- y = strtold(col2.data, NULL);
+ x = strtold(col1.line.data, NULL);
+ y = strtold(col2.line.data, NULL);
                         res = (x < y) ? -1 : (x > y);
                 } else if (kd->flags & (MOD_D | MOD_F | MOD_I)) {
- res = skipmodcmp(&col1, &col2, kd->flags);
+ res = skipmodcmp(&col1.line, &col2.line, kd->flags);
                 } else {
- res = linecmp(&col1, &col2);
+ res = linecmp(&col1.line, &col2.line);
                 }
 
                 if (kd->flags & MOD_R)
Received on Sat Jul 09 2016 - 11:09:58 CEST

This archive was generated by hypermail 2.3.0 : Sat Jul 09 2016 - 11:13:41 CEST