/* Initializer of each process */ void __attribute__((constructor)) init_malloc_wrapper() { const char* malloc_detective_free = getenv(MALLOC_DETECTIVE_FREE); is_out_free_bt = (malloc_detective_free && atoi(malloc_detective_free) == 1); /* INNER_FLAG_UP: Logging file descriptor for child-processes. */ const char* inner_flag_logfd = getenv(INNER_FLAG_LOGFD); char* output_name = NULL; /* MALLOC_DETECTIVE_CHILD: Reuse flag of log stream by children. */ const char* malloc_detective_child = getenv(MALLOC_DETECTIVE_CHILD); const int is_reuse = (malloc_detective_child && atoi(malloc_detective_child) == 1); /* Get file discriptor for output log */ malloc_wapper_logfd = STDERR_FILENO; if (inner_flag_logfd) { /* Reuse the file descriptor that parent has generated. * (or -1. Output suppressed by parents) */ malloc_wapper_logfd = atoi(inner_flag_logfd); } else if ((output_name = getenv(MALLOC_DETECTIVE_OUTPUT)) != NULL) { /* Deciding output stream, stderr or fifo. * Using fifo if defined env-value MALLOC_DETECTIVE_OUTPUT. */ struct stat filestat; if (stat(output_name, &filestat) == -1) { /* Creating fifo, if not exists */ if (mkfifo(output_name, 0600) == -1) { const char* errstr = strerror(errno); fprintf(stderr, "Error: Can't create fifo(%s). mkfifo:%s\n", output_name, errstr); _exit(2); } } else if (!S_ISFIFO(filestat.st_mode)) { fprintf(stderr, "Error: %s is not fifo.\n", output_name); _exit(3); } const mode_t openflag = O_WRONLY || (is_reuse ? 0 : O_CLOEXEC); malloc_wapper_logfd = open(output_name, openflag); if (malloc_wapper_logfd < 0) { const char* errstr = strerror(errno); fprintf(stderr, "Error: Can't open fifo(%s). open:%s\n", output_name, errstr); _exit(1); } /* Save output stream if defined MALLOC_DETECTIVE_CHILD environment as 1. * Otherwise save -1 to suppress output by children. */ if (is_reuse) { char str_logfd[32] = {0}; sprintf(str_logfd, "%d", malloc_wapper_logfd); setenv(INNER_FLAG_LOGFD, str_logfd, 1); } else { setenv(INNER_FLAG_LOGFD, "-1", 1); } } /* load libc's malloc/free */ load_malloc(); load_free(); load_libc_malloc(); load_libc_free(); }
void free(void* p) { if (!origin_free) { load_free(); } origin_free(p); if (depth > 0|| malloc_wapper_logfd == -1) { return; } ++depth; log_output(is_out_free_bt, &loghead_build_free, p, 0); --depth; }
/** * @brief Loads or refreshes saved games. */ int load_refresh (void) { char **files, buf[PATH_MAX], *tmp; int nfiles, i, len; int ok; nsave_t *ns; if (load_saves != NULL) load_free(); load_saves = array_create( nsave_t ); /* load the saves */ files = nfile_readDir( &nfiles, "%ssaves", nfile_dataPath() ); for (i=0; i<nfiles; i++) { len = strlen(files[i]); /* no save or backup save extension */ if (((len < 5) || strcmp(&files[i][len-3],".ns")) && ((len < 12) || strcmp(&files[i][len-10],".ns.backup"))) { free(files[i]); memmove( &files[i], &files[i+1], sizeof(char*) * (nfiles-i-1) ); nfiles--; i--; } } /* Make sure files are none. */ if (files == NULL) return 0; /* Make sure backups are after saves. */ for (i=0; i<nfiles-1; i++) { len = strlen( files[i] ); /* Only interested in swapping backup with file after it if it's not backup. */ if ((len < 12) || strcmp( &files[i][len-10],".ns.backup" )) continue; /* Don't match. */ if (strncmp( files[i], files[i+1], (len-10) )) continue; /* Swap around. */ tmp = files[i]; files[i] = files[i+1]; files[i+1] = tmp; } /* Allocate and parse. */ ok = 0; ns = NULL; for (i=0; i<nfiles; i++) { if (!ok) ns = &array_grow( &load_saves ); nsnprintf( buf, sizeof(buf), "%ssaves/%s", nfile_dataPath(), files[i] ); ok = load_load( ns, buf ); } /* If the save was invalid, array is 1 member too large. */ if (ok) array_resize( &load_saves, array_size(load_saves)-1 ); /* Clean up memory. */ for (i=0; i<nfiles; i++) free(files[i]); free(files); return 0; }