Skip to content

Starting with 8.9.1, SIGPIPE leaks in some cases #14344

Description

@Cogitri

I did this

After #14296, curl has started to leak SIGPIPE in some cases. I‘ve noticed this since the test suite I wrote for our in-house curl-wrapper now sometimes exits which SIGPIPE (I‘d say about 50% of the time). I‘ll try to post the last curl invocation tomorrow.

I expected the following

No SIGPIPEs to leak to the program (or at least no un-announced change to the curl‘s behavior)

curl/libcurl version

curl 8.9.1

operating system

Ubuntu 20.04 (using the Conan package manager, thus using OpenSSL 3.x)

Activity

  1. Cogitri commented on Aug 2, 2024

    @Cogitri
    Author

    Debugging this further, it appears that libcurl isn't actually causing the SIGPIPE that kills the program to be emitted - but in versions <8.9.1 it just happened to suppress it. In our case, we use cpp-httplib for creating a small HTTP server for our unit tests. This server emits SIGPIPE in its thread in some cases, which was previously handled by libcurl, since those SIGPIPEs only happened while curl was performing a request against the server. Now that libcurl doesn't do the ignoring of the server's errors, they're surfacing.

    As such, I don't think this is a libcurl issue, but maybe it'd be wise to document this in the release notes since there seem to be other projects which are affected?

  2. bagder commented on Aug 2, 2024

    @bagder
    Member

    libcurl attempts to supress SIGPIPE from within libcurl itself (or rather the dependencies it uses), which it did before and it apparently now fails to do. So yes, I believe it is a libcurl issue.

    SIGPIPE is not emitted by the server (at least that won't reach curl), it is instead generally caused when the server has closed the connection and the client (curl) tries to send data on the closed socket.

  3. Cogitri commented on Aug 2, 2024

    @Cogitri
    Author

    The SIGPIPE doesn't origin from the thread libcurl uses in our application though - at least in our unit tests it origins from the thread of the HTTP server we spawn. Apparently libcurl previously caused the SIGPIPEs caused by that thread to also be ignored.

    The tests which cause the SIGPIPE to be emitted test that our libcurl wrapper correctly rejects invalid HTTPS certificates, so I suppose libcurl terminates the connection upon noticing the wrong HTTPS certificate and the server then causes the SIGPIPE.

  4. bagder commented on Aug 2, 2024

    @bagder
    Member

    I'm not sure I follow completely but that's not too important.

    The key is that libcurl by default ignores SIGPIPEs during its operation so while libcurl executes it should not receive it - if a SIGPIPE happens in such a circumstance, it is a libcurl bug.

    Outside of libcurl's functions, they are restored and happens "normally".

  5. added a commit that references this issue on Aug 4, 2024
    fe9baa1
  6. bagder commented on Aug 4, 2024

    @bagder
    Member

    Please test #14390 and see if it changes anything.

  7. added a commit that references this issue on Aug 5, 2024
  8. added a commit that references this issue on Aug 5, 2024
    3eec5af
  9. mkauf commented on Aug 5, 2024

    @mkauf
    Contributor

    Not sure if I read the code correctly... but I think that if an application has set CURLOPT_NOSIGNAL to 1, curl 8.9.1 (without this bugfix) will replace the application's signal handler for SIGPIPE, and not restore it later.

    sigpipe_apply() will call sigpipe_restore(), and there this is called:

    sigaction(SIGPIPE, &ig->old_pipe_act, NULL);
    

    ig has been initialized to zeroes, so it does not contain a valid signal handler, but this test program shows that the previous signal handler gets replaced:

    #include <signal.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    int main()
    {
      struct sigaction x;
      memset(&x, '\0', sizeof(x));
    
      signal(SIGPIPE, SIG_IGN);
      sigaction(SIGPIPE, &x, NULL);
    
      usleep(100000000);
    
      return 0;
    }
    

    If you send this program a SIGPIPE, it will quit (at least on Linux).

    @bagder I think that this is quite a serious regression, and it has been introduced in a curl bugfix release (8.9.1), so another bugfix release (8.9.2) is probably a good idea...

  10. rsbeckerca commented on Aug 5, 2024

    @rsbeckerca
    Contributor

    @bagder @mkauf Just an FYI: I can verify that a SIGSEGV occurs on NonStop when receiving a SIGPIPE in sleep mode in the above program. The issue is that x.sa_handler cannot be 0x00000000. Setting it appropriately to SIG_DFL does not leak the signal and the program responds appropriately.

  11. bagder commented on Aug 5, 2024

    @bagder
    Member

    I don't understand. This issue is fixed already. Are you talking about the state of things after the fix or not?

  12. bagder commented on Aug 5, 2024

    @bagder
    Member

    another bugfix release (8.9.2) is probably a good idea...

    That train has gone. It would require a serious effort that I don't think this issue is worth.

  13. mkauf commented on Aug 5, 2024

    @mkauf
    Contributor

    I'm talking about the state of things before the fix.

    I just wanted to point out that libcurl before the fix permanently changed the SIGPIPE signal handler of applications that set CURLOPT_NOSIGNAL to 1.

  14. added a commit that references this issue on Aug 15, 2024
  15. added 6 commits that reference this issue on Aug 28, 2024
    94cae94
    840d136
    ac190da
    ed5c858
    a63f41b
    50e6d90
  16. Coeur commented on Mar 3, 2025

    @Coeur

    Based on 3eec5af, it's fixed in curl 8.10.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions