public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
* 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).