Using snprintf to avoid buffer overrun - c

I dont understand why I am getting an output like this: StackOver↨< as snprintf should take care of null termination as expected output is StackOver. I am using devcpp IDE.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(void)
{
char buffer[10];
printf("%d\n", sizeof(buffer));
snprintf(buffer, sizeof(buffer), "%s", "StackOverflow");
printf("%s", buffer);
return 0;
}

The C Standard states that the copied string shall be nul-terminated:
7.21.6.5 The snprintf function
...
Description
The snprintf function is equivalent to fprintf , except that the
output is written into an array (specified by argument s ) rather than
to a stream. If n is zero, nothing is written, and s may be a
null pointer. Otherwise, output characters beyond the n-1st
are discarded rather than being written to the array, and a null
character is written at the end of the characters actually written
into the array. If copying takes place between objects that
overlap, the behavior is undefined.
It appears you are running with an outdated and/or buggy C runtime library as the snprintf() implementation doesn't seem to properly implement the required behavior.

This code is working fine for me. The buffer only has space for 10 characters so sprintf is only able to write the first 9 characters that you tell it to write ("StackOver"). At the tenth character it stores a terminating null character, since every C string must be null-terminated.
The only suggestion I would make is adding a newline when printing the string at the end:
printf("%s\n", buffer);
The lack of a newline at the end might be the reason why your IDE is showing you that ↨ character.
If you want the buffer to fit "StackOverflow" you need to allocate it to something larger.

Related

Does the gets() function in C automatically add a NULL character at the end of the input string?

I am writing a simple program to convert a number(+ve,32-bit) from binary to decimal. Here's my code:
int main()
{
int n=0,i=0;
char binary[33];
gets(binary);
for (i = 0; i < 33, binary[i] != '\0'; i++)
n=n*2+binary[i]-'0';
printf("%d",n);
}
If I remove binary[i]!='\0', then it gives wrong answer due to garbage values but if I don't it gives the correct answer. My question is: does the gets function automatically add a '\0' (NULL) character at the end of the string or is this just a coincidence?
Yes it does, writing past the end of binary[33] if it needs to.
Never use gets; automatic buffer overrun.
See Why is the gets function so dangerous that it should not be used? for details.
When gets was last supported (though deprecated) by the C standard, it had the following description (§ 7.19.7.7, The gets function):
The gets function reads characters from the input stream pointed to by stdin, into the
array pointed to by s, until end-of-file is encountered or a new-line character is read.
Any new-line character is discarded, and a null character is written immediately after the last character read into the array.
This means that if the string read from stdin was exactly as long as, or longer than, the array pointed to by s, gets would still (try to) append the null character to the end of the string.
Even if you are on a compiler or C standard revision that supports gets, don't use it. fgets is much safer since it requires the size of the buffer being written to as a parameter, and will not write past its end. Another difference is that it will leave the newline in the buffer, unlike gets did.

A little query, String in C

Recently I was programming in my Code Blocks and I did a little program only for hobby in C.
char littleString[1];
fflush( stdin );
scanf( "%s", littleString );
printf( "\n%s", littleString);
If I created a string of one character, why does the CodeBlocks allow me to save 13 characters?
C have no bounds-checking, writing out of bounds of arrays or dynamically allocated memory can't be checked by the compiler. Instead it will lead to undefined behavior.
To prevent buffer overflow with scanf you can tell it to only read a specific number of characters, and nothing more. So to tell it to read only one character you use the format "%1s".
As a small side-note: Remember that strings in C have an extra character in them, the terminator (character '\0'). So if you have a string that should contain one character, the size actually needs to be two characters.
LittleString is not a string. It is a char array of length one. In order for a char array to be a string, it must be null terminated with an \0. You are writing past the memory you have allotted for littleString. This is undefined behavior.Scanf just reads user input from the console and assigns it to the variable specified, in this case littleString. If you would like to control the length of user input which is assigned to the variable, I would suggest using scanf_s. Please note that scanf_s is not a C99 standard
Many functions in C is implemented without any checks for correctness of use. In other words, it is the callers responsibility that the arguments fulfill some rules set by the function.
Example: For strcpy the Linux man page says
The strcpy() function copies the string pointed to by src,
including the terminating null byte ('\0'), to the buffer
pointed to by dest. The strings may not overlap, and the
destination string dest must be large enough to receive the copy.
If you as a caller break that contract by passing a too small buffer, you'll have undefined behavior and anything can happen.
The program may crash or even do exactly what you expected in 99 out of 100 times and do something strange in 1 out of 100 times.

About gets() in C

