Home > Enterprise >  avoiding char buffer overflow more efficiently
avoiding char buffer overflow more efficiently

Time:04-12

i wrote a simple in/out program whenever i run it and enter the input and exceed the char limit i get *** stack smashing detected ***: terminated Aborted (core dumped)

i searched it up and found it was a gcc thing for safety,i heard it might lead to seg faults so i experimented turning it off with -fno-stack-protector and it ran normally if i exceeded the char limit

but what if i want to write the program if the input length is unknown, is there a safer way to do this? more efficient that increasing the value in char to an ridiculously large value?

the code:

#include <stdio.h>
int main()
{
        char in[1];
        printf("in: ");
        scanf("%s\0", &in);
        printf("\nout: %s\n", in);
}

P.s- im new to C, >2 days old so a simple explanation would be appreciated

CodePudding user response:

char in[1]; can hold only the empty string (a single null terminating byte), which is impossible to use safely with scanf.

Also note that explicitly stating the null terminating byte in a string literal is superfluous, as they are implicitly null terminated.

but what if i want to write the program if the input length is unknown, is there a safer way to do this? more efficient that increasing the value in char to an ridiculously large value?

The counter-questions here are:

  • What do you consider inefficient?
  • What do you define as ridiculously large?

As I see it, you have two options:

  1. Use dynamically allocated memory to read strings of an arbitrary size.
  2. Set a realistic upper limit on the length of of input to expect.

An example of #1 can be seen in library functions like POSIX getline or getdelim. Its re-implementation can be as simple as as malloc (realloc), getchar, and a loop.

The use of #2 depends greatly on the context of your program, and what it is supposed to do. Perhaps you a reading a single line, and a smallish buffer will suffice. Maybe you are expecting a larger chunk of data, and need more memory. Only you can decide this for yourself.

In any case, its up to you to avoid undefined behavior by preventing overflows before they happen. It is already too late if one has occurred.

Use field-width specifiers when using %s:

char buf[512];
if (1 != scanf("Q1s", buf))
    /* read error */;

or use sane functions like fgets, which allow you to pass a buffer size as an argument.

CodePudding user response:

stack smashing detected
i searched it up and found it was a gcc thing for safety

That's indeed gcc's way of spotting run-time bugs in your code by inserting so-called "stack canaries" to spot stack corruption/overflows. More errors detected is a good thing.

i heard it might lead to seg faults

No, bugs in your application lead to seg faults. If the compiler provides ways to detect them before the OS, that's a good thing. Dormant but severe bugs in your program is a bad thing. However, the OS would possibly detect the bug too and say "seg fault".

so i experimented turning it off with -fno-stack-protector and it ran normally if i exceeded the char limit

Basically you know that you are an inexperienced driver and afraid you might hit other cars. To solve, this you drive with your eyes closed instead, so you won't see those cars you could hit. That doesn't mean that they disappear.

char in[1]; can only hold 1 byte of data and if you read out of bounds of this array, you invoke undefined behavior, which will manifest itself as stack smashing or seg faults. Because you are trying to write to memory that doesn't belong to you. This is the bug, this is the problem. The correct solution is to allocate enough memory.

(You also have a bug scanf("%s\0", &in); -> scanf("%s\0", in);. The & isn't needed since in is an array and automatically "decays" into a pointer to its first element when you pass it to a function.)

One sensible way is to allocate 128 bytes or so, and then restrict the input so that it cannot be more than 128 bytes. The proper function to read strings with restricted input length is fgets. So you could either switch to fgets or you could accept that your beginner trial programs need not live up to production quality and just use scanf for now. (You can use scanf safely as shown in another answer, but IMO that's just more cumbersome than using fgets.)

Also I would strongly advise C beginners not to worry about if they allocate 10 bytes or 100 bytes. Learn programming by using a PC and then it won't matter. Optimizing memory consumption is an advanced topic which you will learn later on.

  • Related