hi,
know this is a sort of an inactive list, so i'm sorry for necroposting into
a void.

still, we see cscope aborts at exit due to myexit() recursive call. we have
2 cases, see backtraces in
bugzillas mentioned:

https://bugzilla.redhat.com/show_bug.cgi?id=2269887 - report 1 and a
research
https://bugzilla.redhat.com/show_bug.cgi?id=2256515 - report 2
https://src.fedoraproject.org/rpms/cscope/c/a4d105ed18317c43e41fd20934509f8f250edc68?branch=rawhide
- an ugly fix

so a research shows that the cscope process attempted a normal exit (by "q"
or Ctrl-D) calling myexit(0).
in the middle of it a signal SIGHUP handler was called, which is myexit()
itself. then glibc detects a
double-free condition in __GI___libc_free() while performing
fclose(refsfound). then glibc aborts the process
with __GI_abort() and the "free(): double free detected in tcache 2"
message. backtraces we have are:

main.c:847 in main(): /* normal quit */ myexit(0); ->
  main.c:1079 in myexit(sig=0): freefilelist(); ->
    dir.c:727 in in freefilelist(): free(srcfiles[--nsrcfiles]); ->
      malloc.c:3352 in __GI___libc_free() ->
        <signal handler called> ->
          main.c:1062 in myexit (sig=1 SIGHUP ): fclose(refsfound); ->
            iofclose.c:74 in _IO_new_fclose() -> ... ->
              malloc.c:3391 in __GI___libc_free() ->
                malloc_printerr("free(): double free detected in tcache 2")
-> __GI_abort()

main.c:847 in main(): /* normal quit */ myexit(0); ->
  main.c:1066 in myexit(sig=0): unlink(temp1); ->
    unlink.c:28 __unlink (name=<temp1> "/tmp/cscope.699047/cscope.1"); ->
      <signal handler called> ->
        main.c:1062 in myexit (sig=1 SIGHUP ): fclose(refsfound); ->
          iofclose.c:74 in _IO_new_fclose() -> ... ->
            malloc.c:3391 in __GI___libc_free() ->
              malloc_printerr("free(): double free detected in tcache 2")
-> __GI_abort()

in a short word, a process abort is caused by myexit() interrupted by a
signal which handler is myexit() itself.

note, free() and fclose() are NOT async-signal-safe, see "man 7
signal-safety". calling an async-signal-unsafe
function from a signal handler is perfectly legal unless the signal
interrupted another async-signal-unsafe function.
so i'm not sure about the unlink() case, unlink() is async-signal-safe.
still, the double-free condition is still
there, as we can see from the backtrace.

i'm not going to fix the whole signal handling in cscope, as it seems
broken. 1) myexit() calls functions which are
not async-signal-safe 2) signal() infrastructure (which is broken) is used
instead of sigaction(). i'll ugly-fix only
this specific case where myexit() is interrupted by a call to myexit()
itself by resetting signal handlers to default
ones. this may be not entirely correct but whatever.

Best regards,
Vladis

---

diff -up ./src/main.c.orig ./src/main.c
--- ./src/main.c.orig 2024-08-04 16:49:08.723525637 +0200
+++ ./src/main.c 2024-08-04 16:53:19.967862016 +0200
@@ -1056,11 +1056,18 @@ Please see the manpage for more informat
 void
 myexit(int sig)
 {
+ /* reset signal handlers to default ones, so myexit() is not called
+ * recursively as a signal handler during a normal exit */
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+
  /* HBB 20010313; close file before unlinking it. Unix may not care
  * about that, but DOS absolutely needs it */
  if (refsfound != NULL)
  fclose(refsfound);
-
+
  /* remove any temporary files */
  if (temp1[0] != '\0') {
  unlink(temp1);

_______________________________________________
Cscope-devel mailing list
Cscope-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/cscope-devel

Reply via email to