[英]Can string literals be passed in posix_spawn's argv?
For the posix_spawn
function its prototype is: 对于
posix_spawn
函数,它的原型是:
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 (ie pointers to mutable characters). 值得注意的是,
argv
参数指向char *
指针数组(即指向可变字符的指针)。 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 );
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. 指针参数(或参数指向的指针数据)是否指向const限定类型与函数是否可以修改指向对象无关。 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:
作为惯例,当对象不被修改时,通常最好在参数中使用const限定指针:
but there is no requirement to do so in the C language. 但是没有要求用C语言这样做。 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; 由于
T *
和const T *
不能互为别名,因此界面必须选择更有可能让调用者想要的形式; 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
. 这是
posix_spawn
的情况。
In general, when it comes to standard functions (C or POSIX), they cannot have any observable side effects except as specified . 通常,当涉及标准函数(C或POSIX)时, 除非另有说明 ,否则它们不会有任何可观察到的副作用 。 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
: 例如,用于
strerror
POSIX文档:
The returned string pointer might be invalidated or the string content might be overwritten by a subsequent call to strerror(),
返回的字符串指针可能无效,或者后续调用strerror()可能会覆盖字符串内容,
Short of such documentation, an application could assume that the string returned by strerror
is never modified by the implementation. 如果没有这样的文档,应用程序可以假定
strerror
返回的字符串永远不会被实现修改。
Since posix_spawn
is not documented to modify the strings pointed to by its argv
array, it does not modify them. 由于没有记录
posix_spawn
来修改其argv
数组指向的字符串,因此它不会修改它们。
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. 此外,请注意,
posix_spawn
必须是线程安全的,并且不对应用程序进行任何显式约束以便并发访问argv
字符串。 As such, any modification would introduce data races, thereby rendering posix_spawn
non-thread-safe, contrary to specification. 因此,任何修改都会引入数据争用,从而使
posix_spawn
非线程安全,与规范相反。
I'm pretty sure the type was chosen for compatibility with the char **argv
argument to main
(and execve
). 我很确定选择的类型与
main
(和execve
)的char **argv
参数兼容。 (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. POSIX似乎没有说这些数组被修改,但我相信没有现有的实现会修改它们。 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. 使用不同的参数(和可执行文件名称)可能有一些原因,但这些参数会更长 ,因此
posix_spawn
无论如何都必须为副本分配内存,并且不能就地执行修改。
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. 鉴于,存在技术段错误风险,因为
argv
期望非const
char*
数组并提供字符串文字可以导致UB。 With a function perhaps modeling main(int argc, char *argv[])
, code can write to argv[0]
. 使用函数建模
main(int argc, char *argv[])
,代码可以写入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.参数
argc
和argv
以及argv
数组指向的字符串应该可由程序修改 ,并在程序启动和程序终止之间保留它们最后存储的值。 C11 §5.1.2.2.1 2C11§5.1.2.2.12
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. 虽然使用
posix_spawn()
,我怀疑是否会发生写入,C99的解决方案使用复合文字而不是字符串文字 ,因此避免了UB的潜力。
// 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]
现在
posix_spawn()
可以写入v2[0]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.