delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2014/10/14/12:27:26

X-Recipient: archive-cygwin AT delorie DOT com
DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id
:list-unsubscribe:list-subscribe:list-archive:list-post
:list-help:sender:message-id:date:from:mime-version:to:subject
:references:in-reply-to:content-type:content-transfer-encoding;
q=dns; s=default; b=lot6ULxTR0a5puvyQ2B5RtqReH1KmwIwi6b7xKTppLi
mGD2VKKOxcReF665qk2WRMEpcAEPWf3NmDWLy9hwv8u0rKmY6O4IZobESvqluzX+
oIW1mQ89mVbe4dGC6XH8NTx3l9rAkeC0h4syRkxfffzYM71c55SETG3TWM29QmWU
=
DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id
:list-unsubscribe:list-subscribe:list-archive:list-post
:list-help:sender:message-id:date:from:mime-version:to:subject
:references:in-reply-to:content-type:content-transfer-encoding;
s=default; bh=rznXtyNOd9K6aEf9jkD7K9V3wYE=; b=Ss8paxLr2jvdp53kR
YZ1wZqae/37uHYlRFNhMx8Q77KQ0VWxIy4FZ7c9d0TI41P0GiBe/sIb6BDzzRJwu
/pBqc5TBN2uHuNonpBx0VOtljMYsq2sXJHRZgRlpu0CPxjRQTykBvdF62vy6T3hO
gcGSC+2XXY5VscSe8ZEb95e+kU=
Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Id: <cygwin.cygwin.com>
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
Sender: cygwin-owner AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
Delivered-To: mailing list cygwin AT cygwin DOT com
Authentication-Results: sourceware.org; auth=none
X-Virus-Found: No
X-Spam-SWARE-Status: No, score=-1.8 required=5.0 tests=AWL,BAYES_00,SPF_HELO_PASS,SPF_PASS,T_RP_MATCHES_RCVD autolearn=ham version=3.3.2
X-HELO: limerock04.mail.cornell.edu
X-CornellRouted: This message has been Routed already.
Message-ID: <543D4ED3.6020605@cornell.edu>
Date: Tue, 14 Oct 2014 12:26:59 -0400
From: Ken Brown <kbrown AT cornell DOT edu>
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Thunderbird/31.1.2
MIME-Version: 1.0
To: cygwin AT cygwin DOT com
Subject: Re: Crash in g_file_monitor on 32-bit Cygwin
References: <53AB82AB DOT 5000304 AT cornell DOT edu> <53ADA5B5 DOT 10404 AT cornell DOT edu> <53ADAF68 DOT 2020703 AT cygwin DOT com> <53AEA23A DOT 8030306 AT cornell DOT edu>
In-Reply-To: <53AEA23A.8030306@cornell.edu>
X-IsSubscribed: yes

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 AT 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 AT 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 AT entry=0x60fd0000, si=..., tls=tls AT 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 AT entry=11372, si=...)
     at /usr/src/debug/cygwin-1.7.32-1/winsup/cygwin/signal.cc:299
#8  0x610d90c2 in kill (sig=sig AT entry=6, pid=11372)
     at /usr/src/debug/cygwin-1.7.32-1/winsup/cygwin/signal.cc:308
#9  raise (sig=sig AT 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 AT 4 (mem=0x0, mem AT 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

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019