I was investigating a bug in the Go toolchain's
fork of ar(1), called gopack, and I discovered
two similar bugs in native ar.

1. With a __.SYMDEF file of size (2*n)+1 bytes,
   the size given in the header will incorrectly
   include the padding byte.

2. When writing an archive member file to disk,
   the odd-size check occurs before the write
   which will access one byte past the end of
   the buffer containing the member data.

The solution for both errors is to check for an
odd size after the write, not before.

A patch is attached.  I also modified the code
to properly insert a newline character between
archive members when necessary, in accordance
with the ar(6) man page.

  Anthony

--- /n/sources/sys/src/cmd/ar.c 2010-01-21 16:16:47.000000000 -0800
+++ ar.c        2011-05-05 03:15:19.000000000 -0700
@@ -827,8 +827,6 @@
        Bseek(&b,seek(fd,0,1), 0);
 
        len = symdefsize;
-       if(len&01)
-               len++;
        sprint(a.date, "%-12ld", time(0));
        sprint(a.uid, "%-6d", 0);
        sprint(a.gid, "%-6d", 0);
@@ -842,6 +840,8 @@
        if(HEADER_IO(Bwrite, &b, a))
                        wrerr();
 
+       if(len&01)
+               len++;
        len += Boffset(&b);
        if (astart) {
                wrsym(&b, len, astart->sym);
@@ -855,7 +855,7 @@
                wrsym(&b, len, aend->sym);
 
        if(symdefsize&0x01)
-               Bputc(&b, 0);
+               Bputc(&b, '\n');
        Bterm(&b);
 }
 
@@ -1121,10 +1121,12 @@
        if(HEADER_IO(write, fd, bp->hdr))
                return 0;
        len = bp->size;
-       if (len & 01)
-               len++;
        if (write(fd, bp->member, len) != len)
                return 0;
+       if (len & 01) {
+               if(write(fd, "\n", 1) != 1)
+                       return 0;
+       }
        return 1;
 }
 

Reply via email to