On 2025-06-13 21:39, Glenn Strauss via Cygwin wrote:
On Fri, Jun 13, 2025 at 02:25:17PM -0700, Jeremy Drake via Cygwin wrote:
On Fri, 13 Jun 2025, Jeremy Drake wrote:

I am working on some posix_spawn tests for the new stc repository [1], and
making sure they behave the same between Cygwin and Linux.  I found one
case (so far) which does not: passing NULL for argument "envp" to
posix_spawn.

In Cygwin, this results in the child inheriting the environment from the
caller (same as passing "environ"), but on Linux this results in the child
getting an empty environment (same as passing a char *envp[] = {NULL}).

The Open Group doc on posix_spawn[2] doesn't seem to say anything about
the potential for envp being NULL, but does mention

For the Ada language binding for Start_Process to be implemented with
posix_spawn(), that binding would need to explicitly pass an empty
signal mask and the parent's environment to posix_spawn() whenever the
caller of Start_Process allowed these arguments to default, since
posix_spawn() does not provide such defaults.

That at least implies that passing NULL does not default to using the
parent's environment.

Thoughts?  Is this a bug in Cygwin, or "undefined behavior" that it's
perfectly within its rights to do whatever it feels like in response
(empty environment or inherited environment, or crash every second
Tuesday)?

Oops, I forgot my footnote links:

[1]: https://cygwin.com/cgit/cygwin-apps/stc/
[2]: https://pubs.opengroup.org/onlinepubs/007904975/functions/posix_spawn.html

Latest Issue 8 2024 SUSV5:

https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn.html

says envp is pointer to char * array.

The man pages from different OS contain something like (from Linux):

    The argument envp is an array of character pointers to null-terminated 
strings. These strings constitute the environment for the new
    process image. The environment array is terminated by a null pointer.

I have never interpreted NULL as a valid value for envp.
I think the behavior is unspecified, and could segfault.
If caller intends an empty environment, then caller should pass:
   char *e[] = { NULL };

Could also pass a pointer to the final NULL pointer in environ to avoid defining your own.
Therefore, in lighttpd's portability wrapper for fork-execve,
passing NULL for envp (to my wrapper) is used to inherit default env
from current process (char **environ), whether lighttpd uses
posix_spawn() or execve().  This is the same behavior you described
for Cygwin, though lighttpd passes `environ` to posix_spawn(), not NULL.
--
Take care. Thanks, Brian Inglis              Calgary, Alberta, Canada

La perfection est atteinte                   Perfection is achieved
non pas lorsqu'il n'y a plus rien à ajouter  not when there is no more to add
mais lorsqu'il n'y a plus rien à retrancher  but when there is no more to cut
                                -- Antoine de Saint-Exupéry

--
Problem reports:      https://cygwin.com/problems.html
FAQ:                  https://cygwin.com/faq/
Documentation:        https://cygwin.com/docs.html
Unsubscribe info:     https://cygwin.com/ml/#unsubscribe-simple

Reply via email to