Subject: bin/34627: patch(1) segfaults, when fed from stdin in batch or force mode
To: None <gnats-admin@netbsd.org, netbsd-bugs@netbsd.org>
From: None <lkundrak@redhat.com>
List: netbsd-bugs
Date: 09/26/2006 15:55:00
>Number:         34627
>Category:       bin
>Synopsis:       patch(1) segfaults, when fed from stdin in batch or force mode
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Sep 26 15:55:00 +0000 2006
>Originator:     Lubomir Kundrak
>Release:        NetBSD 3.0
>Organization:
>Environment:
System: NetBSD masaker 3.0 NetBSD 3.0 (GENERIC) #0: Mon Dec 19 01:04:02 UTC 2005 builds@works.netbsd.org:/home/builds/ab/netbsd-3-0-RELEASE/i386/200512182024Z-
obj/home/builds/ab/netbsd-3-0-RELEASE/src/sys/arch/i386/compile/GENERIC i386
Architecture: i386
Machine: i386

>Description:
When patch(1) command reads from standard input and the patchfile doesn't contain reference to file name, it dies due to NULL pointer dereference.

Program received signal SIGSEGV, Segmentation fault.
0xbdbb2222 in strdup () from /usr/lib/libc.so.12
(gdb) bt
#0  0xbdbb2222 in strdup () from /usr/lib/libc.so.12
#1  0x0804f194 in xstrdup (s=0x0) at util.c:228
#2  0x0804b356 in there_is_another_patch () at pch.c:170
#3  0x08049608 in main (argc=2, argv=0xbfbfe8f4) at patch.c:150
(gdb) up 2
#2  0x0804b356 in there_is_another_patch () at pch.c:170
170                             filearg[0] = xstrdup(bestguess);
(gdb) l
165                         p_indent, p_indent == 1 ? "" : "s");
166             skip_to(p_start, p_sline);
167             while (filearg[0] == NULL) {
168                     if (force || batch) {
169                             say("No file to patch.  Skipping...\n");
170                             filearg[0] = xstrdup(bestguess);
171                             skip_rest_of_patch = TRUE;
172                             return TRUE;
173                     }
174                     ask("File to patch: ");
(gdb) print bestguess
$1 = 0x0
(gdb)                                        

Obviously the problem is, that bestguess doesn't get set in intuit_diff_type(), because the patchfile lacks the filename specification.
>How-To-Repeat:
$ cat |patch -t
1c1
< a
---
> b
Hmm...  Looks like a normal diff to me...
No file to patch.  Skipping...
Memory fault (core dumped)
$

>Fix:
either modify xstrdup() to not actually call strdup() in case of NULL argument, or add the conditional test on NULL pointer before the problematic statement. Or completly skip it out -- is it needed at all?