Welcome to the Linux Foundation Forum!

There seems to be memory leak when reading /proc/pid/mem from another process

I tried to read memory content of process from another process. However, VmRss of the target process was rapidly increased while reading its memory. Why this is happening?

Please check the following test code I used. This program fork child process and read its memory. the child process do nothing, but VmRss of the child process will be increased while the parent process reading child process's memory.

The test code is the following.

  1. #include <cstdlib>
  2. #include <cstdio>
  3. #include <unistd.h>
  4. #include <sys/types.h>
  5. #include <sys/ptrace.h>
  6. #include <sys/wait.h>
  7. #include <err.h>
  8. #include <cerrno>
  9. #include <cstring>
  10. #include <fcntl.h>
  11.  
  12. #include <vector>
  13. #include <utility>
  14.  
  15. const int RD_SIZE = 1 * 1024 * 1024;
  16.  
  17. void read_stat(char *path) {
  18. int fd = open(path, O_RDONLY);
  19. char *buf = (char*)malloc(sizeof(char) * 128);
  20. size_t statm_len = read(fd, buf, 128);
  21. int err = errno;
  22. if (statm_len == -1) {
  23. printf("failed to read statm at %d: %s\n", err, strerror(err));
  24. exit(EXIT_FAILURE);
  25. } else {
  26. printf("%s\n", buf);
  27. }
  28. free(buf);
  29. close(fd);
  30. }
  31.  
  32. // 41e53000-41e58000 rw-p 00000000 00:00 0 xxxxxx
  33. std::vector<std::pair<unsigned long, unsigned long> > read_maps(char *path) {
  34. FILE *f = fopen(path, "r");
  35. char *buf = (char*)malloc(sizeof(char) * 16);
  36. int len = 0;
  37. int read_phase = 0;
  38. unsigned long from;
  39. unsigned long to;
  40. std::vector<std::pair<unsigned long, unsigned long> > res;
  41. while (true) {
  42. int v = fgetc(f);
  43. if (v == EOF) break;
  44.  
  45. if (read_phase == 0) {
  46. if (v == '-') {
  47. from = strtol(buf, NULL, 16);
  48. len = 0;
  49. buf[0] = '\0';
  50. read_phase = 1;
  51. } else {
  52. buf[len++] = v;
  53. buf[len] = '\0';
  54. }
  55. } else if (read_phase == 1) {
  56. if (v == ' ') {
  57. to = strtol(buf, NULL, 16);
  58. len = 0;
  59. buf[0] = '\0';
  60. read_phase = 2;
  61. } else {
  62. buf[len++] = v;
  63. buf[len] = '\0';
  64. }
  65. } else if (read_phase == 2) {
  66. if (v == 'r') {
  67. unsigned long cur_pos = from;
  68. while (cur_pos < to) {
  69. unsigned long next_pos = cur_pos + RD_SIZE;
  70. if (next_pos > to) next_pos = to;
  71. unsigned long length = next_pos - cur_pos;
  72. res.push_back(std::make_pair(cur_pos, length));
  73. cur_pos = next_pos;
  74. }
  75. } else if (v == '-') {
  76. // nothing to do
  77. } else {
  78. printf("something wrong in parse\n");
  79. exit(EXIT_FAILURE);
  80. }
  81. read_phase = 3;
  82. } else {
  83. if (v == '\n') {
  84. read_phase = 0;
  85. }
  86. }
  87. }
  88. free(buf);
  89. fclose(f);
  90. return res;
  91. }
  92.  
  93. int main(int argc, char *argv[]) {
  94. pid_t pid;
  95.  
  96. pid = fork();
  97.  
  98. if (pid == -1) {
  99. err(EXIT_FAILURE, "failed to fork");
  100. } else if (pid == 0) {
  101. // child process
  102. while (true) {
  103. sleep(10);
  104. }
  105. exit(EXIT_SUCCESS);
  106. } else {
  107. sleep(3);
  108. // parent
  109. printf("parent: child pid is %d\n", pid);
  110.  
  111. // attach to the process
  112. int ptrace_res = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
  113. if (ptrace_res < 0) {
  114. perror("failed to attach to the child process");
  115. exit(EXIT_FAILURE);
  116. }
  117. sleep(1);
  118.  
  119. char *buf = NULL;
  120. char *path = (char*)malloc(sizeof(char) * 128);
  121.  
  122. // read from /proc/pid/statm
  123. sprintf(path, "/proc/%d/statm", pid);
  124. read_stat(path);
  125.  
  126. // read from /proc/pid/maps
  127. sprintf(path, "/proc/%d/maps", pid);
  128. auto target_list = read_maps(path);
  129.  
  130. // read from /proc/pid/mem
  131. sprintf(path, "/proc/%d/mem", pid);
  132. int fd = open(path, O_RDONLY);
  133. buf = (char*)malloc(sizeof(char) * RD_SIZE);
  134.  
  135. for (auto it : target_list) {
  136. unsigned long from, length;
  137. from = it.first;
  138. length = it.second;
  139. // printf("read from %lx, length: %lu\n", from, length);
  140. lseek64(fd, from, SEEK_SET);
  141. size_t ret = read(fd, buf, RD_SIZE);
  142. int err = errno;
  143. // skip I/O error
  144. if (ret == -1 && err != 5) {
  145. printf("failed to read at %d: %s\n", err, strerror(err));
  146. break;
  147. }
  148. }
  149.  
  150. ptrace(PTRACE_DETACH, pid, NULL, NULL);
  151.  
  152. close(fd);
  153.  
  154. // read from /proc/pid/statm
  155. sprintf(path, "/proc/%d/statm", pid);
  156. read_stat(path);
  157. }
  158.  
  159. exit(EXIT_SUCCESS);
  160. }

Welcome!

It looks like you're new here. Sign in or register to get started.
Sign In

Welcome!

It looks like you're new here. Sign in or register to get started.
Sign In

Categories

Upcoming Training