Bug 749017

Summary: don't flush stdout at program exit
Product: Red Hat Enterprise Linux 6 Reporter: Levente Farkas <lfarkas>
Component: glibcAssignee: Jeff Law <law>
Status: CLOSED NOTABUG QA Contact: qe-baseos-tools-bugs
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 6.1CC: fweimer, mfranc
Target Milestone: rc   
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2012-02-15 21:04:07 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Levente Farkas 2011-10-25 20:28:40 UTC
the long story short:
-----------------------------------
[root@raif-nvr-5 ~]# vidux-helper hdsentinel getDisks 2>/dev/null
/dev/sda
/dev/sdb
[root@raif-nvr-5 ~]# vidux-helper hdsentinel getDisks >out
[root@raif-nvr-5 ~]# ll out
-rw-r--r-- 1 root root 0 Oct 24 22:33 out
-----------------------------------
so we've got a helper binary exec. which produce output (eg. the disk devices), BUT if i redirect it into a file then a file becomes empty! how can it be possible??? imho it's against the standard.
unfortunately i can't share the code since it's include proprietary libs too.  
but this's the relevant part:
-----------------------------------
static int hds_getdisks(int argc, char *argv[], void *data)
{
        char **diskarr;

        if ((diskarr = getDisks()) == NULL) {
                fprintf(stderr, "%s: can't init hdsentinel\n", progname);
                return EXIT_FAILURE;
        }

        while (*diskarr)
                puts(*diskarr++);
        //fflush(stdout);
        return EXIT_SUCCESS;
}
-----------------------------------
if i comment out the above fflush(stdout); then it's working. but why? (anyway we don not call setvbuf, setlinebuf or setbuf*).
but how can it be possible that at program exit the stdout is not flushed?

ps. anyway the same program is working on rhel-5 but not on rhel-6.

Comment 2 Andreas Schwab 2011-10-26 07:30:39 UTC
There is no test case.

Comment 3 RHEL Program Management 2011-10-30 05:47:42 UTC
Since RHEL 6.2 External Beta has begun, and this bug remains
unresolved, it has been rejected as it is not proposed as
exception or blocker.

Red Hat invites you to ask your support representative to
propose this request, if appropriate and relevant, in the
next release of Red Hat Enterprise Linux.

Comment 4 Levente Farkas 2011-11-03 20:31:42 UTC
is there any way i can sen licensed binary .so files which needed to link and run an example c program?

Comment 5 Jeff Law 2012-02-07 21:19:11 UTC
Levente,

It really depends on the license.  I obviously can't give legal advice about what you can and can not send, particularly since I'm not privy to the license terms.

In the mean time, could you run your testcase using strace?  That should show the syscalls being issued, which might in turn lead us towards the bug.

Thanks,

Comment 6 Jeff Law 2012-02-07 21:28:45 UTC
One more thing to note, are you absolutely sure the disk isn't full?  That's the one case I'm aware of where this kind of behaviour would be expected.

Comment 7 Levente Farkas 2012-02-14 22:16:07 UTC
i'm absolutely sure (tested on many system).

our solution was to add
setlinebuf(stdout); 
at the beginning of the main and it's start to working:-)
anyway it's a setuid root program so can't be straced as normal user, but i can strace as root, the effect is the same:
-------------------------------
[root@eagle ~]# /home/lfarkas/workspace/Vidux/vidux-helper/vidux-helper hdsentinel getDisks
/dev/sda
/dev/sdb
[root@eagle ~]# /home/lfarkas/workspace/Vidux/vidux-helper/vidux-helper hdsentinel getDisks >out
[root@eagle ~]# ls -l out 
-rw-r--r-- 1 root root 0 Feb 14 23:02 out
-------------------------------
and:
-------------------------------
# strace /home/lfarkas/workspace/Vidux/vidux-helper/vidux-helper hdsentinel getDisks
...
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2b95bba000
write(1, "/dev/sda\n", 9/dev/sda
)               = 9
write(1, "/dev/sdb\n", 9/dev/sdb
)               = 9
exit_group(0)                           = ?
-------------------------------
but at the same time
-------------------------------
# strace /home/lfarkas/workspace/Vidux/vidux-helper/vidux-helper hdsentinel getDisks >out 
...
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f15abe86000
exit_group(0)                           = ?
[root@eagle ~]# ls -l out 
-rw-r--r-- 1 root root 0 Feb 14 23:04 out
-------------------------------
and i send you a private mail too:-)

Comment 8 Jeff Law 2012-02-15 21:04:07 UTC
The problem here is libhds's has a FINI defined (readelf --dynamic libhds.so).

The FINI points to location 0x3deaa within the shared library which is a routine _haltproc.

_haltproc looks like;

(gdb) x/10i 0x3deaa
   0x3deaa <_haltproc>: callq  0x54748 <SYSTEM_LIB_EXIT>
   0x3deaf <_haltproc+5>:       mov    $0xe7,%eax
   0x3deb4 <_haltproc+10>:      mov    0x2b8425(%rip),%rbx        # 0x2f62e0
   0x3debb <_haltproc+17>:      movzwl (%rbx),%edi
   0x3debe <_haltproc+20>:      syscall 


Note the syscall instruction and the assignment to $eax at location 0x3deaf.  syscall 0xe7 is the exitgroup syscall.  This causes the process to exit when libhds's FINI is run.  That in turn prevents the exit handlers within the C library from running and thus the IO buffers are not flushed.

Whomever provides libhds needs to fix their library to not halt the process as that's going to prevent any other shlib FINI functions from running as well as preventing the standard exit handlers from running (which close open file descriptors, flush buffers, etc).