2
#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.

2
  • scanf() is a horrible function to parse input, as you're finding out. When it fails to convert input, it leaves your input stream in an unknown state, which is really bad if it's a stream like stdin where you can't go back. Even more perverse, if you write a set of fields using a format string with [f]printf(), that same format string isn't guaranteed to be able to read that same data when used by scanf(). It's usually much better to read an entire line via fgets() (or getline() if available) and parse the string yourself. You can even use sscanf() to replicate scanf(). Commented Oct 15, 2020 at 11:58
  • (cont) That also handles newlines much better than scanf()'s "Did I leave the newline in the buffer or not?!?" uncertainty when scanf() is mixed with other input-reading functions. Commented Oct 15, 2020 at 11:59

2 Answers 2

4

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(" %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:

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[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:

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

Live demo

Sign up to request clarification or add additional context in comments.

Comments

3

If you are on windows you can use scanf_s() as described in the Microsoft documentation here. There is also an example given:

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

4 Comments

How is scanf_s("%9s", s, (unsigned)_countof(s)); any different from scanf("%9s", s);? If it's because you think scanf() is deprecated, Microsoft is lying to you. scanf() is a function any C implementation must provide - it's not "deprecated" at all.
Well he wrote that scanf("%9s", s) "did not work as expected" (whatever that means). I never tried scanf() because (as you said, Microsoft thinks) it's deprecated (If Microsoft is lying to me that wouldn't be the first time, i honestly didn't know). That was the reason why i suggested scanf_s because it always worked perfectly fine for me.
@AndrewHenle, yes, the infamous Microsoft trickery.
@Michael Read this about Microsoft's implementation of Annex K of the C standard: Field Experience With Annex K — Bounds Checking Interfaces Note that Annex K is optional to begin with. Also, Microsoft botched the implementation in ways that make fixes impossible without breaking existing code. I'm pretty sure this dates back to the days of Microsoft's "embrace, extend, extinguish" mindset, which thankfully seems to have waned quite a bit.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.