Program with pseudo-tty behaving differently in single-step

Andrea Monaco via Gdb <[email protected]>
Newsgroups gmane.comp.gdb.devel
Message-ID <[email protected]>
I have a program that behaves very differently when single-stepping and
when running freely in gdb.

The first part of the program opens a pseudo-terminal pair in the usual
way.  This pair includes a master (that sort of simulates the user: you
can read from master and write to master like a human would do) and a
slave (that the child process uses as a terminal for stdin and stdout,
receiving what you send to master and sending back to master).

The child process runs bc (a calculator).  The parent sends the line
"1+1\n" and reads back the subsequent line.


#define _GNU_SOURCE


#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>


char buffer [1024];


int master, slave;


ssize_t
readl (int fd, char *buf)
{
  ssize_t i = 0;

  do
    {
      read (fd, buf+i, 1);
    }
  while (buf [i++] != '\n');

  return i;
}


int
main (int argc, char *argv [])
{
  int i;
  char *name;
  pid_t child;

  master = getpt ();

  if (master < 0)
    {
      perror ("getpt() failed");
      return 1;
    }

  if (grantpt (master) < 0 || unlockpt (master) < 0)
    {
      perror ("grantpt() or unlockpt() failed");
      return 1;
    }

  name = ptsname (master);
  
  if (!name)
    return 1;

  slave = open (name, O_RDWR);
  
  if (slave < 0)
    {
      perror ("could not open slave");
      return 1;
    }

  /* until now, we opened a pseudo-tty pair in the standard way */

  child = fork ();

  if (child < 0)
    {
      perror ("fork failed");
      return 1;
    }

  if (!child)
    {
      /* in the child, we close stdin and stdout and substitute them
	 both with the slave pseudo-terminal for input and output */
      
      close (1); 
      close (0);

      if (dup (slave) == -1 || dup (slave) == -1)
	{
	  perror ("dup failed");
	  return 1;
	}
      
      execlp ("bc", "bc", NULL);
      
      perror ("could not exec bc");
    }

  /* in the parent, we skip the startup message of bc */
  for (i = 0; i < 4; i++)
    {
      readl (master, buffer);
    }

  write (master, "1+1\n", strlen ("1+1\n"));
  readl (master, buffer); /* we skip the echo line of 1+1 */
  
  read (master, buffer, 3);  /* now we read the result line */

  buffer [3] = '\0';
  
  printf ("%s", buffer);
  
  return 0;
}


In gdb, when I do a run I get "1+1" as output.  When I single-step, I
get 2 from the last printf instead, which is the desired output.

Can anyone replicate this?  Is there a known explanation?



Andrea Monaco
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.