log: fix -L bounds checking bug
[gitweb.git] / line-log.c
index 8cc29a0000f8456331457c0d247c242f3113517e..1c3ac8dccd1dd7c1c15aaa82e80d6dbdf129bb56 100644 (file)
@@ -110,12 +110,14 @@ static void range_set_check_invariants(struct range_set *rs)
 static void sort_and_merge_range_set(struct range_set *rs)
 {
        int i;
-       int o = 1; /* output cursor */
+       int o = 0; /* output cursor */
 
        qsort(rs->ranges, rs->nr, sizeof(struct range), range_cmp);
 
-       for (i = 1; i < rs->nr; i++) {
-               if (rs->ranges[i].start <= rs->ranges[o-1].end) {
+       for (i = 0; i < rs->nr; i++) {
+               if (rs->ranges[i].start == rs->ranges[i].end)
+                       continue;
+               if (o > 0 && rs->ranges[i].start <= rs->ranges[o-1].end) {
                        if (rs->ranges[o-1].end < rs->ranges[i].end)
                                rs->ranges[o-1].end = rs->ranges[i].end;
                } else {
@@ -297,6 +299,7 @@ static void line_log_data_insert(struct line_log_data **list,
        p = xcalloc(1, sizeof(struct line_log_data));
        p->path = path;
        range_set_append(&p->ranges, begin, end);
+       sort_and_merge_range_set(&p->ranges);
        if (ip) {
                p->next = ip->next;
                ip->next = p;
@@ -591,13 +594,13 @@ parse_lines(struct commit *commit, const char *prefix, struct string_list *args)
                                    lines, &begin, &end,
                                    full_name))
                        die("malformed -L argument '%s'", range_part);
+               if (lines < end || ((lines || begin) && lines < begin))
+                       die("file %s has only %lu lines", name_part, lines);
                if (begin < 1)
                        begin = 1;
                if (end < 1)
                        end = lines;
                begin--;
-               if (lines < end || lines < begin)
-                       die("file %s has only %ld lines", name_part, lines);
                line_log_data_insert(&ranges, full_name, begin, end);
 
                free_filespec(spec);