简体   繁体   English

如何使用 scanf 避免缓冲区溢出

[英]How to avoid buffer overflow using scanf

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    char first_name[20];
    char last_name[20];
    int student_num;
    char debts[1];

    printf("Enter name:");
    scanf("%s", first_name);
    printf("Enter lastname:");
    scanf("%s", last_name);
    printf("Enter six bits length student ID:");
    scanf("%d", &student_num);
    printf("Do you have debts for university [Y/N]?");
    scanf("%s", debts);

    printf("\nYour name is %s %s.\n", first_name, last_name);
    printf("Your Student ID is %d.\n", student_num);
    printf("Debts: %s.\n", debts);
    return (EXIT_SUCCESS);
}

How to avoid buffer overflow in this code?如何避免此代码中的缓冲区溢出? I want my code to produce such an output:我希望我的代码产生这样的输出:

Enter name:Enescekilokoneyasharrontannamyantoniaaquin
Enter lastname:Basenau
Enter six bits length student ID:456789
Do you have debts for university [Y/N]?YES

Your name is **Enescekilokoneyashar** (only 20 bits from name input) *Basenau*.
Your Student ID is **393299**.
Debts: **Y**.

Process returned -1073741819 (0xC0000005)   execution time : 36.336 s
Press any key to continue.

I have tried to use:我曾尝试使用:

scanf("%19s", first_name);

But it does not work as I expect.但它不像我期望的那样工作。 I need to find some another way to validate input parameters to prevent buffer overflow attack and limit input to buffers size.我需要找到另一种方法来验证输入参数以防止缓冲区溢出攻击并将输入限制为缓冲区大小。

You can maintain the use of scanf but you need to limit the size of what it can take to the size of the destination buffer, something like:您可以保留scanf的使用,但您需要将其可以占用的大小限制为目标缓冲区的大小,例如:

scanf(" %19[^\n]", first_name); //last destination buffer element is for null byte

Note that this specifier can parse spaces so you can take an input with more than one word.请注意,此说明符可以解析空格,因此您可以输入包含多个单词的输入。

It will, however, leave a \\n character in the stdin buffer, or the remaining characters that were not parsed in case you input a larger string, so you need to clear it every time you want to parse a new input, you can make a handy function that you can call when you need such clearence, making it a pattern:但是,它会在stdin缓冲区中留下一个\\n字符,或者在输入较大字符串时未解析的剩余字符,因此每次要解析新输入时都需要清除它,您可以使一个方便的函数,您可以在需要这种清除时调用它,使其成为一种模式:

void clear_buffer(){
    int c;
    while ((c = getchar()) != '\n' && c != EOF){
        continue;
    }
}

Your char debts[1] buffer is also problematic, it's too small to store a string, it needs to have at least 2 characters to be able to store the null terminator:您的char debts[1]缓冲区也有问题,它太小而无法存储字符串,它需要至少有 2 个字符才能存储空终止符:

char debts[2];

And the call will be:电话将是:

clear_buffer();
scanf(" %1[^\n]", debts);

Lastly you should verify the return of scanf , for instance, in scanf("%d", &student_num) , if you input alphabetical characters instead of digits, the function will fail to parse and return 0, you can also make it parse at most 6 digits, something along the lines of:最后你应该验证scanf的返回,例如,在scanf("%d", &student_num) ,如果你输入字母字符而不是数字,函数将无法解析并返回 0,您也可以使其最多解析6 位数字,类似于:

clear_buffer();
if(scanf("%6d", &student_num) == 0){ // %6d limit the input to 6 digits
    //handle error
}

Live demo现场演示

If you are on windows you can use scanf_s() as described in the Microsoft documentation here .如果你是在Windows中可以使用的微软文档中描述scanf_s() 在这里 There is also an example given:还给出了一个例子:

char s[10];
scanf_s("%9s", s, (unsigned)_countof(s));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM