[Bug 32149] New: Interrupting inferior during a getline causes the stream to fail

Bug ID 32149
Summary Interrupting inferior during a getline causes the stream to fail
Product lldb
Version 4.0
Hardware Macintosh
OS MacOS X
Status NEW
Severity normal
Priority P
Component All Bugs
Assignee lldb-dev@lists.llvm.org
Reporter malaperle@gmail.com
CC llvm-bugs@lists.llvm.org

- macOS 10.12.3
- LLDB from trunk or lldb-360.1.70 (Xcode 8.2.1)

1. Create an executable with this code:

#include <iostream>
#include <string>

int main() {
        while (std::cin.good()) {
                std::string Line;
                std::getline(std::cin, Line);
        }
        return 0;
}

2. Start debugging it with LLDB (lldb a.out)
3. "run"
4. Once it starts running, interrupt it (Ctrl-C)
5. Once it's stopped, do "continue"

Process terminates!

If I look at the error state bits of the stream, the fail and eof bits are set.

This bug is particularly an issue for me as I am trying to debug clangd (part
of clang-tools-extra) which spends much of its time waiting for input on stdin.
If I try to attach to it, it interrupt it then when I resume, it terminates.

Interestingly, on Linux with LLDB 3.8, this problem doesn't occur.

Jim Ingham changed bug 32149

What Removed Added
Resolution INVALID
Status NEW RESOLVED

Comment # 3 on bug 32149 from Jim Ingham

Looks like getline uses LibC's getc on macOS.  All of the getc family can get
EINTR if something interrupts this read call.  

That attaching with a debugger interrupts an ongoing system call most likely
varies from system to system.  But it does happen on macOS, and isn't something
the debugger can control.

It looks like getline doesn't handle EINTR itself.  It also sets both bad and
eof to true on EINTR on OSX.  But I don't think you can rely on that because if
I close the input by sending ^D I get the same result.

Something like this works, but it's a little ugly:

#include <iostream>
#include <string>
#include <stdio.h>

int main() {
  errno = 0;
  while (errno == EINTR || !std::cin.eof()) {
    std::string Line;
    errno = 0;
    std::cin.clear();
    std::getline(std::cin, Line);
  }
  return 0;
}

Anyway, this isn't an issue with lldb.