On Solaris, at least:
$ pwd
/var/tmp/maxpath/0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890/0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890/0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890/0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890/012345678901234567890123456789/0123456
$ pwd | wc -c
1024
$ vi a
Vim: Caught deadly signal SEGV
Vim: Finished.
Segmentation Fault (core dumped)
$ vi
Segmentation Fault (core dumped)
Using truss and libumem, the problem becomes reasonably apparent. Using
LD_PRELOAD=libumem.so.1 UMEM_DEBUG=default,verbose truss -u a.out -u libc:
-o /tmp/vi.out vi a
I get this output:
72705 /1@1: -> alist_add(0x8285804, 0x82cb428, 0x2)
72706 /1@1: -> buflist_add(0x82cb428, 0x3)
72707 /1@1: -> buflist_new(0x82cb428, 0x0, 0x0, 0x3)
72708 /1@1: -> fname_expand(0x82f8e08, 0x8046ec8, 0x8046ecc)
72709 /1@1: -> fix_fname(0x82cb428, 0x0)
72710 /1@1: -> FullName_save(0x82cb428, 0x1)
72711 /1@1: -> alloc(0x400, 0x0)
72712 /1@1: <- alloc() = 0x82d3188
72713 /1@1: -> vim_FullName(0x82cb428, 0x82d3188, 0x400, 0x1)
72714 /1@1: -> path_with_url(0x82cb428, 0x0)
72715 /1@1: -> libc:strncmp(0x82cb429, 0x82544b0, 0x3)
72716 /1@1: <- libc:strncmp() = -1
72717 /1@1: -> libc:strncmp(0x82cb429, 0x82544b4, 0x3)
72718 /1@1: <- libc:strncmp() = -1
72719 /1@1: <- path_with_url() = 0
72720 /1@1: -> mch_FullName(0x82cb428, 0x82d3188, 0x400, 0x1)
72721 /1@1: -> vim_strrchr(0x82cb428, 0x2f)
72722 /1@1: -> utfc_ptr2len(0x82cb428, 0x0)
72723 /1@1: <- utfc_ptr2len() = 1
72724 /1@1: <- vim_strrchr() = 0
72725 /1@1: -> mch_dirname(0x82d3188, 0x400)
72726 /1@1: -> libc:getcwd(0x82d3188, 0x400)
72727 /1:
getcwd("/var/tmp/maxpath/012345678901234567890123456789012345678901234567890123456789012345678
901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890/0123456789012345678901234567890
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012
345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234
567890/01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234
567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456
78901234567890123456789012345678901234567890/012345678901234567890123456789012345678901234567890123456
789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567890/0123456789012345678
90123456789/0123456", 1024) = 0
72728 /1@1: <- libc:getcwd() = 0x82d3188
72729 /1@1: <- mch_dirname() = 1
72730 /1@1: -> libc:strlen(0x82d3188, 0x0)
72731 /1@1: <- libc:strlen() = 1023
72732 /1@1: -> libc:strcmp(0x82cb428, 0x824d790)
72733 /1@1: <- libc:strcmp() = 51
72734 /1@1: -> libc:strcat(0x82d3188, 0x824d7b0)
72735 /1@1: <- libc:strcat() = 0x82d3188
72736 /1@1: -> libc:strlen(0x82d3188, 0x0)
72737 /1@1: <- libc:strlen() = 1024
72738 /1@1: -> libc:strlen(0x82cb428, 0x0)
72739 /1@1: <- libc:strlen() = 1
72740 /1@1: <- mch_FullName() = 0
72741 /1@1: -> vim_strncpy(0x82d3188, 0x82cb428, 0x3ff)
72742 /1@1: -> libc:strncpy(0x82d3188, 0x82cb428, 0x3ff)
72743 /1@1: <- libc:strncpy() = 0x82d3188
72744 /1@1: <- vim_strncpy() = 0
72745 /1@1: <- vim_FullName() = 0
72746 /1@1: -> vim_strsave(0x82cb428, 0x0)
72747 /1@1: -> libc:strlen(0x82cb428, 0x0)
72748 /1@1: <- libc:strlen() = 1
72749 /1@1: -> alloc(0x2, 0x0)
72750 /1@1: <- alloc() = 0x82cb408
72751 /1@1: -> libc:memmove(0x82cb408, 0x82cb428, 0x2)
72752 /1@1: <- libc:memmove() = 0x82cb408
72753 /1@1: <- vim_strsave() = 0x82cb408
72754 /1@1: -> vim_free(0x82d3188, 0x0)
In os_unix.c, the path we trace through mch_FullName() grabs the cwd into "buf"
(an input parameter) with mch_dirname(), which succeeds, since it's just short
enough to fit into the 1024-byte buffer (with the trailing NUL). We then get
the strlen() of buf, returning 1023, as the truss output shows on line 72731.
We then compare that value to the input parameter "len", which is the size of
"buf", and since 1023 is not >= 1024, we assume we can add a slash to the end,
overwriting the end of the buffer.
Looks like this code has been in place since at least vim 7.0 (in fact, the
code has looked like this since vim 6.0, and prior to that, the behavior here
was even worse), so it's been in all versions of vim shipped in Solaris.
If we instead compare "l >= len - 1", we avoid any of that, return failure from
mch_FullName(), and let vim handle that appropriately higher up. We could try
to fix it so that cwds of arbitrary lengths are handled here, but it appears
that vim handles it well enough, that this simple fix is sufficient for now.
And the patch that fixes the problem:
--- src/os_unix.c Tue May 1 09:52:21 2012
+++ src/os_unix.c Tue May 1 09:52:24 2012
@@ -2509,7 +2509,7 @@
}
l = STRLEN(buf);
- if (l >= len)
+ if (l >= len - 1)
retval = FAIL;
#ifndef VMS
else
Thanks,
Danek
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php