Reputation: 141628
For the posix_spawn
function its prototype is:
int posix_spawn(pid_t *restrict pid, const char *restrict path,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *restrict attrp,
char *const argv[restrict], char *const envp[restrict]);
Notably, the argv
parameter points to an array of char *
pointers (i.e. pointers to mutable characters). Further, the documentation does not seem to give any guarantee that the data will not be written to.
My question is: is there a guarantee somewhere that it is OK to pass a string literal? Or are we risking a segfault?
Sample code:
char *v[] = { "foo.exe", "bar", NULL };
posix_spawn( NULL, "foo.exe", NULL, NULL, v, NULL );
Upvotes: 8
Views: 1623
Reputation: 215407
Using string literals is perfectly fine here.
Whether a pointer argument (or pointer data pointed to by an argument) points to const-qualified type has nothing to do with whether the function can modify a pointed-to object. This is purely a matter of the contract of the function in question. As a convention, it's usually preferable to use const-qualified pointers in arguments when the object won't be modified:
but there is no requirement to do so in the C language. And for functions that use double-pointer types in their interfaces, there's often a tradeoff here. Since T *
and const T *
cannot alias one another, the interface has to choose the form more likely for the caller to want; if the caller wants the other form, it has to make a temporary copy to pass to the function. This is the case for posix_spawn
.
In general, when it comes to standard functions (C or POSIX), they cannot have any observable side effects except as specified. Unless the DESCRIPTION for the function documents that it will modify an object "belonging to" the application, or which the application has access to, it cannot modify it; doing so is non-conforming. This is why functions which return pointers to static storage explicitly document it. For example, POSIX documents for strerror
:
The returned string pointer might be invalidated or the string content might be overwritten by a subsequent call to strerror(),
Short of such documentation, an application could assume that the string returned by strerror
is never modified by the implementation.
Since posix_spawn
is not documented to modify the strings pointed to by its argv
array, it does not modify them.
Further, note that posix_spawn
is required to be thread-safe, and does not place any explicit constraint on applications for concurrent access to the argv
strings. As such, any modification would introduce data races, thereby rendering posix_spawn
non-thread-safe, contrary to specification.
Upvotes: 3
Reputation: 154245
is there a guarantee somewhere that it is OK to pass a string literal? Or are we risking a segfault?
Given, there is a technical segfault risk as argv
expects a non-const
array of char*
and providing a string literal can lead to UB. With a function perhaps modeling main(int argc, char *argv[])
, code can write to argv[0]
.
int main(int argc, char *argv[])
...
The parametersargc
andargv
and the strings pointed to by theargv
array shall be modifiable by the program, and retain their last-stored values between program startup and program termination. C11 §5.1.2.2.1 2
int foo(......., char *const argv[restrict], char *const envp[restrict]);
char *v[] = { "foo.exe", "bar", NULL };
foo( NULL, "foo.exe", NULL, NULL, v, NULL );
Alternative
Although with posix_spawn()
, I doubt a write will occur, a solution with C99 employs a compound literal rather than a string literal and so avoids UB potential.
// char *v[] = { "foo.exe", "bar", NULL };
char *v2[] = { (char [8]){"foo.exe"}, (char [4]){"bar"}, NULL };
posix_spawn( NULL, "foo.exe", NULL, NULL, v2, NULL );
Now posix_spawn()
can write to v2[0]
Upvotes: 1
Reputation: 33717
I'm pretty sure the type was chosen for compatibility with the char **argv
argument to main
(and execve
). (Although in a traditional implementation with proper process separation, the kernel eventually has to make a copy.)
POSIX does not seem to say that these arrays are modified, but I'm pretty confident that no existing implementation will modify them. There could be some reasons for using different arguments (and executable names), but those will be longer, so posix_spawn
has to allocate memory for a copy anyway, and cannot perform the modification in-place.
Upvotes: 1