6

On a Linux system a C process is started on boot, which creates a fork of itself. It is not a kernal process or something. In most cases a ps -ef show both processes as expecxted, but sometimes it looks like the following:

1258 root       0:00 myproc 
1259 root       0:00 [myproc]

i.e. one of the processes surrounded by brackets. According to ps:

If the arguments cannot be located (usually because it has not been set, 
as is the case of system processes and/or kernel threads) the command name 
is printed within square brackets.

I do not understand what it means when the 'arguments cannot be located'. The process is started always exactly the same, and the fork is always created in the exact same way. How can it happen, that sometimes 'the arguments cannot be located' and sometimes they can?

In addition, the process is always started without any arguments...

Questions I have:

  • What do those brackets really mean? Does the process run at all when /proc/{pid}/cmdline is empty?
  • Why do I get those brackets sometimes and not always?
  • How/Where to fix this problem?

Additional information:

  • The process is always started without any arguments! Just the name of the command myproc.
  • The main process seems to run always correct (no brackets around name, executable in /proc/x/cmdline).
  • The child process sometimes has its name in brackets.
  • The content of /proc/child-pid/cmdline of a correct running child process is myproc.
  • The content of /proc/child-pid/cmdline of an incorrect running child process is empty!
  • Again: same code, different child processes!
Alex
  • 5,700
  • That's the arguments passed to the last execve system call that the process (or any of its ancestors) made, found in /proc/the-pid/cmdline on Linux. – Stéphane Chazelas Jan 23 '14 at 14:18
  • The file /proc/the-pid/cmdline contains only exactly one word: myproc. So if this name appears in brackets in ps -ef it means that the argument myproc cannot be located. Does it mean the executable itself cannot be located? That it is not in $PATH? – Alex Jan 23 '14 at 14:22
  • No, I expect /proc/x/cmdline is empty when you see [xxx], where xxx is the process name (not the first argument to the last command that process executed) as found in /proc/x/stat. You can get an empty cmdline for kernel processes (no exec), for the processes that passed an empty list of arguments to the last process they executed, or for processes that altered their argv[] – Stéphane Chazelas Jan 23 '14 at 14:29
  • But how can a fork() command create correct child processes and incorrect child processes at random? Please see updated question – Alex Jan 23 '14 at 14:31
  • The question is not WHAT those brackets mean, but WHY I get them sometimes, at random... – Alex Jan 23 '14 at 14:55
  • 1
    The fork should copy the arg list from the parent. Sounds like a stack overwrite. You could see that if after the fork, your process writes to areas of memory it's not meant to, like envp[0][-1]=1;argv[0][0]=0. The args are at the bottom of the stack, so it's not that difficult to overwrite them by mistake. – Stéphane Chazelas Jan 23 '14 at 14:55
  • 1
    You might want to run the program under valgrind. – psusi Jan 23 '14 at 14:57
  • If the process or any of its parents executed a command (like /path/to/myproc), then it will most likely have received at least one argument, the argv[0], likely "myproc". It's generally hard to execute a command without any argument (with no argv[0]) – Stéphane Chazelas Jan 23 '14 at 14:59
  • So under what circumstances does the child sometimes receive this argument, sometimes not? Does a child without executable make sense at all? – Alex Jan 23 '14 at 15:00
  • 1
    The child inherits the arg list upon the fork. It's not the fork that makes that disappear, it's probably what your child process does later intentionaly or not that does. valgrind is a good advice indeed. – Stéphane Chazelas Jan 23 '14 at 15:02
  • If you started it by entering myproc at a shell prompt, then it received one argument: myproc. – Stéphane Chazelas Jan 23 '14 at 15:06
  • @Stephane: Thanks for the input, I will try to dig deeper. Unfortunately I cannot use valgrind, so I have to debug the code myself ... – Alex Jan 23 '14 at 15:07

2 Answers2

9

ps -f normally shows the argument list passed to the last execve() system call the process or any of its ancestors did.

