Why does pclose return prematurely?

拥有回忆 提交于 2020-07-09 17:13:42

问题


UPDATE 1: This question has been updated to eliminate the multithreading, simplifying its scope. The original problem popened in the main thread, and pclosed 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 popens a script in the main thread, waits a little bit, then pcloses 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!