Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 327617

Summary: stderr should go to process console (was: Gdb hangs after user code writes to stderr multiple times.)
Product: [Tools] CDT Reporter: Tim Cook <cook>
Component: cdt-debug-dsf-gdbAssignee: Project Inbox <cdt-debug-dsf-gdb-inbox>
Status: REOPENED --- QA Contact: Jonah Graham <jonah>
Severity: normal    
Priority: P3 CC: cdtdoug, jamesblackburn+eclipse, mijstonen, nobody, pawel.1.piech, yurivolo
Version: 8.0Flags: jamesblackburn+eclipse: review+
Target Milestone: ---   
Hardware: PC   
OS: Windows 7   
Whiteboard:
Attachments:
Description Flags
CDT 7.0.1 patch
none
CDI patch to use process console instead of GDB console
marc.khouzam: iplog-
New thread to read GDB error stream marc.khouzam: iplog-

Description Tim Cook CLA 2010-10-12 19:10:21 EDT
Build Identifier: M20100909-0800

After multiple executions of fprintf(stderr, "some string\n") in user code, the gdb process stderr buffer gets full and further writes to stderr hang gdb.

Reproducible: Always
Comment 1 Tim Cook CLA 2010-10-12 19:11:55 EDT
Created attachment 180715 [details]
CDT 7.0.1 patch
Comment 2 Tim Cook CLA 2010-10-12 19:14:52 EDT
The attached patch adds a command processor to read from the gdb process error stream. Stderr output is shown in the Console View.
Comment 3 Tim Cook CLA 2010-10-14 08:46:14 EDT
Code to demonstrate problem :

#include <stdio.h>
#include <stdlib.h>

