ma lz <[email protected]> writes:
> In certain environments (e.g., CentOS 7 host with Docker container running
> Euler 24.03, older kernel), popen() internally first tries clone3, which
> fails with ENOSYS (38), then falls back to traditional clone and succeeds.
> However, the errno value from the failed clone3 attempt (38) is not cleared,
> so after a successful popen(), errno remains 38.
Sure.
> If a caller (incorrectly) checks errno even when popen() succeeds, they might
> see errno == ENOSYS and mistakenly believe an error occurred, even though the
> command executed successfully.
That would be a a bug in that caller (and I don't see any such
caller). It is *extremely* common for system functions to trash errno
in non-failure paths. That variable is only promised to be meaningful
after a failure return.
The point of the errno = 0 step in popen_check() is so that we don't
print an unrelated error code if popen fails without setting errno.
POSIX doesn't require it to set errno, oddly enough:
Upon successful completion, popen() shall return a pointer to an
open stream that can be used to read or write to the
pipe. Otherwise, it shall return a null pointer and may set errno
to indicate the error.
> Proposed Fix
> Move errno = 0 to the success path, so errno is only cleared when popen()
> actually succeeds:
This is based on a complete misunderstanding of what that step is for.
It would break the case we're protecting against without fixing
anything.
regards, tom lane