I am writing a C program, which has a 5-element array to store a string. And I am using gets() to get input. When I typed in more than 5 characters and then output the string, it just gave me all the characters I typed in. I know the string is terminated by a \0 so even I exceeded my array, it will still output the whole thing.
But what I am curious is where exactly gets() stores input, either buffer or just directly goes to my array?
What if I type in a long long string, will gets() try to store characters in the memories that should not be touched? Would it gives me a segment fault?
That's why gets is an evil. It does not check array bound and often invokes undefined behavior. Never use gets, instead you can use fgets.
By the way, now gets is no longer be a part of C. It has been removed in C11 standard in favor of a new safe alternative, gets_s1 (see the wiki). So, better to forget about gets.
1. C11: K.3.5.4.1 The gets_s function
Synopsis
#define _ _STDC_WANT_LIB_EXT1_ _ 1
#include <stdio.h>
char *gets_s(char *s, rsize_t n);
gets() will store the characters in the 5-element buffer. If you type in more than 4 characters, the end of string character will be missed and the result may not work well in any string operations in your program.
excerpt from man page on Ubuntu Linux
gets() reads a line from stdin into the buffer pointed to by s until
either a terminating newline or EOF, which it replaces with a null byte
('\0'). No check for buffer overrun is performed
The string is stored in the buffer and if it is too long it is stored in contiguous memory after the buffer. This can lead to unintended writing over of data or a SEGV fault or other problems. It is a security issue as it can be used to inject code into programs.
gets() stores the characters you type directly into your array and you can safely use/modify them. But indeed, as haccks and unxnut correctly state, gets doesn't care about the size of the array you give it to store its chars in, and when you type more characters than the array has space for you might eventually get a segmentation fault or some other weird results.
Just for the sake of completeness, gets() reads from a buffered file called stdin which contains the chars you typed. More specifically, it takes the chars until it reaches a newline. That newline too is put into your array and next the '\0' terminator. You should, as haccks says, use fgets which is very much alike:
char buf[100]; // the input buffer
fgets(buf, 100, stdin); // reads until it finds a newline (your enter) but never
// more than 99 chars, using the last char for the '\0'
// you can now use and modify buf

Printf a buffer of char with length in C

I have a buffer which I receive through a serial port. When I receive a certain character, I know a full line has arrived, and I want to print it with printf method. But each line has a different length value, and when I just go with:
printf("%s", buffer);
I'm printing the line plus additional chars belonging to the former line (if it was longer than the current one).
I read here that it is possible, at least in C++, to tell how much chars you want to read given a %s, but it has no examples and I don't know how to do it in C. Any help?
I think I have three solutions:
printing char by char with a for loop
using the termination character
or using .*
QUESTION IS: Which one is faster? Because I'm working on a microchip PIC and I want it to happen as fast as possible
You can either add a null character after your termination character, and your printf will work, or you can add a '.*' in your printf statement and provide the length
printf("%.*s",len,buf);
In C++ you would probably use the std::string and the std::cout instead, like this:
std::cout << std::string(buf,len);
If all you want is the fastest speed and no formatting -- then use
fwrite(buf,1,len,stdout);
The string you have is not null-terminated, so, printf (and any other C string function) cannot determine its length, thus it will continue to write the characters it finds there until it stumbles upon a null character that happens to be there.
To solve your problem you can either:
use fwrite over stdout:
fwrite(buffer, buffer_length, 1, stdout);
This works because fwrite is not thought for printing just strings, but any kind of data, so it doesn't look for a terminating null character, but accepts the length of the data to be written as a parameter;
null-terminate your buffer manually before printing:
buffer[buffer_length]=0;
printf("%s", buffer); /* or, slightly more efficient: fputs(buffer, stdout); */
This could be a better idea if you have to do any other string processing over buffer, that will now be null-terminated and so manageable by normal C string processing functions.
Once you've identified the end of the line, you must append a '\0' character to the end of the buffer before sending it to printf.
You can put a NUL (0x0) in the buffer after receiving the last character.
buffer[i] = 0;

Reading In A String and comparing it C

Im trying to create a C based string menu where a user inputs a command and then a block of code runs.
Whatever i do the conditional is never true:
char *input= "";
fgets(input, 50, stdin);
printf("%s",input);
printf("%d",strcmp( input,"arrive\0"));
if(strcmp( input,"arrive\0")==0){....
Im fairly new to c and am finding strings really annoying.
What am i doing wrong?
Note: current code crashes my program :(
Why strcmp always return non 0:
strcmp will return 0 only when the strings are identical. As for why it's evaluating to different always. It is because fgets puts a newline character at the end of your input buffer before the null termination.
/*Will print 0 if you type in arrive<enter>*/
printf("%d",strcmp( input,"arrive\n"));
Why your program crashes:
Another problem is that input should be a char buffer. Like so: char input[1024];
Currently you have input as a pointer to a null terminated string (which is read only memory)
Friendly suggestion:
Also don't put the null terminated \0 inside the string literals. It is implied automatically when you use a string literal. It doesn't matter to double null terminate as far as strcmp is concerned, but it may cause problems elsewhere in your future programs. And people will wonder why you're doing double null termination.
Try :
#define BUFF_LEN 256
char input[BUFF_LEN];
fgets(input, BUFF_LEN, stdin);
What you have , *input is a pointer to an address of memory that has not been allocated, hence can not be used by your program. The result of using it as you are is undefined, but usually leads to a segmentation fault. If you want to access it as a pointer, you will first need to allocate it:
char *input = malloc(BUFF_LEN);
... of course, test that for failure (NULL) then free() it after you are done using it.
Edit:
At least according to the single UNIX specification, fgets() is guaranteed to null terminate the buffer. Its not necessary to initialize input[].
As others have said, it is not necessary to include null / newlines when using strcmp().
I also strongly, strongly advise you to get used to using strncmp() now, while beginning to avoid many problems down the road.
Try replacing the first line with
char input[50];
memset(input, 0, sizeof(input));
Edit:
However, the real problem why strcmp doesn't return 0 is you have to "trim" the string read from fgets, which in most cases, includes a newline character.

Resources