Bug 976368 - printf() not properly handling pthread cancelling
printf() not properly handling pthread cancelling
Status: NEW
Product: Red Hat Enterprise Linux 7
Classification: Red Hat
Component: glibc (Show other bugs)
7.2
i686 Linux
unspecified Severity medium
: rc
: 7.2
Assigned To: glibc team
qe-baseos-tools
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2013-06-20 08:56 EDT by Nils Olav Selåsdal
Modified: 2017-07-28 07:12 EDT (History)
6 users (show)

See Also:
Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed:
Type: Bug
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)

  None (edit)
Description Nils Olav Selåsdal 2013-06-20 08:56:46 EDT
Description of problem:

It seems printf() doesn't properly handle pthread cancellation requests.

According to http://pubs.opengroup.org/onlinepubs/9699919799//functions/V2_chap02.html printf is either a cancellation point, or it's not allowed to be a cancellation point, in either case it should not leave stdout in an inconsistent state.

Version-Release number of selected component (if applicable):
glibc-2.12-1.80.el6_3.7.i686

Steps to Reproduce:
The following program, compiled with g++ t.cpp -pthread
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

void *my_routine(void *arg) {
  int i;
  for (i = 0; i < 200; i++) {
    printf("%d\n", i);
  }
  return NULL;
}

int main(void) {
  pthread_t thread;
  if (pthread_create(&thread, NULL, my_routine, NULL)) {
    fprintf(stderr, "Cannot create pthread\n");
    return 1;
  }
  usleep(0);
  pthread_cancel(thread);
  pthread_join(thread, NULL);
  //fflush(stdout);
  sleep(1);
  return 0;
}

will occasionally print a number twice, suggesting that printf() has been cancelled in mid operation - not properly cleaning up its internals, e.g. as in this output:

$ ./a.out 
0
1
2
3
4
5
6
7
8
9
10
11
12
13
13
Comment 2 Carlos O'Donell 2013-06-20 10:11:42 EDT
(In reply to Nils Olav Selesdal from comment #0)
> Description of problem:
> 
> It seems printf() doesn't properly handle pthread cancellation requests.

Agreed, it looks like the stream state isn't fully consistent. It would appear that the write completes but before it can be recorded as complete the cancellation is acted upon. Then when we flush the stream before thread exit and we flush the output again a second time (recording it correctly this time). Thus I suspect it's always a double flush at the end of a the list of numbers.

The immediate workaround is to disable cancellation around printf.

> will occasionally print a number twice, suggesting that printf() has been
> cancelled in mid operation - not properly cleaning up its internals, e.g. as
> in this output:

That is not correct. Asynchronous cancellation is not the default state for glibc. Therefore printf can't be interrupted mid-operation. However, printf must ensure that it's internal state is consistent *before* calling any other operation that may be a cancellation point (since that would cause the cancellation to trigger).

How many times do you have to run this to see the double output? A hundred? A million?
Comment 3 Nils Olav Selåsdal 2013-06-20 10:34:45 EDT
> How many times do you have to run this to see the double output? A hundred?
> A million?

This happened 3 times within 20 runs now.
Comment 7 Carlos O'Donell 2015-01-14 17:06:53 EST
It is not likely we will fix this for RHEL 6 given the rework required to make IO streams completely safe to cancel. The best workaround I can recommend is not to do IO or expect that stdio may be unusable afterwards.

I'm moving the bug to RHEL 7 becuase we want to track this, but the work is going to be done upstream first after the fixes for cancellation are done. The RHEL 6 cancellation implementation is fundamentally flawed and a rewrite was required to make it work correctly and conform to POSIX.

Note You need to log in before you can comment on or make changes to this bug.