问题
UPDATE 1: This question has been updated to eliminate the multithreading, simplifying its scope. The original problem popen
ed in the main thread, and pclose
d the child process in a different thread. The problem being asked about is reproducible much more simply, by doing the popen
and pclose
in the same (main) thread.
Update 2: With help from responders at How to check libc version?, I think I've identified that the libc being used is uClibc 0.9.30.
The following code popen
s a script in the main thread, waits a little bit, then pclose
s the child process in the same main thread. This program is cross-compiled for several cross-targets.
The executable's code:
// mybin.c
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
static FILE* logFile = NULL;
static void logInit( const char* fmt );
static void log_( const char* file, int line, const char* fmt, ... );
static void logCleanup();
#define log(fmt, ...) log_( __FILE__, __LINE__, fmt, ##__VA_ARGS__ )
int main( int argc, char* argv[] )
{
logInit( "./mybin.log" );
{
bool success = false;
FILE* f;
if ( ! (f = popen( "./myscript", "r" )) )
{
log( "popen error: %d (%s)", errno, strerror( errno ) );
goto end;
}
log( "before sleep" );
sleep( 1 );
log( "after sleep" );
pclose( f );
log( "after pclose" );
success = true;
}
end:
log( "At end" );
logCleanup();
return 0;
}
/** Initializes logging */
static void logInit( const char* file )
{
logFile = fopen( file, "a" );
}
/** Logs timestamp-prefixed, newline-suffixed printf-style text */
static void log_( const char* file, int line, const char* fmt, ... )
{
//static FILE* logOut = logFile ? logFile : stdout;
FILE* logOut = logFile ? logFile : stdout;
time_t t = time( NULL );
char fmtTime[16] = { '\0' };
struct tm stm = *(localtime( &t ));
char logStr[1024] = { '\0' };
va_list args;
va_start( args, fmt );
vsnprintf( logStr, sizeof logStr, fmt, args );
va_end( args );
strftime( fmtTime, sizeof fmtTime, "%Y%m%d_%H%M%S", &stm );
fprintf( logOut, "%s %s@%d %s\n", fmtTime, file, line, logStr );
}
/** Cleans up after logInit() */
static void logCleanup()
{
if ( logFile ) { fclose( logFile ); }
logFile = NULL;
}
The script:
#! /bin/bash
# mybin
rm -f ./myscript.log
for i in {1..10}; do echo "$(date +"%Y%m%d_%H%M%S") script is running" >> ./myscript.log; sleep 1; done
The expected behavior is that the compiled executable spawns execution of the script in a child process, waits for its completion, then exits. This is met on many cross-targets including x86, x64, and ARM. Below is an example architecture on which the expected behavior is met, compilation, and corresponding logs:
$ uname -a
Linux linuxbox 5.4.8-200.fc31.x86_64 #1 SMP Mon Jan 6 16:44:18 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
Compilation:
$ gcc --version && gcc -g ./mybin.c -lpthread -o mybin
gcc (GCC) 9.2.1 20190827 (Red Hat 9.2.1-1)
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$
mybin.log:
20200705_200950 ./mybin.c@33 before sleep
20200705_200951 ./mybin.c@35 after sleep
20200705_201000 ./mybin.c@37 after pclose
20200705_201000 ./mybin.c@44 At end
myscript.log:
20200705_200950 script is running
20200705_200951 script is running
20200705_200952 script is running
20200705_200953 script is running
20200705_200954 script is running
20200705_200955 script is running
20200705_200956 script is running
20200705_200957 script is running
20200705_200958 script is running
20200705_200959 script is running
However, on one target, an odd thing occurs: pclose
returns early: after the script has started running, but well before it has completed running -- why? Below is the problem architecture on which the unexpected behavior is observed, cross-compiler flags, and corresponding logs:
$ uname -a
Linux hostname 2.6.33-arm1 #2 Wed Jul 1 23:05:25 UTC 2020 armv7ml GNU/Linux
Cross-compilation:
$ /path/to/toolchains/ARM-cortex-m3-4.4/bin/arm-uclinuxeabi-gcc --version
arm-uclinuxeabi-gcc (Sourcery G++ Lite 2010q1-189) 4.4.1
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ /path/to/toolchains/ARM-cortex-m3-4.4/bin/arm-uclinuxeabi-gcc -O2 -Wall -fno-strict-aliasing -Os -D__uClinux__ -fno-strict-aliasing -mcpu=cortex-m3 -mthumb -g -ffunction-sections -fdata-sections -I/path/to/toolchains/ARM-cortex-m3-4.4/usr/include/ -Wl,--gc-sections -Wl,-elf2flt=-s -Wl,-elf2flt=8192 -I/path/to/toolchains/ARM-cortex-m3-4.4/sysroot/usr/include -I/path/to/libs/ARM-cortex-m3-4.4/usr/include/ -L/path/to/toolchains/ARM-cortex-m3-4.4/sysroot/usr/lib -lrt -L/path/to/libs/ARM-cortex-m3-4.4/usr/lib -L/path/to/libs/ARM-cortex-m3-4.4/lib -o mybin ./mybin.c -lrt -lpthread
$
mybin.log:
20200705_235632 ./mybin.c@33 before sleep
20200705_235633 ./mybin.c@35 after sleep
20200705_235633 ./mybin.c@37 after pclose
20200705_235633 ./mybin.c@44 At end
myscript.log:
20200705_235632 script is running
The gist of my question is: why does pclose
return prematurely, and why only on this one cross-target?
Comments and research have me circling the notion that this is a bug in the variant/version of libc
- it'd be great if someone knowledgeable on the subject could help confirm if that is the case.
Not a dup of pclose() prematurely returning in a multi-threaded environment (Solaris 11)
来源:https://stackoverflow.com/questions/62724531/why-does-pclose-return-prematurely