简体   繁体   English

字符串文字可以在posix_spawn的argv中传递吗?

[英]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限定指针:

  1. to allow passing pointers to const-qualified objects without casts, and 允许将指针传递给没有强制转换的const限定对象,以及
  2. as an indication that the object won't be modified. 表示不会修改对象。

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 parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination. 参数argcargv以及argv数组指向的字符串应该可由程序修改 ,并在程序启动和程序终止之间保留它们最后存储的值。 C11 §5.1.2.2.1 2 C11§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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM