将argv [0]设置为比当前分配的值更长的值

时间:2016-05-19 11:16:26

标签: c argv

我正在用C语言编写一个程序来生成大量进程并且应该通过argv [0]报告它们的状态,所以在调用ps时很容易看出发生了什么。

我知道最初argv [0]带有一定的内存分配,包含程序名称(在大多数情况下)。

但是我需要设置比包含程序名称的20个字节更长的字符串。我的状态可以是80到100个字符。

我做了一些测试,如果我把这个更长的字符串记忆到argv [0]中它“对我有效”但我担心我会开始写入无主内存并导致段错误,这是不可接受的。

如何安全地调整为argv [0]分配的内存?

示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* generate_really_long_program_name() {
  return strdup("here is something that generates really long program name\0");
}


int main (int argc, char *argv[])
{
  printf("Current argv[0] length: %zu\n", strlen(argv[0]));

  char* my_program_name = generate_really_long_program_name();
  strncpy(argv[0], my_program_name, strlen(my_program_name)); // Can this segfault?
  free(my_program_name);

  printf("New argv[0] length: %zu\n", strlen(argv[0]));

  return 0;
}

示例输出:

$ ./argv
Current argv[0] length: 6
New argv[0] length: 57

1 个答案:

答案 0 :(得分:1)

要在Linux下的ps更改名称显示,请使用prctl而不是更改argv[0](这是一个黑客攻击 - 而且这种黑客行为无处不在):

int s;
s = prctl(PR_SET_NAME,"myProcess\0",NULL,NULL,NULL); 

执行此行后,请查看ps,您将看到“myProcess”而不是原始名称。

无论prctl的原始长度如何,您都可以随意将任何字符串传递给argv[0]。但是如果你的字符串超过16个字节(包括终止空字节,它将被截断:

  

PR_SET_NAME(自Linux 2.6.9起)
                使用中的值设置调用线程的名称                 (char *)arg2指向的位置。这个名字可以达到                 16个字节长,包括终止空字节。 (如果                 字符串的长度,包括终止空字节,                 超过16个字节,字符串被静默截断。)这是                 可以通过pthread_setname_np(3)设置的相同属性                 并使用pthread_getname_np(3)检索。属性是                 同样可以通过/ proc / self / task / [tid] / comm访问,其中tid                 是调用线程的名称。

关于这个问题:

strncpy(argv[0], my_program_name, strlen(my_program_name)); // Can this segfault?

C99标准说:

  

参数argcargv以及argv数组指向的字符串应该可由程序修改,并在程序启动和程序终止之间保留它们最后存储的值。

但是你不能增加argv[0]的大小,所以如果strlen(my_program_name)大于argv[0]已分配的内存,你将得到一个未定义的行为:缓冲区溢出,段错误或其他任何内容因为它是UB