可以在 posix_spawn 的 argv 中传递字符串文字吗?
Can string literals be passed in posix_spawn's argv?
对于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 );
我很确定选择该类型是为了与 main
(和 execve
)的 char **argv
参数兼容。 (尽管在具有适当进程分离的传统实现中,内核最终必须进行复制。)
POSIX 似乎并没有说这些数组被修改了,但我非常有信心现有的实现不会修改它们。使用不同的参数(和可执行文件名称)可能有一些原因,但这些参数会 更长 ,因此 posix_spawn
无论如何都必须为副本分配内存,并且无法执行就地修改。
is there a guarantee somewhere that it is OK to pass a string literal? Or are we risking a segfault?
考虑到,存在技术段错误风险,因为 argv
需要 char*
的非 const
数组并提供 字符串文字 可导致 UB。使用一个函数可能建模 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. 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 );
备选
虽然使用 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]
在这里使用字符串文字非常好。
指针参数(或参数指向的指针数据)是否指向const限定类型与函数是否可以修改指向的对象无关。这纯粹是相关功能的契约问题。作为惯例,当对象不被修改时,通常最好在参数中使用 const 限定指针:
- 允许在不强制转换的情况下将指针传递给 const 限定的对象,并且
- 表示对象不会被修改。
但是在C语言中没有要求这样做。对于在其接口中使用双指针类型的函数,这里通常需要权衡。由于 T *
和 const T *
不能互为别名,接口必须选择调用者更可能需要的形式;如果调用者想要其他形式,它必须制作一个临时副本以传递给函数。 posix_spawn
.
就是这种情况
一般来说,当涉及到标准函数(C 或 POSIX)时,它们 不会有任何可观察到的副作用,除非指定 。除非函数的描述说明它将修改一个对象 "belonging to" 应用程序,或者应用程序可以访问的对象,否则它不能修改它;这样做是不合格的。这就是 return 指向静态存储的函数明确记录它的原因。例如,POSIX 文档 strerror
:
The returned string pointer might be invalidated or the string content might be overwritten by a subsequent call to strerror(),
缺少此类文档,应用程序可能会假设由 strerror
编辑的字符串 return 从未被实现修改。
由于 posix_spawn
没有记录修改其 argv
数组指向的字符串,因此不会修改它们。
此外,请注意 posix_spawn
需要线程安全,并且不会对应用程序并发访问 argv
字符串施加任何明确的限制。因此,任何修改都会引入数据竞争,从而导致 posix_spawn
非线程安全,这与规范相反。
对于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 );
我很确定选择该类型是为了与 main
(和 execve
)的 char **argv
参数兼容。 (尽管在具有适当进程分离的传统实现中,内核最终必须进行复制。)
POSIX 似乎并没有说这些数组被修改了,但我非常有信心现有的实现不会修改它们。使用不同的参数(和可执行文件名称)可能有一些原因,但这些参数会 更长 ,因此 posix_spawn
无论如何都必须为副本分配内存,并且无法执行就地修改。
is there a guarantee somewhere that it is OK to pass a string literal? Or are we risking a segfault?
考虑到,存在技术段错误风险,因为 argv
需要 char*
的非 const
数组并提供 字符串文字 可导致 UB。使用一个函数可能建模 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. 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 );
备选
虽然使用 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]
在这里使用字符串文字非常好。
指针参数(或参数指向的指针数据)是否指向const限定类型与函数是否可以修改指向的对象无关。这纯粹是相关功能的契约问题。作为惯例,当对象不被修改时,通常最好在参数中使用 const 限定指针:
- 允许在不强制转换的情况下将指针传递给 const 限定的对象,并且
- 表示对象不会被修改。
但是在C语言中没有要求这样做。对于在其接口中使用双指针类型的函数,这里通常需要权衡。由于 T *
和 const T *
不能互为别名,接口必须选择调用者更可能需要的形式;如果调用者想要其他形式,它必须制作一个临时副本以传递给函数。 posix_spawn
.
一般来说,当涉及到标准函数(C 或 POSIX)时,它们 不会有任何可观察到的副作用,除非指定 。除非函数的描述说明它将修改一个对象 "belonging to" 应用程序,或者应用程序可以访问的对象,否则它不能修改它;这样做是不合格的。这就是 return 指向静态存储的函数明确记录它的原因。例如,POSIX 文档 strerror
:
The returned string pointer might be invalidated or the string content might be overwritten by a subsequent call to strerror(),
缺少此类文档,应用程序可能会假设由 strerror
编辑的字符串 return 从未被实现修改。
由于 posix_spawn
没有记录修改其 argv
数组指向的字符串,因此不会修改它们。
此外,请注意 posix_spawn
需要线程安全,并且不会对应用程序并发访问 argv
字符串施加任何明确的限制。因此,任何修改都会引入数据竞争,从而导致 posix_spawn
非线程安全,这与规范相反。