0

I want to prevent buffer overflow by making the filename no more than 20 character long. Is there a better function I should use? Like fgets?

#include <stdio.h>

int main()
{
char filename[20]; //20 character long
printf("Please enter your filename:");
scanf("%s", filename);


return 0;
}
myadeniboy
  • 55
  • 7
  • `fgets()` allows limiting the length of input. Try `fgets(filename, sizeof(filename), stdin)`. That will prevent buffer overflow. It also can detect when the user has entered more characters than the buffer can hold (rather than overflowing the buffer) so you can manage it. Read the documentation. – Peter Oct 26 '18 at 23:58
  • @Peter When I use fgets, it will not read the file, but I have no problem with scanf. – myadeniboy Oct 27 '18 at 00:12
  • 1
    See [Specifying the maximum string length to `scanf()` dynamically in C (like `%s` in `printf()`)](https://stackoverflow.com/questions/28459980/specifying-the-maximum-string-length-to-scanf-dynamically-in-c-like-s-in-pr). For the case shown, you could use `scanf("%19s", filename);` with a static length limit (instead of dynamic as discussed in the linked question) – Jonathan Leffler Oct 27 '18 at 00:29
  • @myadeniboy If you use `fgets`, you need to [remove the newline](https://stackoverflow.com/questions/2693776) that `fgets` puts in the buffer. – user3386109 Oct 27 '18 at 00:47
  • You don't solve buffer overflow by making your buffers too small :) – rici Oct 27 '18 at 03:32
  • @myadeniboy - `fgets()`, at most, will only read one line of input, since it will stop at the first newline. If the line is longer than the buffer, it only reads part of the line, and it is necessary to call it more than once (e.g. in a loop) to get the whole line. If `scanf()` works in the same case, that's because you're overrunning the buffer. You can't have your cake and eat it too - expecting `fgets()` to read more than the supplied buffer length in one call is simply ludicrous. – Peter Oct 27 '18 at 12:57
  • @JonathanLeffler Thank you for this, but why use 19 instead 20? – myadeniboy Oct 28 '18 at 03:27
  • Because! Ancient history mainly. At the time (later 70s), buffet overflows were not recognized as the problem they are (witness `gets()`, and the fact that `scanf()` makes it hard to avoid them). The decision was made to use the length excluding the terminal null, like `strlen()`, and then everything else decided to use length of buffer including terminal null, but it was too late to change `scanf()` et al. Changing the meaning would break working code. – Jonathan Leffler Oct 28 '18 at 03:51
  • @JonathanLeffler So I can use `scanf("%19s", filename);` instead of `fgets` to prevent buffer overflow attack? – myadeniboy Oct 28 '18 at 04:12

1 Answers1

0

scanf and fgets both can be used, but one will probably be easier for your application.

scanf can be used, but check the return value.

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

int main(void) {
    char filename[20];
    while(scanf("%19s", filename) == 1) {
        printf("filename: %s\n", filename);
    }
    if(errno) return perror("filename"), EXIT_FAILURE;
    return EXIT_SUCCESS;
}

Outputs,

12345678901234567890
filename: 1234567890123456789
filename: 0

fgets gets the entire line without matching it to input.

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

int main(void) {
    char filename[20];
    while(fgets(filename, sizeof filename, stdin)) {
        printf("filename: %s\n", filename);
    }
    if(errno) return perror("filename"), EXIT_FAILURE;
    return EXIT_SUCCESS;
}

Outputs,

12345678901234567890
filename: 1234567890123456789
filename: 0
[\n]

Usually, too-long filenames either truncate or complain, this is easy to see with fgets, eg, How to discard the rest of a line in C.

Neil
  • 1,767
  • 2
  • 16
  • 22