bug in vi's undo
Kartik Agaram
ak at akkartik.com
Sun Jun 3 05:32:12 UTC 2018
$ git log |head -n1
commit 0972c7f7a570c38edb68e1c60a45614b7a7c7d55
$ uname -a
Linux akkartik 4.4.0-112-generic #135-Ubuntu SMP Fri Jan 19 11:48:14
UTC 2018 i686 i686 i686 GNU/Linux
$ gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
To reproduce:
$ make menuconfig
# accept all defaults, save config
$ make
$ cat > x
a
b
c
d
e
$ ./busybox vi x
Navigate to the bottom line, delete using 'dd'.
Hit 'dd' again to delete the new bottom line.
Hit 'u' to undo the previous deletion.
Hit 'u' a second time.
Expected contents:
a
b
c
d
e
Contents seen:
^@a
b
c
d
An earlier version also segfaulted at this point.
=== Attempt #1
The issue seems to be fixed by deleting this special-case when the
deleted text is at the end of the buffer:
@@ -2307,10 +2307,6 @@ static void undo_push(char *src, unsigned int
length, uint8_t u_type) // Add to
// Allocate a new undo object
if (u_type == UNDO_DEL || u_type == UNDO_DEL_CHAIN) {
// For UNDO_DEL objects, save deleted text
- if ((src + length) == end)
- length--;
- // If this deletion empties text[], strip the newline.
When the buffer becomes
- // zero-length, a newline is added back, which
requires this to compensate.
undo_entry = xzalloc(offsetof(struct undo_object,
undo_text) + length);
memcpy(undo_entry->undo_text, src, length);
} else {
However, as that deleted comment hints, then I reintroduce a bug in a
different situation:
Delete all 5 lines with '5dd'.
Hit 'u' to undo.
Instead of seeing the original 5 lines, I end up with an extra final newline.
=== Attempt #2
I can fix both situations by changing the condition to match (my
interpretation of) the comment, triggering only when the entire buffer
is deleted:
@@ -2307,7 +2307,7 @@ static void undo_push(char *src, unsigned int
length, uint8_t u_type) // Add to
// Allocate a new undo object
if (u_type == UNDO_DEL || u_type == UNDO_DEL_CHAIN) {
// For UNDO_DEL objects, save deleted text
- if ((src + length) == end)
+ if (src == text && (src + length) == end)
length--;
// If this deletion empties text[], strip the newline.
When the buffer becomes
// zero-length, a newline is added back, which
requires this to compensate.
Can any of you[1] think other situations where this would break?
Thanks,
Kartik
[1] Particularly Jody Bruchon, original author of commit a8d6f9be in
Apr 2014. Thanks in advance, Jody.
More information about the busybox
mailing list