When you run a command xxx arg1 arg2 at a shell prompt, your shell usually forks a process searches for a command by the xxx name and executes it as:

execve("/path/to/that/xxx", ["xxx", "arg1", "arg2"], @exported_variables)

It should be noted that the first argument is xxx there.

After execution, the whole memory of the process is wiped, and those arguments (and environment) are found at the bottom of the stack of the process.

You get the first 4096 bytes of those arguments in /proc/<the-pid>/cmdline and that's where ps gets it from.

Upon a fork or clone, the child inherits the whole memory of its parent including that arg list.

You get the [xxx] when /proc/<the-pid>/cmdline is empty. In that case, instead of displaying the arg list, ps displays the process name which it finds in /proc/<the-pid>/stat (for executed commands, that's the first 16 bytes of the basename of the executable file passed to the last execve()). That can happen for three reasons (that I can think of):

  • The process or any of its ancestors never executed anything. That's the case of kernel threads (and can only be the case of kernel threads since all the other processes are descendants of init (which is executed)).

    $ ps -fp2
    UID        PID  PPID  C STIME TTY          TIME CMD
    root         2     0  0 Jan13 ?        00:00:00 [kthreadd]
    
  • The process executed a command with an empty list of arguments. That usually never happens because programs are usually always passed at least one argument, the command name, but you can force it with for instance:

    int main(int argc, char *argv[]) {
      if (argc) execve("/proc/self/exe",0,0);
      else system("ps -fp $PPID");
    }
    

    Once compiled and run:

    $ test1
    UID        PID  PPID  C STIME TTY          TIME CMD
    stephane 31932 29296  0 15:16 pts/5    00:00:00 [exe]
    
  • The process overwrites its argv[] on its stack.

    The arguments are NUL-terminated strings in memory. If you make the last character of the arg list non-null for instance with envp[0][-1]=1 (the envp[] values follow the argv[] ones on the stack), then the kernel assumes you've modified it and only returns in /proc/xxx/cmdline the first argument up to the first NUL character. So

    int main(int argc, char* argv[], char *envp[]) {
      envp[0][-1]=1;
      argv[0][0]=0;
      system("ps -fp $PPID");
    }
    

    Would also show [xxx].

    Given that the arglist (and environ) are at the bottom of the stack, this kind of scenario can happen if you've got a bug in your code that makes you write on the stack past the end of what it's meant to write, for instance, if using strcpy instead of strncpy. To debug this kind of issue, valgrind is very useful.

  • envp[0][-1]=1; will crash for accessing possibly uninitialised memory before the beginning of envp[0], as you need a little more work to get the last element in a C array, but it's nice psuedocode – cat Apr 27 '17 at 21:51
  • @cat, as long as you pass at least one argument (and commands are generally passed at least the argv[0]) and one environment variable, envp[0][-1] (the byte before the first env string) will be initialised. That will be the last byte of the last arg (the closing '\0') as on Linux the environ string are stored after the argv strings at the bottom of the stack. That's the whole point. Try that code for yourself if you want. – Stéphane Chazelas Apr 28 '17 at 06:12
2

There s no problem in it. When ps is not able to determine the full path of the command because args not available:

Sometimes the process args will be unavailable; when this happens, ps will instead print
the executable name in brackets. 

Extract from man

See also: https://unix.stackexchange.com/questions/78461/aix-why-does-ps-display-the-process-name-between-square-brackets/109173#109173

Kiwy
  • 9,534
  • But there is a problem! Each time the child process is in this weird state, it does not seem to work as supposed to! So for me there is a big problem... – Alex Jan 23 '14 at 14:41
  • If you're program make use of th process args then it seems normal it does not work correctly. but that would be more a development problem than a system issue in my opinion, I never had problem with the bracket – Kiwy Jan 23 '14 at 14:44
  • There are no process args! And the problem sometimes happens, sometimes it does not. Why? – Alex Jan 23 '14 at 14:53