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

时间:2018-05-30 04:32:13

标签: c posix string-literals

对于the posix_spawn function,其原型是:

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]);

值得注意的是,argv参数指向char *指针数组(即指向可变字符的指针)。此外,文档似乎没有保证不会写入数据。

我的问题是:是否可以保证传递字符串文字?或者我们冒着一个段错误的风险?

示例代码:

char *v[] = { "foo.exe", "bar", NULL };
posix_spawn( NULL, "foo.exe", NULL, NULL, v, NULL );

3 个答案:

答案 0 :(得分:2)

在这里使用字符串文字非常好。

指针参数(或参数指向的指针数据)是否指向const限定类型与函数是否可以修改指向对象无关。这纯粹是有关功能合同的问题。作为惯例,当对象不被修改时,通常最好在参数中使用const限定指针:

  1. 允许将指针传递给没有强制转换的const限定对象,
  2. 表示不会修改对象。
  3. 但是没有要求在C语言中这样做。对于在其接口中使用双指针类型的函数,这里通常需要权衡。由于T *const T *不能互为别名,因此界面必须选择更有可能让调用者想要的格式;如果调用者想要另一个表单,则必须将临时副本传递给该函数。这是posix_spawn的情况。

    一般来说,当涉及标准功能(C或POSIX)时,除了指定的之外,不能有任何可观察到的副作用。除非函数文档描述它将修改对象“属于”应用程序,或者应用程序可以访问的对象,否则它不能修改它;这样做是不合格的。这就是返回指向静态存储指针的函数显式记录它的原因。例如,strerror的POSIX文档:

      

    返回的字符串指针可能无效,或者后续调用strerror()可能会覆盖字符串内容,

    如果缺少此类文档,应用程序可能会认为strerror返回的字符串永远不会被实现修改。

    由于未记录posix_spawn来修改其argv数组指向的字符串,因此不会修改它们。

    此外,请注意posix_spawn必须是线程安全的,并且不会对应用程序对argv字符串的并发访问进行任何显式约束。因此,任何修改都会引入数据竞争,从而使posix_spawn非线程安全,与规范相反。

答案 1 :(得分:1)

我非常确定选择的类型与java-8-openjdk {和char **argv的{​​{1}}参数兼容。 (虽然在传统的实现具有适当的进程分离的情况下,内核最终必须进行复制。)

POSIX似乎没有说这些数组已被修改,但我非常有信心没有现有的实现会修改它们。使用不同的参数(和可执行文件名)可能有一些原因,但那些更长,因此main必须为副本分配内存,并且不能在以下情况下执行修改:的地方。

答案 2 :(得分:1)

  

是否可以保证传递字符串文字?或者我们冒着一个段错误的风险?

鉴于,argv期望非const数组char*并提供字符串文字可导致UB,因此存在技术段错误风险。使用可能建模main(int argc, char *argv[])的函数,代码可以写入argv[0]

  

int main(int argc, char *argv[])
  ...
  参数argcargv以及argv数组指向的字符串应由程序可修改,并在程序启动之间保留其最后存储的值和程序终止。 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 );

<强>替代

虽然使用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 );

现在posix_spawn()可以写入v2[0]