Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fix the tracee_info allocator: realloc() can't be used anymore here.

The problem was realloc() can't be use to anymore to allocate new
tracee_info because pointers to these structures can live across a
call to realloc().  For instance:

    1. parent_tracee = get_tracee_info(parent_pid, true)
    2. child_tracee = get_tracee_info(child_pid, true)  /!\ reallocation
    3. parent_tracee still points to the old memory area

Now, a chained pool allocation mechanism is used.

Change-Id: I7ca94baa29991651dd78a850df991da93b2268b3
  • Loading branch information...
commit 75cc16435e2d6ef12348864e2ebf09d91a2057cf 1 parent 305ae31
@cedric-vincent cedric-vincent authored
Showing with 91 additions and 108 deletions.
  1. +0 −1  src/cli.c
  2. +7 −6 src/trace.c
  3. +84 −99 src/tracee/info.c
  4. +0 −2  src/tracee/info.h
View
1  src/cli.c
@@ -421,7 +421,6 @@ int main(int argc, char *argv[])
/* TODO: remove the need for initialization. */
init_module_path();
- init_module_tracee_info();
init_module_ldso();
if (config.verbose_level)
View
13 src/trace.c
@@ -149,7 +149,8 @@ bool launch_process()
return false;
default: /* parent */
- tracee = new_tracee(pid);
+ /* Allocate its tracee_info structure. */
+ tracee = get_tracee_info(pid, true);
if (tracee == NULL)
return false;
@@ -177,7 +178,8 @@ bool attach_process(pid_t pid)
* until they are closed. */
list_open_fd(pid);
- tracee = new_tracee(pid);
+ /* Allocate its tracee_info structure. */
+ tracee = get_tracee_info(pid, true);
if (tracee == NULL)
return false;
@@ -298,8 +300,7 @@ int event_loop()
continue; /* Skip the call to ptrace(SYSCALL). */
}
else if (WIFSIGNALED(tracee_status)) {
- VERBOSE(get_nb_tracees() != 1,
- "pid %d: terminated with signal %d",
+ VERBOSE(1, "pid %d: terminated with signal %d",
pid, WTERMSIG(tracee_status));
delete_tracee(tracee);
continue; /* Skip the call to ptrace(SYSCALL). */
@@ -376,7 +377,7 @@ int event_loop()
tracee->sigstop = SIGSTOP_ALLOWED;
status = ptrace(PTRACE_SYSCALL, child_pid, NULL, 0);
if (status < 0) {
- notice(WARNING, SYSTEM, "ptrace(SYSCALL, %d)", child_pid);
+ notice(WARNING, SYSTEM, "ptrace(SYSCALL, %d) [1]", child_pid);
delete_tracee(tracee);
}
}
@@ -418,7 +419,7 @@ int event_loop()
status = ptrace(PTRACE_SYSCALL, tracee->pid, NULL, signal);
if (status < 0) {
/* The process died in a syscall. */
- notice(WARNING, SYSTEM, "ptrace(SYSCALL, %d)", tracee->pid);
+ notice(WARNING, SYSTEM, "ptrace(SYSCALL, %d) [2]", tracee->pid);
delete_tracee(tracee);
}
}
View
183 src/tracee/info.c
@@ -20,35 +20,36 @@
* 02110-1301 USA.
*/
-#include <sys/ptrace.h> /* ptrace(2), PTRACE_*, */
#include <sys/types.h> /* pid_t, size_t, */
-#include <stdlib.h> /* NULL, exit(3), */
-#include <stddef.h> /* offsetof(), */
-#include <sys/user.h> /* struct user*, */
-#include <limits.h> /* ULONG_MAX, */
+#include <stdlib.h> /* NULL, */
#include <assert.h> /* assert(3), */
-#include <sys/wait.h> /* waitpid(2), */
#include <string.h> /* bzero(3), */
#include <stdbool.h> /* bool, true, false, */
#include "tracee/info.h"
-#include "arch.h" /* REG_SYSARG_*, word_t */
-#include "syscall/syscall.h" /* USER_REGS_OFFSET, */
#include "notice.h"
-static struct tracee_info *tracee_infos;
-static size_t max_tracees = 0;
-static size_t nb_tracees = 0;
+ /* Don't use too many entries since XXX all XXX when searching for a
+ * new tracee. */
+#define POOL_MAX_ENTRIES 16
+
+struct pool {
+ struct tracee_info entries[POOL_MAX_ENTRIES];
+ size_t nb_entries;
+ struct pool *next;
+};
+
+static struct pool *first_pool = NULL;
/**
- * Reset the default values for the structure @tracee.
+ * Reset the default values for the given @tracee.
*/
-static void reset_tracee(struct tracee_info *tracee, bool free_fields)
+void delete_tracee(struct tracee_info *tracee)
{
- if (free_fields && tracee->trigger != NULL)
+ if (tracee->trigger != NULL)
free(tracee->trigger);
- if (free_fields && tracee->exe != NULL)
+ if (tracee->exe != NULL)
free(tracee->exe);
bzero(tracee, sizeof(struct tracee_info));
@@ -57,122 +58,106 @@ static void reset_tracee(struct tracee_info *tracee, bool free_fields)
}
/**
- * Allocate @nb_elements empty entries in the table tracee_infos[].
+ * Allocate a new pool and initialize an entry for the tracee @pid.
*/
-void init_module_tracee_info()
+static struct tracee_info *new_tracee(pid_t pid)
{
+ struct pool *last_pool;
+ struct pool *new_pool;
size_t i;
- const int nb_elements = 64;
- tracee_infos = calloc(nb_elements, sizeof(struct tracee_info));
- if (tracee_infos == NULL)
- notice(ERROR, SYSTEM, "calloc()");
+ /* Search for the last pool. */
+ for (last_pool = first_pool; last_pool != NULL; last_pool = last_pool->next)
+ if (last_pool->next == NULL)
+ break;
+
+ new_pool = calloc(1, sizeof(struct pool));
+ if (new_pool == NULL) {
+ notice(WARNING, SYSTEM, "calloc()");
+ return NULL;
+ }
+
+ if (last_pool != NULL)
+ last_pool->next = new_pool;
+ else {
+ assert(first_pool == NULL);
+ first_pool = new_pool;
+ }
- /* Set the default values for each entry. */
- for(i = 0; i < nb_elements; i++)
- reset_tracee(&tracee_infos[i], false);
+ /* Set the default values for each new entry. */
+ for(i = 0; i < POOL_MAX_ENTRIES; i++)
+ delete_tracee(&new_pool->entries[i]);
- max_tracees = nb_elements;
+ new_pool->entries[0].pid = pid;
+ return &new_pool->entries[0];
}
/**
- * Initialize a new entry in the table tracee_infos[] for the tracee @pid.
+ * Return the entry related to the tracee @pid. If no entry were
+ * found, a new one is created if @create is true, otherwise NULL is
+ * returned.
*/
-struct tracee_info *new_tracee(pid_t pid)
+struct tracee_info *get_tracee_info(pid_t pid, bool create)
{
+ struct tracee_info *tracee;
+ struct pool *pool;
size_t i;
- size_t first_slot;
- struct tracee_info *new_tracee_infos;
- assert(nb_tracees <= max_tracees);
+ /* Remember what the first free slot is in the first free
+ * pool, if we have to @create a new entry. */
+ struct pool *free_pool = NULL;
+ size_t free_slot = 0;
- /* Check if there is still an empty entry in tracee_info[]. */
- if (nb_tracees == max_tracees) {
- new_tracee_infos = realloc(tracee_infos, 2 * max_tracees * sizeof(struct tracee_info));
- if (new_tracee_infos == NULL) {
- notice(WARNING, SYSTEM, "realloc()");
- return NULL;
- }
+ for (pool = first_pool; pool != NULL; pool = pool->next) {
+ for(i = 0; i < POOL_MAX_ENTRIES; i++) {
+ if (pool->entries[i].pid == pid)
+ return &pool->entries[i];
- /* Set the default values for each new entry. */
- for(i = max_tracees; i < 2 * max_tracees; i++)
- reset_tracee(&new_tracee_infos[i], false);
+ if (!create
+ || free_pool != NULL
+ || pool->entries[i].pid != 0)
+ continue;
- first_slot = max_tracees; /* Skip non-empty slot. */
- max_tracees = 2 * max_tracees;
- tracee_infos = new_tracee_infos;
- }
- else
- first_slot = 0;
-
- /* Search for a free slot. */
- for(i = first_slot; i < max_tracees; i++) {
- if (tracee_infos[i].pid == 0) {
- tracee_infos[i].pid = pid;
- nb_tracees++;
- return &tracee_infos[i];
+ free_pool = pool;
+ free_slot = i;
}
}
- /* Should never happen. */
- assert(0);
- return NULL;
-}
-
-/**
- * Reset the entry in tracee_infos[] related to the tracee @pid.
- */
-void delete_tracee(struct tracee_info *tracee)
-{
- nb_tracees--;
- reset_tracee(tracee, true);
-}
-
-/**
- * Give the number of tracee alive at this time.
- */
-size_t get_nb_tracees()
-{
- return nb_tracees;
-}
-
-/**
- * Search in the table tracee_infos[] for the entry related to the
- * tracee @pid.
- */
-struct tracee_info *get_tracee_info(pid_t pid, bool create)
-{
- size_t i;
-
- /* Search for the entry related to this tracee process. */
- for(i = 0; i < max_tracees; i++)
- if (tracee_infos[i].pid == pid)
- return &tracee_infos[i];
-
if (!create)
return NULL;
- /* Create the tracee_infos[] entry dynamically. */
- return new_tracee(pid);
+ if (free_pool != NULL) {
+ tracee = &free_pool->entries[free_slot];
+ tracee->pid = pid;
+ return tracee;
+ }
+ else {
+ tracee = new_tracee(pid);
+ assert(tracee != NULL);
+ return tracee;
+ }
}
/**
- * Call @callback on each living tracee process. It returns the status
- * of the first failure, that is, if @callback returned seomthing
+ * Call @callback on each tracees. This function returns the status
+ * of the first failure, that is, if @callback returned something
* lesser than 0, otherwise 0.
*/
int foreach_tracee(foreach_tracee_t callback)
{
+ struct pool *pool;
int status;
- int i;
+ size_t i;
- for(i = 0; i < max_tracees; i++) {
- if (tracee_infos[i].pid == 0)
- continue;
+ for (pool = first_pool; pool != NULL; pool = pool->next) {
+ for(i = 0; i < POOL_MAX_ENTRIES; i++) {
+ if (pool->entries[i].pid == 0)
+ continue;
- status = callback(tracee_infos[i].pid);
- if (status < 0)
- return status;
+ status = callback(pool->entries[i].pid);
+ if (status < 0)
+ return status;
+ }
}
return 0;
View
2  src/tracee/info.h
@@ -47,9 +47,7 @@ struct tracee_info {
typedef int (*foreach_tracee_t)(pid_t pid);
extern void init_module_tracee_info(void);
-extern struct tracee_info *new_tracee(pid_t pid);
extern void delete_tracee(struct tracee_info *tracee);
-extern size_t get_nb_tracees(void);
extern struct tracee_info *get_tracee_info(pid_t pid, bool create);
extern int foreach_tracee(foreach_tracee_t callback);
extern void inherit_fs_info(struct tracee_info *child, struct tracee_info *parent);
Please sign in to comment.
Something went wrong with that request. Please try again.