函数中的堆与函数参数重叠

Heap in function overlaps function parameter

我编写了一个程序,将输出目录名 (argv[1]) 与文件名 (char *output_files_basename[]) 合并:

algo.c:

#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/errno.h>
#include <sys/stat.h>
#include <sys/types.h>

#include "algo.h"
#include "parameters.h"

char *output_files_basename[] = {
    "test1",
    "test2",
    "test3",
    "test4",
    NULL
};

extern int errno;

int main(int argc, char *argv[]) {
    char output_dir[MAX_PATH_LENGTH] = "";
    char *output_files_fullpath[] = { NULL };
    int ret = 0;

    /* check parameters */
    if (argc < 2) {
        printf("Not enough parameters\n");
        printf("Should be:\n");
        printf("%s output_dir\n", argv[0]);
        return EINVAL;
    }

#if DEBUG > 0
    printf("Arguments: \n");
    printf("output_dir: %s\n", argv[1]);
#endif

    strncpy(output_dir, argv[1], MAX_PATH_LENGTH - 1);
    output_dir[MAX_PATH_LENGTH - 1] = '[=10=]';

#if DEBUG > 0
    printf("output_dir: %s\n", output_dir);
#endif

    /* set full input file names */
    form_fullpath(output_files_fullpath, output_files_basename, output_dir);

    free_fullpath(output_files_fullpath);

    return EXIT_SUCCESS;
}

algo.h:

#ifndef ALGO_H
#define ALGO_H

#define DEBUG           1

#define MAX_PATH_LENGTH 256

#endif /* ALGO_H */

parameters.h:

#ifndef PARAMETERS_H
#define PARAMETERS_H

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include "algo.h"

/* get input_dir and append to input_files_basename => input_files_fullpath */
void form_fullpath(char *input_files_fullpath[], char *input_files_basename[], char *input_dir);

/* free memory */
void free_fullpath(char *input_files_fullpath[]);

#endif /* PARAMETERS_H */

parameters.c:

#include "parameters.h"

extern int errno;

void form_fullpath(char *input_files_fullpath[], char *input_files_basename[], char *input_dir) {

    int file_iter = 0;
    char *strtmp = NULL;

    for (file_iter = 0; input_files_basename[file_iter] != NULL && input_dir != NULL; file_iter++) {
        //#ifdef TTT
        input_files_fullpath[file_iter] = malloc(sizeof(char) *
                          (strlen(input_files_basename[file_iter]) +
                           strlen(input_dir) + 2) /* '/' and '[=13=]' */);
        //#endif
        /*sprintf(input_files_fullpath[file_iter], "%s/%s%c",
                  input_dir,
                  input_files_basename[file_iter],
                  '[=13=]');*/

#if DEBUG > 0
        //printf("file_fullpath[%d]: %s\n", file_iter, input_files_fullpath[file_iter]);
        printf("input_files_basename[%d]: %s\n", file_iter, input_files_basename[file_iter]);
        printf("%d input_dir: %s\n", file_iter, input_dir);
#endif
    }
    input_files_fullpath[file_iter] = NULL;
}

void free_fullpath(char *input_files_fullpath[]) {
    int file_iter = 0;

    for (file_iter = 0; input_files_fullpath[file_iter] != NULL; file_iter++) {
        free(input_files_fullpath[file_iter]);
    }
}

当我在 form_fullpath 函数中评论 malloc 时,我得到以下输出:

./algo output/
Arguments:
output_dir: output/
output_dir: output/
input_files_basename[0]: test1
0 input_dir: output/
input_files_basename[1]: test2
1 input_dir: output/
input_files_basename[2]: test3
2 input_dir: output/
input_files_basename[3]: test4
3 input_dir: output/

但是当我在 form_fullpath 函数中取消注释 malloc 时,我的输出是这样的:

./algo output/
Arguments:
output_dir: output/
output_dir: output/
input_files_basename[0]: test1
0 input_dir: output/
input_files_basename[1]: test2
1 input_dir: P
input_files_basename[2]: test3
2 input_dir: P
input_files_basename[3]: test4
3 input_dir: P

为什么 mallocinput_dir 函数参数重叠?如果有人能解释我,我将不胜感激。

Why malloc overlaps input_dir function parameter?

Because your code is invalid. The array:

char *output_files_fullpath[] = {NULL};

has only one element, yet you write out-of-bounds to it in form_fullpath, in pseudocode:

int main() {
     char *output_files_fullpath[] = {NULL};
     form_fullpath(output_files_fullpath, ...)
}
void form_fullpath(char *input_files_fullpath[],  ...) {
   for (file_iter in 0 1 2 3) {
      input_files_fullpath[file_iter] = something
   }
}

input_files_fullpath has only 1 element, not 5. You can:

  • Allocate more elements char *output_files_fullpath[20];
  • use dynamic allocation to dynamically re-allocate output_files_fullpath each loop, for example.

Notes:

  • Instead of malloc+snprintf you could use asprintf.`
  • Doing sprintf(..., "%c", '[=18=]') is pointless, results in writing two zeros on the end of string and I think this is also a bug as it results in writing to the memory out-of-bounds by byte. Remove that '[=19=]'. sprintf always writes zero terminating character by itself anyway.
  • Prefer to use snprintf.
  • I guess, consider using shorter variable names? It's kind of strange that output_files_fullpath becomes input_files_fullpath in function, it's still output.
  • Consider using size_t for array iterators.