【问题标题】:Check if input string exceeds buffer limit (crash)检查输入字符串是否超过缓冲区限制(崩溃)
【发布时间】:2017-04-28 15:21:15
【问题描述】:

我正在创建一个函数,它将目录路径作为参数传递,或者如果它留空,则提示用户输入。

我已设置我的PATH_MAX=100if 语句来检查if ((strlen(folder path) + strlen(file path)) > PATH_MAX) 会要求用户再次输入。

但是,当我检查所有条件是否有效(设置PATH_MAX=20)时,如果folder path 本身超过PATH_MAX,缓冲区会由于大小不足而崩溃(L'Buffer is too small' &&0)。

有没有办法预先检查用户是否超过PATH_MAX并告知路径太长,以避免崩溃缓冲区?还是我应该只增加PATH_MAX 的大小?

代码:

#define PATH_MAX 100
void CreateFiles(char folder[PATH_MAX])
{
    char addrbook[PATH_MAX] = "caf-sorted.txt";
    char path[PATH_MAX]="";

    if ((strlen(folder)<4)) 
    {
        //User inputs directory
        printf("Enter New Directory\n(!Do not enter filename!)\n");

        if (NULL == fgets(path, sizeof path, stdin))
        {//check if fgets fails
            if (ferror(stdin))
            {
                folder="";
                perror("fgets() failed");
                CreateFiles(folder);
                return;
            }
        }
    }
    else
        memcpy(path, folder, strlen(folder));

    path[strcspn(path, "\n\r")] = 0;

    if (strlen(addrbook) > 0 && '\\' != path[strlen(path) - 1])
    {
        if (PATH_MAX < strlen(path))
        {
            errno = EINVAL;
            perror("'path' too long");
            folder="";
            CreateFiles(folder);
            return;
        }

        strcat(path, "\\");
    }

    if (PATH_MAX < (strlen(path) + strlen(addrbook)))
    {
        errno = EINVAL;
        perror("'path\\filename' too long");
        folder="";
        CreateFiles(folder);
        return;
    }
}

【问题讨论】:

  • 你应该在你得到它的地方检查它。
  • 即使使用CreateFiles(char folder[PATH_MAX])folder 也可以指向比MAX_PATH 更长的字符串——这可能会失败memcpy(path, folder, strlen(folder));
  • folder 在传入 CreateFiles, if (folder&gt;PATH_MAX){folder="";} 之前正在检查主目录
  • path[strlen(path) - 1] 是一个可利用的 hack,因为 strlen(path) 不能保证大于 0。
  • if (folder&gt;PATH_MAX) 将指针与整数进行比较 - 也许您的意思是其他一些测试? IAC,最好 CreateFiles() 独立存在,如果传入长字符串的指针也不会失败。

标签: c string memory buffer


【解决方案1】:

您必须考虑终止空字符

if (!(strlen(path) < PATH_MAX))

确保路径中的字符数(不包括空字符)始终至少比 PATH_MAX 少 1,从而为终止空字符留出空间。

你必须在你使用的每个 C 字符串中考虑到这一点,因为如果你希望能够以空值终止它,strlen(char *string) 总是比存储字符串所需的空间小一。

编辑:所以我至少研究了你的函数的前几行,并试图快速重新实现它们。它不漂亮,但它有效:

#include <stdio.h>
#include <string.h>
#include <strings.h>

#define PATH_MAX 100

void create_files (char *folder)
{
    char addr_book[] = "caf-sorted.txt";
    char path[PATH_MAX];


    // Setting all bytes in *path to zero
    bzero(path, PATH_MAX);



    // If the folder name is too short, we ask for a new one
    if (strlen(folder) < 4) {

        char c; // This will store our input from stdin, one char at a time



        // As long as the supplied path name is too short, we'll keep asking:

        while (strlen(path) < 4) {
            printf("Please enter a path (no filename!): ");


            // We get one character at a time from stdin using getc(...):
            // until we encounter a newline

            for (int i = 0; (c = getc(stdin)) != '\n'; i++) {

                if (i < PATH_MAX - 1) {

                    // As long as we have space for two more characters
                    // (the value of c plus a null character after it)
                    // We'll keep appending c:

                    path[i] = c;

                } else if (i == PATH_MAX - 1) {

                    // If we get too many characters from stdin, we
                    // display an error message and reset our path to
                    // all null characters again, so the outermost loop
                    // will run again

                    fprintf(stderr, "Path is too long!\n");
                    bzero(path, PATH_MAX);

                    // Notice that we do not have a break statement
                    // here, we iterate through the input string from
                    // stdin until we encounter a newline character,
                    // so we don't have any superfluous characters
                    // that spill into the beginning ouf our freshly
                    // reset path string
                }
            }
        }
    } else {
        // Or, you know, if the programmer specifies a proper value,
        // Just do it the easy way and copy that into our path string
        // (although this will truncate a folder name that is too long):

        strncpy(path, folder, PATH_MAX - 1);
    }
}

int main ()
{
    create_files("");

    return 0;
}

【讨论】:

  • 问题是缓冲区在 fgets 命令中崩溃。如果它通过了那个阶段,我的if 语句就会捕获它。所以基本上我必须想办法让 fgets 不超过限制
  • fgets(path, PATH_MAX, stdin); 原理相同。您可能希望首先将路径中的所有字节设置为零,如下所示:bzero(path, PATH_MAX) 为此,您需要 #include &lt;strings.h&gt;
  • 所以最好的方法是限制fgets 接受99 个字符?我是新的,但想象会有更好的方法。 string.h 已包含在内。写不完每一行,太多了:)
  • 这可能会造成混淆,因为有 (单数)和 (复数)。无论如何,这就是它在我的系统上的样子。我刚刚查看了 fgets(...) 手册页,它似乎已经读取了 size - 1 个字节。我会深入研究代码,看看我能找到什么。
  • @afdggfh "您可能希望首先将路径中的所有字节设置为零" --> OP 的代码已经准备好使用 char path[PATH_MAX]="";
猜你喜欢
  • 1970-01-01
  • 2015-12-29
  • 2014-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-16
  • 1970-01-01
相关资源
最近更新 更多