0

I was programming with C language to get some information of the processes and tasks on Ubuntu(Ubuntu 20.04 and gcc 9.3.0).
I used the following code to scan the directory of the task of a process with a known pid:

char root_path[20] = "/proc/";
strcat(root_path, name_list[i]->d_name);
strcat(root_path, "/task");
tnum = scandir(root_path, &task_list, filter, alphasort);

where name_list[i]->d_name is the pid of the process in the form of char*. Then I used the result in task_list to visit the status of those tasks:

char path1[20] = "/proc/";
strcat(path1, task_list[j]->d_name);
strcat(path1, "/status");
FILE *fp = fopen(path1, "r");

It's just simple code. The problem I came cross is that although most of the tasks can be visited normally, there existed some task id that made fopen return a null pointer fp. I used assert statement to detect that. But when I use cat /proc/tid/status to check the file, it's there and could be normally accessed.
When I changed the directory into /proc/pid/task/tid/status, the problem still existed.
I want to know why I can't visit the certain task file, there seems no difference between it and other status files. The tid of the task that returns a null pointer is fixed until I compile the source code another time.

sweetieeee
  • 21
  • 3
  • 1
    If `fopen` returns NULL, use `perror` to print an error message stating *why* the call failed. – dbush Mar 15 '21 at 15:17
  • 1
    You can replace `strcat(); strcat();` with `snprintf();` – pmg Mar 15 '21 at 15:20
  • You probably need to check the `errno` value to find the error cause. You can do it by `if (fp == NULL) printf("Error: %s\n", strerror(errno));`. Make sure you `#include` the `` for `strerror` and `` for `errno` variable (it's actually a macro). – Ammar Faizi Mar 15 '21 at 15:27
  • 1
    "I used assert statement to detect that." Note that `assert` should be used for debugging, not for error detection. – Ian Abbott Mar 15 '21 at 16:21
  • @IanAbbott: It's sure better than "segmentation fault" when you don't know why or even where. – Joshua Mar 15 '21 at 17:07
  • @Joshua Yes, but it doesn't obviate the need to add proper error checking/handling. – Ian Abbott Mar 15 '21 at 17:28

1 Answers1

0

char path1[20] is too short. With these strings you need at least char path1[24] for the worst case sized PID. Your program is undefined due to running off the end of a stack array.

Once it's not undefined, if it keeps happening, call perror(path1) to print out the path you tried to access and the error message.

Hint: sizeof("string") can be used in the array declaration, so you could write char path1[sizeof("/proc/" + 10 + sizeof("/status")] and have the compiler do the counting for you.

Joshua
  • 40,822
  • 8
  • 72
  • 132
  • pids are at most 5 digits on linux, so the longest these names could be is 19 characters (including the terminating NUL). – Chris Dodd Mar 15 '21 at 17:15
  • @ChrisDodd: I wouldn't be too sure about that. https://stackoverflow.com/a/6294196/14768 shows you can set it to 7 digits today; thus 21 needed already. – Joshua Mar 15 '21 at 17:17