0

I am writing a small C code to take some user input, which would be a string. Now I read at a lot of places that using gets() will be very unsafe as it may lead to buffer overflow attacks. And in most of the places what I found as an alternative was using fgets() instead, which is safer as far as buffer overflows are concerned.

Now I have a problem scenario, where in I do not know the buffer size before hand. It just can not be determined. It could be anything. So in this case, will fgets() be handy ?

Also, what is wrong if I make use of gets(), as shown below, to solve this problem ?

char * temp_buffer_to_hold_user_input = NULL;
cahr * actual_buffer_that_stores_user_input = NULL;
int length_of_user_input =0;

/* taking user input, irrespective of its length using gets() */

gets(temp_buffer_to_hold_user_input);

/* now finding the length of the user input string and allocating the required number of bytes for proper (safe) usage */

length_of_user_input=length(temp_buffer_to_hold_user_input);
actual_buffer_that_stores_user_input = (char*)malloc(length_of_user_input*sizeof(char));
strcpy(actual_buffer_that_stores_user_input, temp_buffer_to_hold_user_input);

/* and now we work with our actual buffer */

So does the above usage of gets() still have buffer overflow problem ? Because, in the above we are not declaring a fixed size buffer at all in the first place... so no buffer overflow is what I am expecting.

Please correct me if I am missing out on something!

5
  • 4
    Indeed there is no buffer overflow. gets() storing the string at NULL will hurt though. Commented Jul 22, 2014 at 9:48
  • 1
    Just say NO to gets() and get on with your life. Just FYI: gets() is no longer part of the C language since December 2011 (some C2011 compilers provide it as an extension; other compilers may not be C2011 compatible yet). Commented Jul 22, 2014 at 9:48
  • No buffer overflow problem will occur, because you using dynamic array(char * temp_buffer_to_hold_user_input = NULL;). And i think there is no need for storing the i/p to another array. Commented Jul 22, 2014 at 9:48
  • 2
    On POSIX platforms, use getline or getdelim instead. Commented Jul 22, 2014 at 9:51
  • You can simulate getline by: 1. fgetc until your buffer is filled/newline-reached or 2. fread() to a buffer and strcspn() to find out where your newline is (then handle moving extra data or seeking). Commented Jul 22, 2014 at 16:37

3 Answers 3

5
char * temp_buffer_to_hold_user_input = NULL;

You set the pointer to NULL. Hence there is no buffer at all and gets will fail with undefined behavior (probably a segmentation fault in practice).

gets requires that you present a valid pointer to a buffer. A null pointer doesn't point to anything, hence this pre-condition is not satisfied. Since all buffers have finite length and user input is of unknown length, there's just no way at all to avoid getting a potential buffer overflow (and not to mention security risk). It's so bad that gets has been removed from the official standard.

The correct way is to use fgets. Dealing with a variable-sized input is tricky though, so you have two options:

  • Use fgets with a "large-enough for all my cases" buffer size. The easy way out. Worst case is you lose some input.
  • Repeatedly use fgets and concatenate to some dynamically allocated array (and don't forget to resize this array as needed!) until you reach the delimiter. Note: depending on what you're doing with the string though, you may not even need to hold the entire thing around, which simplifies things.
Sign up to request clarification or add additional context in comments.

1 Comment

I agree. What you could do in practice is call "fgets" repeatetly using a finite length temp_buffer_to_hold_user_input until the buffer you are reading from is empty, and each time increase the size of your actual_buffer_that_stores_user_input and append the new data.
2

If you don't know the buffer size before hand you can take a look to getline(), or build your own function and realloc your string, something like:

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

int main(void)
{
    char buf[8], *s = NULL, *p;
    size_t i = 0;

    while (fgets(buf, sizeof buf, stdin)) {
        if (i++ == 0) {
            s = malloc(sizeof buf);
            if (s == NULL) {
                perror("malloc");
                exit(EXIT_FAILURE);
            }
            strcpy(s, buf);
        } else {
            s = realloc(s, (i + 1) * sizeof(buf));
            if (s == NULL) {
                perror("realloc");
                exit(EXIT_FAILURE);
            }
            strcat(s, buf);
        }
        if ((p = strchr(s, '\n'))) {
            *p = '\0';
            break;
        }
    }
    printf("%s\n", s);
    free(s);
    return 0;
}

Without an intermediate buffer:

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

#define BUF_LEN 8

int main(void)
{
    size_t len = BUF_LEN;
    char *s, *p;

    p = s = malloc(len);
    if (s == NULL) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    while (fgets(p, BUF_LEN, stdin)) {
        if ((p = strchr(p, '\n'))) {
            *p = '\0';
            break;
        } else {
            len += BUF_LEN - 1;
            s = realloc(s, len);
            if (s == NULL) {
                perror("realloc");
                exit(EXIT_FAILURE);
            }
            p = s + len - BUF_LEN;
        }
    }
    printf("%s\n", s);
    free(s);
    return 0;
}

1 Comment

I love the warning about always checking the result of malloc and realloc below the sample code that doesn't. en.wikipedia.org/wiki/File:MagrittePipe.jpg
0

Tweaking gets() to avoid buffer overflow

Others have addressed your questions in the body. Here's a quick answer that addresses the question in your title.

Standard C provides a "safer" variant of gets via gets_s. Its was added to the C Standard with ISO/IEC TR 24731-1. Among other things, the safer function of TR 24731-1 check the destination buffer size to avoid many of the buffer overflow problems of their "unsafe" counterparts.

Here's from the document:

enter image description here

So you really don't need to tweak anything. You only need to use the correct function for the job ;)

Comments

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.