C strcpy的奇怪行为

时间:2014-04-24 11:08:05

标签: c xcode clang undefined-behavior buffer-overflow

我在C中编写了一个小程序。当我通过我的Makefileclang编译时,它编译得很完美并且有效。但是,在Xcode中,这个函数表现得不像它应该的那样(或者它表现得很好)喜欢它应该和clang忽略它。)

size_t getUrlForArgAndPlatform(char **dest, const char *arg, const char *platform) {
    int isLinux = strcmp(platform, "Linux");
    int isOSX = strcmp(platform, "Darwin");

    char *platformUrlDelimiter = malloc(6 + 1);
    if (isLinux == 0) {
        strcpy(platformUrlDelimiter, "linux");
    } else if (isOSX == 0) {
        strcpy(platformUrlDelimiter, "osx");
    } else {
        strcpy(platformUrlDelimiter, "common");
    }

    int length = (int) strlen(kBaseUrl);
    length += strlen(platformUrlDelimiter);
    length += strlen(arg);
    length += 5;

    char *buffer = (char *) malloc(length);
    if (buffer == NULL) {
        exit(EXIT_FAILURE);
    }
    strcpy(buffer, kBaseUrl);
    strcat(buffer, "/");
    strcat(buffer, platformUrlDelimiter);
    strcat(buffer, "/");
    strcat(buffer, arg);
    strcat(buffer, ".md");

    *dest = malloc(strlen(buffer) + 1);
    strcpy(*dest, buffer);

    free(platformUrlDelimiter);
    free(buffer);

    return strlen(buffer) + 1;
}

在10次中有效4次。在其他6次中,Xcode告诉我strcpy(*dest, buffer)的{​​{1}}失败了。如果我看一下调试器,我会看到SIGBRT包含两次相同的字符串。为什么呢?

2 个答案:

答案 0 :(得分:2)

您为buffer计算的尺寸不太正确:

int length = (int) strlen(kBaseUrl);
length += strlen(platformUrlDelimiter);
length += strlen(arg);
length += 5;

最后一部分应该是' + 6'因为"/"需要空格".md"NUL AND 需要空格{{1}}。

答案 1 :(得分:0)

(已经提到了不正确的长度。)

你的代码中有很多无意义的复制。由于您不修改platformUrlDelimiter,因此无需复制两次。这更简单:

const char *platformUrlDelimiter = "common";
if (isLinux == 0) {
    platformUrlDelimiter = "linux";
} else if (isOSX == 0) {
    platformUrlDelimiter = "osx";
}

然后移除对free (platformUrlDelimiter)的调用。

每次调用strcat()(可能)都必须不必要地遍历缓冲区。我会写:

int length = strlen(kBaseUrl)
           + strlen(platformUrlDelimiter)
           + strlen(arg)
           + 6;

*dest = malloc(length);
if (*dest) {
  sprintf (*dest, "%s/%s/%s.md", kBaseUrl, platformUrlDelimiter, arg);
} else {
  /* Error */
}

return length;

现在根本不需要使用buffer

此外,代码末尾还有真正的错误

free(buffer);

return strlen(buffer) + 1;

不得在释放后以任何方式使用buffer的值。