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: List-Subscribe: List-Archive: List-Post: List-Help: , 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 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> Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit 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 >>>> #include >>>> >>>> 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- 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-". 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 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=) 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 = (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=) 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=) at /usr/src/debug/gamin-0.1.10-16/server/gam_channel.c:699 #2 gam_server_create ( session=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