int main(void) {
  int i = 0;
  setvbuf(stderr, NULL, _IONBF, 0);

  for (i = 0; i < 50000; i++) {
    printf("iteration %d\n", i);

    // On iteration 14, stepping the following line will leave debugger in run state.
    fprintf(stderr, "!!!Hello World!!!!!!Hello World!!!\n");
  }
  return EXIT_SUCCESS;
}
Comment 4 James Blackburn CLA 2010-10-14 08:55:25 EDT
Very similar to bug 270369 in CDI.
Comment 5 Marc Khouzam CLA 2011-01-17 10:59:03 EST
This works ok on Linux.  Maybe because we can use PTYs.  I'll try it from home, on a Windows machine.
Comment 6 Marc Khouzam CLA 2011-01-18 06:28:39 EST
I can see this on Windows.  The patch seems to fix the problem, but I find the behavior strange.  With the patch, I see each line of output to stderr being printed to the program's console gradually (that is very nice), but I don't see the similar stdout printouts until the very end of the program (which is how stdout is currently behaving on Windows).  Why the difference?
Comment 7 Marc Khouzam CLA 2011-05-19 12:41:12 EDT
(In reply to comment #4)
> Very similar to bug 270369 in CDI.

I've looked at the CDI solution which reads from GDB's error stream and prints to the GDB console.

I'm curious to know why CDI chooses to print to the GDB console and not the process console?  I couldn't quite find what GDB will print to its error stream, so are we worried that output that is not from the process could be printed there and that is why CDI goes to the GDB console?
Comment 8 Marc Khouzam CLA 2011-05-19 12:55:22 EDT
Created attachment 196140 [details]
CDI patch to use process console instead of GDB console

Not being sure why CDI chooses to write stderr printouts to the GDB console, I tried it with the process console.  This is the patch to do that.

This is all so I can decide where DSF-GDB should print input received on GDB's stderr.
Comment 9 Nobody - feel free to take it CLA 2011-05-19 12:58:34 EDT
(In reply to comment #7)
> I'm curious to know why CDI chooses to print to the GDB console and not the
> process console?  I couldn't quite find what GDB will print to its error
> stream, so are we worried that output that is not from the process could be
> printed there and that is why CDI goes to the GDB console?

I don't understand why are you so confused. All GDB io streams go to the GDB console and the process streams to the process console, what's wrong with it?
Comment 10 James Blackburn CLA 2011-05-19 13:02:55 EDT
(In reply to comment #7)
> I'm curious to know why CDI chooses to print to the GDB console and not the
> process console?  I couldn't quite find what GDB will print to its error
> stream, so are we worried that output that is not from the process could be
> printed there and that is why CDI goes to the GDB console?

The reason was I was seeing errors from GDB itself coming out GDB's stderr.  Target output was being wrapped in MI and going correctly to the correct console.  It may be that our GDB behaves differently to native linux gdb in which case there isn't a good reason...
Comment 11 Marc Khouzam CLA 2011-05-19 13:03:25 EDT
(In reply to comment #9)
> (In reply to comment #7)
> > I'm curious to know why CDI chooses to print to the GDB console and not the
> > process console?  I couldn't quite find what GDB will print to its error
> > stream, so are we worried that output that is not from the process could be
> > printed there and that is why CDI goes to the GDB console?
> 
> I don't understand why are you so confused. All GDB io streams go to the GDB
> console and the process streams to the process console, what's wrong with it?

On Windows, we cannot use a PTY, so I'm trying out CDI without the option to "Connect process input & output to a terminal".

Currently
    cout << "Hello cout" << endl;
this goes to the process console.

    cerr << "Hello cerr" << endl;
this goes to the GDB console.

That is because GDB's error stream is used to print the process stderr.  I don't know what else GDB's error stream is used for, so, if it is only for the process' stderr, shouldn't we print this to the process console?
Comment 12 Marc Khouzam CLA 2011-05-19 13:06:18 EDT
(In reply to comment #10)

> The reason was I was seeing errors from GDB itself coming out GDB's stderr. 
> Target output was being wrapped in MI and going correctly to the correct
> console.  It may be that our GDB behaves differently to native linux gdb in
> which case there isn't a good reason...

If GDB uses its stderr for actual GDB errors, then I see the point, and I don't see how to differentiate between GDB error printouts and inferior error printouts.

I don't know what GDB uses its stderr for.  I'll have to ask.
Comment 13 Marc Khouzam CLA 2011-05-19 13:09:56 EDT
(In reply to comment #9)

> I don't understand why are you so confused. All GDB io streams go to the GDB
> console and the process streams to the process console, what's wrong with it?

Re-reading my first question, I can see why you didn't see my point, I didn't explain myself well at all.
Comment 14 James Blackburn CLA 2011-05-19 13:15:17 EDT
(In reply to comment #12)
> If GDB uses its stderr for actual GDB errors, then I see the point, and I don't
> see how to differentiate between GDB error printouts and inferior error
> printouts.

Well I'm not sure whether GDB does do this. However any linked in simulators or target specific bits might just write to the error stream.

There's a thread on target stderr vs. stdout:
http://www.cygwin.com/ml/gdb-patches/2005-12/msg00011.html
Comment 15 James Blackburn CLA 2011-05-19 13:23:25 EDT
Looks like this patch was committed:
http://www.cygwin.com/ml/gdb-patches/2005-12/msg00095.html
mi-interp.c has:
  ...
  /* Route target output through the MI. */
  gdb_stdtarg = mi->targ;
  /* Route target error through the MI as well. */
  gdb_stdtargerr = mi->targ;
  ...

AFAICS this means that targets stdour and stderr will be wrapped in MI, which may be different from what happens for native debugging...

http://www.cygwin.com/ml/gdb-patches/2005-12/msg00014.html
Comment 16 Marc Khouzam CLA 2011-05-19 13:35:15 EDT
(In reply to comment #15)
> Looks like this patch was committed:
> http://www.cygwin.com/ml/gdb-patches/2005-12/msg00095.html
> mi-interp.c has:
>   ...
>   /* Route target output through the MI. */
>   gdb_stdtarg = mi->targ;
>   /* Route target error through the MI as well. */
>   gdb_stdtargerr = mi->targ;
>   ...
>
> AFAICS this means that targets stdour and stderr will be wrapped in MI, which
> may be different from what happens for native debugging...
> 
> http://www.cygwin.com/ml/gdb-patches/2005-12/msg00014.html

Right, so target errors will come out with @ in front (maybe not on linux, but we handle it also), and that will be on GDB's output stream.

What goes on GDB stderr, I'm still trying to figure out
Comment 17 Marc Khouzam CLA 2011-05-19 13:51:16 EDT
I was able to get GDB to print to stderr using CLI mode, as shown below.  The 'display <use a type>' command will do it.

> gdb.7.3 a.out
GNU gdb (GDB) 7.2.90.20110420-cvs
(gdb) l
1       struct str {};
2       int main() {
3           str s;
4           return 0;
5       }
(gdb) start
Temporary breakpoint 1 at 0x804849a: file a.cc, line 4.
Starting program: /home/lmckhou/testing/a.out 

Temporary breakpoint 1, main () at a.cc:4
4           return 0;
(gdb) display str
Disabling display 1 to avoid infinite recursion.
1: str = Attempt to use a type name as an expression

I confirmed it was writing to stderr by redirecting GDB's stderr to a file like so:

bash
gdb.7.3 testing/a.out 2> tt

And the string "Attempt to use a type name as an expression" got redirected.

When using MI, 'gdb -i mi' and redirecting, that particular stderr printout comes out on stdout instead, with a & prefix.  But a cerr or fprintf(stderr, from the inferior does come out on GDB's stderr.

This makes me think that it is safe to print GDB's stderr to the inferior console.
Comment 18 James Blackburn CLA 2011-05-19 14:18:58 EDT
(In reply to comment #17)
> When using MI, 'gdb -i mi' and redirecting, that particular stderr printout
> comes out on stdout instead, with a & prefix.  But a cerr or fprintf(stderr,
> from the inferior does come out on GDB's stderr.
> 
> This makes me think that it is safe to print GDB's stderr to the inferior
> console.

This may be true for native GDB, but it's not true for target GDB.  For target GDB, stdout and stderr for the target will always be in the MI.  stderr of the GDB process will therefore only contain stuff that was fprintf(stderr, ...) from within the GDB process itself: i.e. a linked in simulator or target specific architecture bits.

It may be true that GDB itself wraps its output in stderr, but it may not be the case that all the things that are linked with GDB wrap their stderr like this.   Hence, for non-native targets, it makes sense to send GDB stderr to the gdb console and not to the target console.
Comment 19 Marc Khouzam CLA 2011-05-19 14:33:05 EDT
(In reply to comment #18)
> (In reply to comment #17)
> > When using MI, 'gdb -i mi' and redirecting, that particular stderr printout
> > comes out on stdout instead, with a & prefix.  But a cerr or fprintf(stderr,
> > from the inferior does come out on GDB's stderr.
> > 
> > This makes me think that it is safe to print GDB's stderr to the inferior
> > console.
> 
> This may be true for native GDB, but it's not true for target GDB.  For target
> GDB, stdout and stderr for the target will always be in the MI.  stderr of the
> GDB process will therefore only contain stuff that was fprintf(stderr, ...)
> from within the GDB process itself: i.e. a linked in simulator or target
> specific architecture bits.
> 
> It may be true that GDB itself wraps its output in stderr, but it may not be
> the case that all the things that are linked with GDB wrap their stderr like
> this.   Hence, for non-native targets, it makes sense to send GDB stderr to the
> gdb console and not to the target console.

Makes sense.
Considering that DSF-GDB currently ignores GDB's stderr altogether, and that CDI outputs to the GDB console, I think doing the same for DSF-GDB is good enough.
Comment 20 Marc Khouzam CLA 2011-05-19 15:00:23 EDT
Created attachment 196157 [details]
New thread to read GDB error stream

This patch mimics the solution for CDI of bug 270369.  It creates a new thread to read GDB's error stream and sends the string as an MI event for the AbstractCLIProcess to printout in the gdb console.

I had to prefix the string with an '&' to indicate that it is an error printout to AbstractCLIProcess.

By not using a PTY, I was able to confirm that inferior stderr printouts are now seen on the gdb console and we no longer have GDB hang when stderr gets full.

Committed to HEAD.
Comment 21 Marc Khouzam CLA 2011-05-19 15:01:35 EDT
Thanks for your help James.
Can you review the fix?
Comment 22 James Blackburn CLA 2011-05-19 15:11:12 EDT
Looks reasonable to me. 

(In reply to comment #20)
> Considering that DSF-GDB currently ignores GDB's stderr altogether, and that
> CDI outputs to the GDB console, I think doing the same for DSF-GDB is good
> enough.

I wonder if there'd a way to get this right in all cases.  i.e.
if (PTY || target {sim|...} )
   send gdb stderr to GDB console
else /* native debugging minus PTY */
   send gdb stderr to target console

I suspect most people using DSF/GDB will be on linux native, so it would make sense for stderr to go to the program console by default. If there was a way to configure where it went that might be an optimal solution?
Comment 24 Marc Khouzam CLA 2011-05-19 15:57:17 EDT
(In reply to comment #22)
> Looks reasonable to me. 
> 
> (In reply to comment #20)
> > Considering that DSF-GDB currently ignores GDB's stderr altogether, and that
> > CDI outputs to the GDB console, I think doing the same for DSF-GDB is good
> > enough.
> 
> I wonder if there'd a way to get this right in all cases.  i.e.
> if (PTY || target {sim|...} )
>    send gdb stderr to GDB console
> else /* native debugging minus PTY */
>    send gdb stderr to target console
> 
> I suspect most people using DSF/GDB will be on linux native, so it would make
> sense for stderr to go to the program console by default. If there was a way to
> configure where it went that might be an optimal solution?

On linux native we _always_ use a PTY, and in that case, the inferior stderr goes to the PTY (i.e., the target console).  So, this bug was really aimed at Windows users.  But I'm all for a better solution for Windows, if we can figure something out.  

I'll leave it alone for now until someone requests it, or some solution is proposed.
Comment 25 Marc Khouzam CLA 2011-05-19 16:12:35 EDT
*** Bug 344126 has been marked as a duplicate of this bug. ***
Comment 26 Marc Khouzam CLA 2011-05-24 11:57:04 EDT
*** Bug 330751 has been marked as a duplicate of this bug. ***
Comment 27 Tim Cook CLA 2011-08-05 17:25:36 EDT
Stderr and stdout should go to the same console on Windows, not stdout to the target console and stderr to the gdb console. My original patch accomplished this on Windows. This works properly on Linux.
Comment 28 Marc Khouzam CLA 2012-03-05 11:05:43 EST
I'm putting this back in the pool if someone has a solution that allows us to know which output of stderr should go to the process console and which should go to the gdb console.