* Crash in g_file_monitor on 32-bit Cygwin
@ 2014-06-26 2:17 Ken Brown
2014-06-27 17:11 ` Ken Brown
0 siblings, 1 reply; 11+ messages in thread
From: Ken Brown @ 2014-06-26 2:17 UTC (permalink / raw)
To: cygwin
This is a followup to https://cygwin.com/ml/cygwin/2014-06/msg00324.html, from which I extracted the following test case:
$ cat gfile-test.c
#include <stdio.h>
#include <gio/gio.h>
void
gfile_add_watch (const char *file)
{
GFile *gfile = g_file_new_for_path (file);
GFileMonitor *monitor;
GFileMonitorFlags gflags = G_FILE_MONITOR_NONE;
monitor = g_file_monitor (gfile, gflags, NULL, NULL);
if (! monitor)
printf ("Can't watch file %s\n", file);
else
printf ("Watching file %s\n", file);
}
int
main ()
{
const char *file = "gfile-test.c";
gfile_add_watch (file);
}
$ gcc -g -O0 -o gfile-test $(pkg-config --cflags gio-2.0) gfile-test.c $(pkg-config --libs gio-2.0)
In the 64-bit case, this behaves as expected:
$ ./gfile-test.exe
Watching file gfile-test.c
In the 32-bit case, however, it crashes. Running it under gdb shows that the call to g_file_monitor leads to a SEGV, but I can't tell exactly where; when I try to single step through the Glib code, I eventually hit an assertion violation in gdb. strace shows lots of exceptions, but I can't make much sense out of it otherwise.
Ken
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Crash in g_file_monitor on 32-bit Cygwin
2014-06-26 2:17 Crash in g_file_monitor on 32-bit Cygwin Ken Brown
@ 2014-06-27 17:11 ` Ken Brown
2014-06-27 17:16 ` Ken Brown
2014-06-27 17:52 ` Yaakov Selkowitz
0 siblings, 2 replies; 11+ messages in thread
From: Ken Brown @ 2014-06-27 17:11 UTC (permalink / raw)
To: cygwin
On 6/25/2014 10:17 PM, Ken Brown wrote:
> This is a followup to https://cygwin.com/ml/cygwin/2014-06/msg00324.html, from which I extracted the following test case:
>
> $ cat gfile-test.c
> #include <stdio.h>
> #include <gio/gio.h>
>
> void
> gfile_add_watch (const char *file)
> {
> GFile *gfile = g_file_new_for_path (file);
> GFileMonitor *monitor;
> GFileMonitorFlags gflags = G_FILE_MONITOR_NONE;
> monitor = g_file_monitor (gfile, gflags, NULL, NULL);
> if (! monitor)
> printf ("Can't watch file %s\n", file);
> else
> printf ("Watching file %s\n", file);
> }
>
> int
> main ()
> {
> const char *file = "gfile-test.c";
> gfile_add_watch (file);
> }
>
> $ gcc -g -O0 -o gfile-test $(pkg-config --cflags gio-2.0) gfile-test.c $(pkg-config --libs gio-2.0)
>
> In the 64-bit case, this behaves as expected:
>
> $ ./gfile-test.exe
> Watching file gfile-test.c
>
> In the 32-bit case, however, it crashes. Running it under gdb shows
> that the call to g_file_monitor leads to a SEGV, but I can't tell
> exactly where; when I try to single step through the Glib code, I
> eventually hit an assertion violation in gdb. strace shows lots of
> exceptions, but I can't make much sense out of it otherwise.
I rebuilt glib and gamin without optimization so that I could step
through the code in gdb. But stepping through the code turned out to be
unnecessary, because the bug was gone after the rebuilds. I don't know
if optimization was really the issue or whether just rebuilding with the
latest tools is what fixed it.
My builds can be obtained from
http://sanibeltranquility.com/cygwin/
if anyone else wants to try to reproduce this without rebuilding the
packages themselves.
Yaakov, could you take a look?
Ken
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Crash in g_file_monitor on 32-bit Cygwin
2014-06-27 17:11 ` Ken Brown
@ 2014-06-27 17:16 ` Ken Brown
2014-06-27 17:52 ` Yaakov Selkowitz
1 sibling, 0 replies; 11+ messages in thread
From: Ken Brown @ 2014-06-27 17:16 UTC (permalink / raw)
To: cygwin
On 6/27/2014 1:11 PM, Ken Brown wrote:
> My builds can be obtained from
>
> http://sanibeltranquility.com/cygwin/
>
> if anyone else wants to try to reproduce this without rebuilding the
> packages themselves.
I forgot to say that you'll probably have to run rebaseall after the
install.
Ken
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Crash in g_file_monitor on 32-bit Cygwin
2014-06-27 17:11 ` Ken Brown
2014-06-27 17:16 ` Ken Brown
@ 2014-06-27 17:52 ` Yaakov Selkowitz
2014-06-28 11:08 ` Ken Brown
1 sibling, 1 reply; 11+ messages in thread
From: Yaakov Selkowitz @ 2014-06-27 17:52 UTC (permalink / raw)
To: cygwin
On 2014-06-27 12:11, Ken Brown wrote:
> On 6/25/2014 10:17 PM, Ken Brown wrote:
>> This is a followup to
>> https://cygwin.com/ml/cygwin/2014-06/msg00324.html, from which I
>> extracted the following test case:
>>
>> $ cat gfile-test.c
>> #include <stdio.h>
>> #include <gio/gio.h>
>>
>> void
>> gfile_add_watch (const char *file)
>> {
>> GFile *gfile = g_file_new_for_path (file);
>> GFileMonitor *monitor;
>> GFileMonitorFlags gflags = G_FILE_MONITOR_NONE;
>> monitor = g_file_monitor (gfile, gflags, NULL, NULL);
>> if (! monitor)
>> printf ("Can't watch file %s\n", file);
>> else
>> printf ("Watching file %s\n", file);
>> }
>>
>> int
>> main ()
>> {
>> const char *file = "gfile-test.c";
>> gfile_add_watch (file);
>> }
>>
>> $ gcc -g -O0 -o gfile-test $(pkg-config --cflags gio-2.0) gfile-test.c
>> $(pkg-config --libs gio-2.0)
>>
>> In the 64-bit case, this behaves as expected:
>>
>> $ ./gfile-test.exe
>> Watching file gfile-test.c
>>
>> In the 32-bit case, however, it crashes. Running it under gdb shows
>> that the call to g_file_monitor leads to a SEGV, but I can't tell
>> exactly where; when I try to single step through the Glib code, I
>> eventually hit an assertion violation in gdb. strace shows lots of
>> exceptions, but I can't make much sense out of it otherwise.
>
> I rebuilt glib and gamin without optimization so that I could step
> through the code in gdb. But stepping through the code turned out to be
> unnecessary, because the bug was gone after the rebuilds. I don't know
> if optimization was really the issue or whether just rebuilding with the
> latest tools is what fixed it.
>
> My builds can be obtained from
>
> http://sanibeltranquility.com/cygwin/
>
> if anyone else wants to try to reproduce this without rebuilding the
> packages themselves.
>
> Yaakov, could you take a look?
Sure. Are you narrow this down to only one of glib or gamin?
Yaakov
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Crash in g_file_monitor on 32-bit Cygwin
2014-06-27 17:52 ` Yaakov Selkowitz
@ 2014-06-28 11:08 ` Ken Brown
2014-10-14 16:27 ` Ken Brown
0 siblings, 1 reply; 11+ messages in thread
From: Ken Brown @ 2014-06-28 11:08 UTC (permalink / raw)
To: cygwin
On 6/27/2014 1:52 PM, Yaakov Selkowitz wrote:
> On 2014-06-27 12:11, Ken Brown wrote:
>> On 6/25/2014 10:17 PM, Ken Brown wrote:
>>> This is a followup to
>>> https://cygwin.com/ml/cygwin/2014-06/msg00324.html, from which I
>>> extracted the following test case:
>>>
>>> $ cat gfile-test.c
>>> #include <stdio.h>
>>> #include <gio/gio.h>
>>>
>>> void
>>> gfile_add_watch (const char *file)
>>> {
>>> GFile *gfile = g_file_new_for_path (file);
>>> GFileMonitor *monitor;
>>> GFileMonitorFlags gflags = G_FILE_MONITOR_NONE;
>>> monitor = g_file_monitor (gfile, gflags, NULL, NULL);
>>> if (! monitor)
>>> printf ("Can't watch file %s\n", file);
>>> else
>>> printf ("Watching file %s\n", file);
>>> }
>>>
>>> int
>>> main ()
>>> {
>>> const char *file = "gfile-test.c";
>>> gfile_add_watch (file);
>>> }
>>>
>>> $ gcc -g -O0 -o gfile-test $(pkg-config --cflags gio-2.0) gfile-test.c
>>> $(pkg-config --libs gio-2.0)
>>>
>>> In the 64-bit case, this behaves as expected:
>>>
>>> $ ./gfile-test.exe
>>> Watching file gfile-test.c
>>>
>>> In the 32-bit case, however, it crashes. Running it under gdb shows
>>> that the call to g_file_monitor leads to a SEGV, but I can't tell
>>> exactly where; when I try to single step through the Glib code, I
>>> eventually hit an assertion violation in gdb. strace shows lots of
>>> exceptions, but I can't make much sense out of it otherwise.
>>
>> I rebuilt glib and gamin without optimization so that I could step
>> through the code in gdb. But stepping through the code turned out to be
>> unnecessary, because the bug was gone after the rebuilds. I don't know
>> if optimization was really the issue or whether just rebuilding with the
>> latest tools is what fixed it.
>>
>> My builds can be obtained from
>>
>> http://sanibeltranquility.com/cygwin/
>>
>> if anyone else wants to try to reproduce this without rebuilding the
>> packages themselves.
>>
>> Yaakov, could you take a look?
>
> Sure. Are you narrow this down to only one of glib or gamin?
The culprit is gamin, and optimization *is* relevant. What's strange,
though, is that when I rebuild it with optimization, my test case hangs
instead of crashing. Summary:
- With gamin-0.1.10-14 (and its subpackages), my test case crashes. The
outward symptom is that there's no output, but running the test case
under gdb shows the SEGV.
- If I rebuild gamin without optimization, I don't see any bug. More
precisely, I build it using your gamin.cygport with the following line
added:
CFLAGS+=" -O0 -g3"
- If I rebuild gamin with optimization (i.e., just using your
gamin.cygport with no changes), my test case hangs.
Ken
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Crash in g_file_monitor on 32-bit Cygwin
2014-06-28 11:08 ` Ken Brown
@ 2014-10-14 16:27 ` Ken Brown
2014-10-14 18:30 ` Ken Brown
0 siblings, 1 reply; 11+ messages in thread
From: Ken Brown @ 2014-10-14 16:27 UTC (permalink / raw)
To: cygwin
On 6/28/2014 7:08 AM, Ken Brown wrote:
> On 6/27/2014 1:52 PM, Yaakov Selkowitz wrote:
>> On 2014-06-27 12:11, Ken Brown wrote:
>>> On 6/25/2014 10:17 PM, Ken Brown wrote:
>>>> This is a followup to
>>>> https://cygwin.com/ml/cygwin/2014-06/msg00324.html, from which I
>>>> extracted the following test case:
>>>>
>>>> $ cat gfile-test.c
>>>> #include <stdio.h>
>>>> #include <gio/gio.h>
>>>>
>>>> void
>>>> gfile_add_watch (const char *file)
>>>> {
>>>> GFile *gfile = g_file_new_for_path (file);
>>>> GFileMonitor *monitor;
>>>> GFileMonitorFlags gflags = G_FILE_MONITOR_NONE;
>>>> monitor = g_file_monitor (gfile, gflags, NULL, NULL);
>>>> if (! monitor)
>>>> printf ("Can't watch file %s\n", file);
>>>> else
>>>> printf ("Watching file %s\n", file);
>>>> }
>>>>
>>>> int
>>>> main ()
>>>> {
>>>> const char *file = "gfile-test.c";
>>>> gfile_add_watch (file);
>>>> }
>>>>
>>>> $ gcc -g -O0 -o gfile-test $(pkg-config --cflags gio-2.0) gfile-test.c
>>>> $(pkg-config --libs gio-2.0)
>>>>
>>>> In the 64-bit case, this behaves as expected:
>>>>
>>>> $ ./gfile-test.exe
>>>> Watching file gfile-test.c
>>>>
>>>> In the 32-bit case, however, it crashes. Running it under gdb shows
>>>> that the call to g_file_monitor leads to a SEGV, but I can't tell
>>>> exactly where; when I try to single step through the Glib code, I
>>>> eventually hit an assertion violation in gdb. strace shows lots of
>>>> exceptions, but I can't make much sense out of it otherwise.
>>>
>>> I rebuilt glib and gamin without optimization so that I could step
>>> through the code in gdb. But stepping through the code turned out to be
>>> unnecessary, because the bug was gone after the rebuilds. I don't know
>>> if optimization was really the issue or whether just rebuilding with the
>>> latest tools is what fixed it.
>>>
>>> My builds can be obtained from
>>>
>>> http://sanibeltranquility.com/cygwin/
>>>
>>> if anyone else wants to try to reproduce this without rebuilding the
>>> packages themselves.
>>>
>>> Yaakov, could you take a look?
>>
>> Sure. Are you narrow this down to only one of glib or gamin?
>
> The culprit is gamin, and optimization *is* relevant. What's strange, though,
> is that when I rebuild it with optimization, my test case hangs instead of
> crashing. Summary:
>
> - With gamin-0.1.10-14 (and its subpackages), my test case crashes. The outward
> symptom is that there's no output, but running the test case under gdb shows the
> SEGV.
>
> - If I rebuild gamin without optimization, I don't see any bug. More precisely,
> I build it using your gamin.cygport with the following line added:
>
> CFLAGS+=" -O0 -g3"
>
> - If I rebuild gamin with optimization (i.e., just using your gamin.cygport with
> no changes), my test case hangs.
I made another attempt to debug this, and I found the problem, but I don't know
how to fix it. First, I have to correct the last assertion I made above about
my test case hanging; I just didn't wait long enough for it to finish. What
happens is that there is a retry loop in
libgamin/gam_api.c:gamin_connect_unix_socket that gives up after 25 seconds.
And the reason it fails is that /usr/libexec/gam_server.exe has crashed. In
fact, the latter always crashes on 32-bit Cygwin if it's built with optimization
and if the directory /tmp/fam-<username> exists before it is run. [And this
directory will always exist after one run of gam_server.exe.]
The crash occurs in a call to g_free at server/gam_channel.c:525 because the
pointer 'dir' that is being freed has been clobbered by a call to
gam_check_not_fat on line 497. Here are some details, based on a build using
Yaakov's gamin.cygport file with the added line
CFLAGS+=" -O1 -g3"
I've appended at the end of this message a transcript of a gdb session that
illustrates some of the assertions I'll be making.
At line 447 of server/gam_channel.c, g_strconcat is called to get a pointer to
the directory name "/tmp/fam-<username>". The value of this pointer is assigned
to the variable 'dir' at line 473, and in my run it is 0x8005c068. Although
'dir' is optimized out, I can see from a disassembly that the pointer is stored
on the stack at -0x510(%ebp):
0x004058fc <+266>: call 0x408bf8 <g_strconcat>
0x00405901 <+271>: mov %eax,-0x510(%ebp)
And I verified in my gdb session that this stack location does indeed contain
0x8005c068. After the call to gam_check_not_fat a little later, that stack
location contains the value 0x00000104. Then when g_free attempts to free the
bogus pointer 0x00000104, we get a crash.
I can't tell from the disassembly why the call to gam_check_not_fat clobbers the
stack. My best guess is that it happens as a result of calls to some Windows
functions. I hope someone more knowledgeable can take this further and fix it.
By the way, the problem doesn't occur in the 64-bit case because the pointer
'dir' is saved in a register rather than on the stack, and apparently (by luck?)
this register is not clobbered by gam_check_not_fat.
Ken
P.S. I think I found a typo in gam_check_not_fat, unrelated to the present
problem. Based on the context and the indentation, I think a couple of lines
need to be enclosed in braces:
--- gam_channel.c.orig 2014-10-14 12:08:55.000000000 -0400
+++ gam_channel.c 2014-10-14 09:46:37.746490800 -0400
@@ -44,8 +44,10 @@
&& (c = strchr (root + 3, '\\')))
c[1] = '\0';
else
- fprintf (stderr, "GetVolumePathName: %d\n", GetLastError ());
- return 0;
+ {
+ fprintf (stderr, "GetVolumePathName: %d\n", GetLastError ());
+ return 0;
+ }
}
if (!GetVolumeInformation (root, volname, MAX_PATH, NULL,
NULL, NULL, fsname, MAX_PATH))
=======================GDB transcript=========================
$ gdb /usr/libexec/gam_server.exe
GNU gdb (GDB) 7.8
[...]
Reading symbols from /usr/libexec/gam_server.exe...Reading symbols from
/usr/lib/debug//usr/libexec/gam_server.exe.dbg...done.
(gdb) b gam_check_secure_dir
Breakpoint 1 at 0x4058b1: file
/usr/src/debug/gamin-0.1.10-16/server/gam_channel.c, line 441.
(gdb) r
Starting program: /usr/libexec/gam_server.exe
[New Thread 11320.0x61c]
[New Thread 11320.0x3abc]
Breakpoint 1, gam_listen_unix_socket (path=<optimized out>)
at /usr/src/debug/gamin-0.1.10-16/server/gam_channel.c:699
699 if (!gam_check_secure_dir()) {
(gdb) s
gam_check_secure_dir ()
at /usr/src/debug/gamin-0.1.10-16/server/gam_channel.c:699
699 if (!gam_check_secure_dir()) {
(gdb)
gam_get_socket_dir () at /usr/src/debug/gamin-0.1.10-16/server/gam_channel.c:441
441 user = g_get_user_name();
(gdb) n
443 if (user == NULL) {
(gdb)
447 ret = g_strconcat("/tmp/fam-", user, NULL);
(gdb) s
g_strconcat (
string1=string1@entry=0x40c2cf <__FUNCTION__.10927+222> "/tmp/fam-")
at /usr/src/debug/glib2.0-2.38.2-4/glib/gstrfuncs.c:569
569 {
(gdb) fin
Run till exit from #0 g_strconcat (
string1=string1@entry=0x40c2cf <__FUNCTION__.10927+222> "/tmp/fam-")
at /usr/src/debug/glib2.0-2.38.2-4/glib/gstrfuncs.c:569
0x00405901 in gam_get_socket_dir ()
at /usr/src/debug/gamin-0.1.10-16/server/gam_channel.c:447
447 ret = g_strconcat("/tmp/fam-", user, NULL);
Value returned is $1 = (gchar *) 0x8005c068 "/tmp/fam-kbrown"
(gdb) n
gam_check_secure_dir ()
at /usr/src/debug/gamin-0.1.10-16/server/gam_channel.c:476
476 if (dir == NULL) {
(gdb) s
481 ret = mkdir(dir, 0700);
(gdb) p dir
$2 = <optimized out>
(gdb) x/x $ebp-0x510
0x28a6a8: 0x8005c068 <<<<<<<<<<<<<<<<<<<<<<<<<<
(gdb) n
482 if (ret >= 0) {
(gdb)
488 switch (errno) {
(gdb)
490 ret = stat(dir, &st);
(gdb)
491 if (ret < 0) {
(gdb)
497 not_fat = gam_check_not_fat(dir);
(gdb)
498 if (not_fat && (st.st_uid != getuid())) {
(gdb) x/x $ebp-0x510
0x28a6a8: 0x00000104 <<<<<<<<<<<<<<<<<<<<<<<<<<<
(gdb) n
gam_server_create (session=0x0)
at /usr/src/debug/gamin-0.1.10-16/server/gam_channel.c:816
816 fd = gam_listen_unix_socket(path);
(gdb) s
gam_listen_unix_socket (path=<optimized out>)
at /usr/src/debug/gamin-0.1.10-16/server/gam_channel.c:816
816 fd = gam_listen_unix_socket(path);
(gdb)
gam_check_secure_dir ()
at /usr/src/debug/gamin-0.1.10-16/server/gam_channel.c:504
504 if (!S_ISDIR (st.st_mode)) {
(gdb)
509 if (not_fat && (st.st_mode & (S_IRWXG|S_IRWXO))) {
(gdb)
515 if (not_fat && ((st.st_mode & (S_IRWXU)) != S_IRWXU)) {
(gdb)
524 GAM_DEBUG(DEBUG_INFO, "Reusing socket directory %s\n", dir);
(gdb)
525 g_free(dir);
(gdb)
g_free (mem=0x104) at /usr/src/debug/glib2.0-2.38.2-4/glib/gmem.c:195
195 {
(gdb) fin
Run till exit from #0 g_free (mem=0x104)
at /usr/src/debug/glib2.0-2.38.2-4/glib/gmem.c:195
Program received signal SIGABRT, Aborted.
0x00405d0b in gam_check_secure_dir ()
at /usr/src/debug/gamin-0.1.10-16/server/gam_channel.c:525
525 g_free(dir);
(gdb) bt
#0 0x00405d0b in gam_check_secure_dir ()
at /usr/src/debug/gamin-0.1.10-16/server/gam_channel.c:525
#1 gam_listen_unix_socket (path=<optimized out>)
at /usr/src/debug/gamin-0.1.10-16/server/gam_channel.c:699
#2 gam_server_create (
session=0x1ac <error: Cannot access memory at address 0x1ac>)
at /usr/src/debug/gamin-0.1.10-16/server/gam_channel.c:816
#3 0x76891194 in WaitForSingleObjectEx () from /c/Windows/syswow64/kernel32.dll
#4 0x76891148 in WaitForSingleObject () from /c/Windows/syswow64/kernel32.dll
#5 0x610db4f6 in sig_send(_pinfo*, siginfo_t&, _cygtls*)@12 (
p=p@entry=0x60fd0000, si=..., tls=tls@entry=0x0)
at /usr/src/debug/cygwin-1.7.32-1/winsup/cygwin/sigproc.cc:679
#6 0x610d8a2c in _pinfo::kill(siginfo_t&)@8 (this=0x60fd0000, si=...)
at /usr/src/debug/cygwin-1.7.32-1/winsup/cygwin/signal.cc:248
#7 0x610d8ef6 in kill0 (pid=pid@entry=11372, si=...)
at /usr/src/debug/cygwin-1.7.32-1/winsup/cygwin/signal.cc:299
#8 0x610d90c2 in kill (sig=sig@entry=6, pid=11372)
at /usr/src/debug/cygwin-1.7.32-1/winsup/cygwin/signal.cc:308
#9 raise (sig=sig@entry=6)
at /usr/src/debug/cygwin-1.7.32-1/winsup/cygwin/signal.cc:284
#10 0x610d9363 in abort ()
at /usr/src/debug/cygwin-1.7.32-1/winsup/cygwin/signal.cc:371
#11 0x61108166 in dlfree@4 (mem=0x0, mem@entry=0x104)
at /usr/src/debug/cygwin-1.7.32-1/winsup/cygwin/malloc.cc:4248
#12 0x61082560 in free (p=0x104)
at /usr/src/debug/cygwin-1.7.32-1/winsup/cygwin/malloc_wrapper.cc:47
#13 0x610d57f5 in _sigfe () from /usr/bin/cygwin1.dll
#14 0x00000000 in ?? ()
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Crash in g_file_monitor on 32-bit Cygwin
2014-10-14 16:27 ` Ken Brown
@ 2014-10-14 18:30 ` Ken Brown
2014-10-14 19:28 ` Corinna Vinschen
2014-10-15 16:46 ` Yaakov Selkowitz
0 siblings, 2 replies; 11+ messages in thread
From: Ken Brown @ 2014-10-14 18:30 UTC (permalink / raw)
To: cygwin
On 10/14/2014 12:26 PM, Ken Brown wrote:
> On 6/28/2014 7:08 AM, Ken Brown wrote:
>> On 6/27/2014 1:52 PM, Yaakov Selkowitz wrote:
>>> On 2014-06-27 12:11, Ken Brown wrote:
>>>> On 6/25/2014 10:17 PM, Ken Brown wrote:
>>>>> This is a followup to
>>>>> https://cygwin.com/ml/cygwin/2014-06/msg00324.html, from which I
>>>>> extracted the following test case:
>>>>>
>>>>> $ cat gfile-test.c
>>>>> #include <stdio.h>
>>>>> #include <gio/gio.h>
>>>>>
>>>>> void
>>>>> gfile_add_watch (const char *file)
>>>>> {
>>>>> GFile *gfile = g_file_new_for_path (file);
>>>>> GFileMonitor *monitor;
>>>>> GFileMonitorFlags gflags = G_FILE_MONITOR_NONE;
>>>>> monitor = g_file_monitor (gfile, gflags, NULL, NULL);
>>>>> if (! monitor)
>>>>> printf ("Can't watch file %s\n", file);
>>>>> else
>>>>> printf ("Watching file %s\n", file);
>>>>> }
>>>>>
>>>>> int
>>>>> main ()
>>>>> {
>>>>> const char *file = "gfile-test.c";
>>>>> gfile_add_watch (file);
>>>>> }
>>>>>
>>>>> $ gcc -g -O0 -o gfile-test $(pkg-config --cflags gio-2.0) gfile-test.c
>>>>> $(pkg-config --libs gio-2.0)
>>>>>
>>>>> In the 64-bit case, this behaves as expected:
>>>>>
>>>>> $ ./gfile-test.exe
>>>>> Watching file gfile-test.c
>>>>>
>>>>> In the 32-bit case, however, it crashes. Running it under gdb shows
>>>>> that the call to g_file_monitor leads to a SEGV, but I can't tell
>>>>> exactly where; when I try to single step through the Glib code, I
>>>>> eventually hit an assertion violation in gdb. strace shows lots of
>>>>> exceptions, but I can't make much sense out of it otherwise.
>>>>
>>>> I rebuilt glib and gamin without optimization so that I could step
>>>> through the code in gdb. But stepping through the code turned out to be
>>>> unnecessary, because the bug was gone after the rebuilds. I don't know
>>>> if optimization was really the issue or whether just rebuilding with the
>>>> latest tools is what fixed it.
>>>>
>>>> My builds can be obtained from
>>>>
>>>> http://sanibeltranquility.com/cygwin/
>>>>
>>>> if anyone else wants to try to reproduce this without rebuilding the
>>>> packages themselves.
>>>>
>>>> Yaakov, could you take a look?
>>>
>>> Sure. Are you narrow this down to only one of glib or gamin?
>>
>> The culprit is gamin, and optimization *is* relevant. What's strange, though,
>> is that when I rebuild it with optimization, my test case hangs instead of
>> crashing. Summary:
>>
>> - With gamin-0.1.10-14 (and its subpackages), my test case crashes. The outward
>> symptom is that there's no output, but running the test case under gdb shows the
>> SEGV.
>>
>> - If I rebuild gamin without optimization, I don't see any bug. More precisely,
>> I build it using your gamin.cygport with the following line added:
>>
>> CFLAGS+=" -O0 -g3"
>>
>> - If I rebuild gamin with optimization (i.e., just using your gamin.cygport with
>> no changes), my test case hangs.
>
> I made another attempt to debug this, and I found the problem, but I don't know
> how to fix it. First, I have to correct the last assertion I made above about
> my test case hanging; I just didn't wait long enough for it to finish. What
> happens is that there is a retry loop in
> libgamin/gam_api.c:gamin_connect_unix_socket that gives up after 25 seconds. And
> the reason it fails is that /usr/libexec/gam_server.exe has crashed. In fact,
> the latter always crashes on 32-bit Cygwin if it's built with optimization and
> if the directory /tmp/fam-<username> exists before it is run. [And this
> directory will always exist after one run of gam_server.exe.]
>
> The crash occurs in a call to g_free at server/gam_channel.c:525 because the
> pointer 'dir' that is being freed has been clobbered by a call to
> gam_check_not_fat on line 497. Here are some details, based on a build using
> Yaakov's gamin.cygport file with the added line
>
> CFLAGS+=" -O1 -g3"
>
> I've appended at the end of this message a transcript of a gdb session that
> illustrates some of the assertions I'll be making.
>
> At line 447 of server/gam_channel.c, g_strconcat is called to get a pointer to
> the directory name "/tmp/fam-<username>". The value of this pointer is assigned
> to the variable 'dir' at line 473, and in my run it is 0x8005c068. Although
> 'dir' is optimized out, I can see from a disassembly that the pointer is stored
> on the stack at -0x510(%ebp):
>
> 0x004058fc <+266>: call 0x408bf8 <g_strconcat>
> 0x00405901 <+271>: mov %eax,-0x510(%ebp)
>
> And I verified in my gdb session that this stack location does indeed contain
> 0x8005c068. After the call to gam_check_not_fat a little later, that stack
> location contains the value 0x00000104. Then when g_free attempts to free the
> bogus pointer 0x00000104, we get a crash.
>
> I can't tell from the disassembly why the call to gam_check_not_fat clobbers the
> stack. My best guess is that it happens as a result of calls to some Windows
> functions. I hope someone more knowledgeable can take this further and fix it.
I stepped into gam_check_not_fat (which I should have done to begin with) and
narrowed this down further. The stack location in question gets clobbered by
the call to GetVolumeInformation:
(gdb) s
gam_check_not_fat (path=0x8005c068 "/tmp/fam-kbrown")
at /usr/src/debug/gamin-0.1.10-16/server/gam_channel.c:35
35 cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, winpath, MAX_PATH);
(gdb) x/x $ebp-0x510
0x28a6a8: 0x8005c068
(gdb) n
37 pGVPN = GetProcAddress(LoadLibrary("kernel32"), "GetVolumePathNameA");
(gdb) x/x $ebp-0x510
0x28a6a8: 0x8005c068
(gdb) n
38 if (!pGVPN || !(pGVPN)(winpath, root, MAX_PATH))
(gdb) x/x $ebp-0x510
0x28a6a8: 0x8005c068
(gdb) n
52 if (!GetVolumeInformation (root, volname, MAX_PATH, NULL,
(gdb) x/x $ebp-0x510
0x28a6a8: 0x8005c068
(gdb) n
58 if (!strncmp(fsname, "FAT", 3)) /* FAT, FAT32 */
(gdb) x/x $ebp-0x510
0x28a6a8: 0x00000104
Here's the code near the call to GetVolumeInformation, followed by what I think
is the relevant disassembly:
if (!GetVolumeInformation (root, volname, MAX_PATH, NULL,
NULL, NULL, fsname, MAX_PATH))
{
fprintf (stderr, "GetVolumeInformation: %d\n", GetLastError ());
return 0;
}
0x00405b3a <+840>: movl $0x104,0x1c(%esp) <<<<<<<<<<<<<<<<
0x00405b42 <+848>: lea -0x120(%ebp),%eax
0x00405b48 <+854>: mov %eax,0x18(%esp)
0x00405b4c <+858>: movl $0x0,0x14(%esp)
0x00405b54 <+866>: movl $0x0,0x10(%esp)
0x00405b5c <+874>: movl $0x0,0xc(%esp)
0x00405b64 <+882>: movl $0x104,0x8(%esp) <<<<<<<<<<<<<<<<
0x00405b6c <+890>: lea -0x224(%ebp),%eax
0x00405b72 <+896>: mov %eax,0x4(%esp)
0x00405b76 <+900>: lea -0x328(%ebp),%eax
0x00405b7c <+906>: mov %eax,(%esp)
0x00405b7f <+909>: call *0x41248c <----- GetVolumeInformation?
0x00405b85 <+915>: sub $0x20,%esp
0x00405b88 <+918>: test %eax,%eax
0x00405b8a <+920>: jne 0x405bb5 <gam_server_create+963>
0x00405b8c <+922>: call *0x412480 <----- GetLastError?
0x00405b92 <+928>: mov %eax,%esi
0x00405b94 <+930>: call 0x408df0 <__getreent>
0x00405b99 <+935>: mov %esi,0x8(%esp)
0x00405b9d <+939>: movl $0x40c70f,0x4(%esp)
0x00405ba5 <+947>: mov 0xc(%eax),%eax
0x00405ba8 <+950>: mov %eax,(%esp)
0x00405bab <+953>: call 0x408df8 <fprintf>
0x00405bb0 <+958>: jmp 0x406073 <gam_server_create+2177>
Note the two marked movl instructions involving 0x104; I guess one of these is
the culprit, but I don't really know what's going on.
Ken
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Crash in g_file_monitor on 32-bit Cygwin
2014-10-14 18:30 ` Ken Brown
@ 2014-10-14 19:28 ` Corinna Vinschen
2014-10-14 21:09 ` Yaakov Selkowitz
2014-10-15 16:46 ` Yaakov Selkowitz
1 sibling, 1 reply; 11+ messages in thread
From: Corinna Vinschen @ 2014-10-14 19:28 UTC (permalink / raw)
To: cygwin
[-- Attachment #1: Type: text/plain, Size: 2042 bytes --]
Hi Ken,
I know the code is not yours, but I have to vent while I see this code :)
On Oct 14 14:30, Ken Brown wrote:
> I stepped into gam_check_not_fat (which I should have done to begin with)
> and narrowed this down further. The stack location in question gets
> clobbered by the call to GetVolumeInformation:
>
> (gdb) s
> gam_check_not_fat (path=0x8005c068 "/tmp/fam-kbrown")
> at /usr/src/debug/gamin-0.1.10-16/server/gam_channel.c:35
> 35 cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, winpath, MAX_PATH);
Ouch. What about paths longer than MAX_PATH?
> (gdb) x/x $ebp-0x510
> 0x28a6a8: 0x8005c068
> (gdb) n
> 37 pGVPN = GetProcAddress(LoadLibrary("kernel32"), "GetVolumePathNameA");
There's no reason to load GetVolumePathName from kernel32 since all supported
platforms provide this entry point.
> (gdb) x/x $ebp-0x510
> 0x28a6a8: 0x8005c068
> (gdb) n
> 38 if (!pGVPN || !(pGVPN)(winpath, root, MAX_PATH))
> (gdb) x/x $ebp-0x510
> 0x28a6a8: 0x8005c068
> (gdb) n
> 52 if (!GetVolumeInformation (root, volname, MAX_PATH, NULL,
> (gdb) x/x $ebp-0x510
> 0x28a6a8: 0x8005c068
> (gdb) n
> 58 if (!strncmp(fsname, "FAT", 3)) /* FAT, FAT32 */
How old is this code? What *exactly* is this function trying to check?
I assume it's checking for certain filesystem capabilities, but then,
there's no good reason to check for a filesystem being "FAT" or "FAT32".
Any other filesystem might have the same or similar capabilities and
be called "FOOBAR".
Whatever the code is doing, it should probably simply call statvfs() and
check the f_flag member of the returned struct statvfs for a certain
flag. The flags returned in f_flag are the same as the fs flags
returned by GetVolumeInformation.
So, what is it the code is trying to test by checking the FS name?
Corinna
--
Corinna Vinschen Please, send mails regarding Cygwin to
Cygwin Maintainer cygwin AT cygwin DOT com
Red Hat
[-- Attachment #2: Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Crash in g_file_monitor on 32-bit Cygwin
2014-10-14 19:28 ` Corinna Vinschen
@ 2014-10-14 21:09 ` Yaakov Selkowitz
0 siblings, 0 replies; 11+ messages in thread
From: Yaakov Selkowitz @ 2014-10-14 21:09 UTC (permalink / raw)
To: cygwin
On 2014-10-14 14:28, Corinna Vinschen wrote:
> I know the code is not yours, but I have to vent while I see this code :)
Actually, this isn't the first time you're seeing this code, it's just
been a while. :-)
> There's no reason to load GetVolumePathName from kernel32 since all supported
> platforms provide this entry point.
They didn't when this code was written.
> How old is this code?
2006.
> What *exactly* is this function trying to check?
gamin enforces permissions on its sockets, which will fail on FAT
partitions for obvious reasons, so we need to bypass those checks in
that case.
Obviously this code is overdue for an update, which I'll try to do later
today.
Yaakov
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Crash in g_file_monitor on 32-bit Cygwin
2014-10-14 18:30 ` Ken Brown
2014-10-14 19:28 ` Corinna Vinschen
@ 2014-10-15 16:46 ` Yaakov Selkowitz
2014-10-16 1:11 ` Ken Brown
1 sibling, 1 reply; 11+ messages in thread
From: Yaakov Selkowitz @ 2014-10-15 16:46 UTC (permalink / raw)
To: cygwin
On 2014-10-14 13:30, Ken Brown wrote:
> I stepped into gam_check_not_fat (which I should have done to begin
> with) and narrowed this down further. The stack location in question
> gets clobbered by the call to GetVolumeInformation:
[snip]
> Here's the code near the call to GetVolumeInformation, followed by what
> I think is the relevant disassembly:
>
> if (!GetVolumeInformation (root, volname, MAX_PATH, NULL,
> NULL, NULL, fsname, MAX_PATH))
> {
> fprintf (stderr, "GetVolumeInformation: %d\n", GetLastError ());
> return 0;
> }
>
> 0x00405b3a <+840>: movl $0x104,0x1c(%esp) <<<<<<<<<<<<<<<<
> 0x00405b42 <+848>: lea -0x120(%ebp),%eax
> 0x00405b48 <+854>: mov %eax,0x18(%esp)
> 0x00405b4c <+858>: movl $0x0,0x14(%esp)
> 0x00405b54 <+866>: movl $0x0,0x10(%esp)
> 0x00405b5c <+874>: movl $0x0,0xc(%esp)
> 0x00405b64 <+882>: movl $0x104,0x8(%esp) <<<<<<<<<<<<<<<<
> 0x00405b6c <+890>: lea -0x224(%ebp),%eax
> 0x00405b72 <+896>: mov %eax,0x4(%esp)
> 0x00405b76 <+900>: lea -0x328(%ebp),%eax
> 0x00405b7c <+906>: mov %eax,(%esp)
> 0x00405b7f <+909>: call *0x41248c <----- GetVolumeInformation?
> 0x00405b85 <+915>: sub $0x20,%esp
> 0x00405b88 <+918>: test %eax,%eax
> 0x00405b8a <+920>: jne 0x405bb5 <gam_server_create+963>
> 0x00405b8c <+922>: call *0x412480 <----- GetLastError?
> 0x00405b92 <+928>: mov %eax,%esi
> 0x00405b94 <+930>: call 0x408df0 <__getreent>
> 0x00405b99 <+935>: mov %esi,0x8(%esp)
> 0x00405b9d <+939>: movl $0x40c70f,0x4(%esp)
> 0x00405ba5 <+947>: mov 0xc(%eax),%eax
> 0x00405ba8 <+950>: mov %eax,(%esp)
> 0x00405bab <+953>: call 0x408df8 <fprintf>
> 0x00405bb0 <+958>: jmp 0x406073 <gam_server_create+2177>
>
> Note the two marked movl instructions involving 0x104; I guess one of
> these is the culprit, but I don't really know what's going on.
While it should be purely academic now, the issue might have been a
failure to mark pGVPN as WINAPI (IOW __stdcall on x86):
- BOOL (*pGVPN)(LPCTSTR, LPTSTR, DWORD);
+ BOOL (WINAPI *pGVPN)(LPCTSTR, LPTSTR, DWORD);
Something must have changed in gcc's optimization that this triggered;
it certainly wasn't an issue when the code was first introduced.
Thanks for tracking this down; gamin-0.1.10-15 uses more modern features
to test for FAT that weren't available back in 2006.
Yaakov
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Crash in g_file_monitor on 32-bit Cygwin
2014-10-15 16:46 ` Yaakov Selkowitz
@ 2014-10-16 1:11 ` Ken Brown
0 siblings, 0 replies; 11+ messages in thread
From: Ken Brown @ 2014-10-16 1:11 UTC (permalink / raw)
To: cygwin
On 10/15/2014 12:46 PM, Yaakov Selkowitz wrote:
> On 2014-10-14 13:30, Ken Brown wrote:
>> I stepped into gam_check_not_fat (which I should have done to begin
>> with) and narrowed this down further. The stack location in question
>> gets clobbered by the call to GetVolumeInformation:
> [snip]
>> Here's the code near the call to GetVolumeInformation, followed by what
>> I think is the relevant disassembly:
>>
>> if (!GetVolumeInformation (root, volname, MAX_PATH, NULL,
>> NULL, NULL, fsname, MAX_PATH))
>> {
>> fprintf (stderr, "GetVolumeInformation: %d\n", GetLastError ());
>> return 0;
>> }
>>
>> 0x00405b3a <+840>: movl $0x104,0x1c(%esp) <<<<<<<<<<<<<<<<
>> 0x00405b42 <+848>: lea -0x120(%ebp),%eax
>> 0x00405b48 <+854>: mov %eax,0x18(%esp)
>> 0x00405b4c <+858>: movl $0x0,0x14(%esp)
>> 0x00405b54 <+866>: movl $0x0,0x10(%esp)
>> 0x00405b5c <+874>: movl $0x0,0xc(%esp)
>> 0x00405b64 <+882>: movl $0x104,0x8(%esp) <<<<<<<<<<<<<<<<
>> 0x00405b6c <+890>: lea -0x224(%ebp),%eax
>> 0x00405b72 <+896>: mov %eax,0x4(%esp)
>> 0x00405b76 <+900>: lea -0x328(%ebp),%eax
>> 0x00405b7c <+906>: mov %eax,(%esp)
>> 0x00405b7f <+909>: call *0x41248c <----- GetVolumeInformation?
>> 0x00405b85 <+915>: sub $0x20,%esp
>> 0x00405b88 <+918>: test %eax,%eax
>> 0x00405b8a <+920>: jne 0x405bb5 <gam_server_create+963>
>> 0x00405b8c <+922>: call *0x412480 <----- GetLastError?
>> 0x00405b92 <+928>: mov %eax,%esi
>> 0x00405b94 <+930>: call 0x408df0 <__getreent>
>> 0x00405b99 <+935>: mov %esi,0x8(%esp)
>> 0x00405b9d <+939>: movl $0x40c70f,0x4(%esp)
>> 0x00405ba5 <+947>: mov 0xc(%eax),%eax
>> 0x00405ba8 <+950>: mov %eax,(%esp)
>> 0x00405bab <+953>: call 0x408df8 <fprintf>
>> 0x00405bb0 <+958>: jmp 0x406073 <gam_server_create+2177>
>>
>> Note the two marked movl instructions involving 0x104; I guess one of
>> these is the culprit, but I don't really know what's going on.
>
> While it should be purely academic now, the issue might have been a failure to
> mark pGVPN as WINAPI (IOW __stdcall on x86):
>
> - BOOL (*pGVPN)(LPCTSTR, LPTSTR, DWORD);
> + BOOL (WINAPI *pGVPN)(LPCTSTR, LPTSTR, DWORD);
Ah, that makes sense. Thanks. I'm glad to have an explanation.
Ken
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2014-10-16 1:11 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-26 2:17 Crash in g_file_monitor on 32-bit Cygwin Ken Brown
2014-06-27 17:11 ` Ken Brown
2014-06-27 17:16 ` Ken Brown
2014-06-27 17:52 ` Yaakov Selkowitz
2014-06-28 11:08 ` Ken Brown
2014-10-14 16:27 ` Ken Brown
2014-10-14 18:30 ` Ken Brown
2014-10-14 19:28 ` Corinna Vinschen
2014-10-14 21:09 ` Yaakov Selkowitz
2014-10-15 16:46 ` Yaakov Selkowitz
2014-10-16 1:11 ` Ken Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).