I am having a problem with gets.
The purpose is to get input from the user until he hits the 'Enter'.
This is the code:
struct LinkedListNode* executeSection2()
{
char inputArr [3] = {'\0'};
struct LinkedListNode* newNode;
struct LinkedListNode* head = NULL;
gets (inputArr);
while (inputArr[0] != 0) // The user didn't press "Enter"
{
newNode=newLinkedListNode();
newNode->tree=newHuffmanNode(inputArr[0],atoi(inputArr+2));
head = addNode(&head, newNode);
gets (inputArr);
}
head = buildHuffmanTree(&head);
return head;
}
It seems OK, the user hits the 'Enter', the code go out from the while, but after the return, I get the error message:
Stack around the variable 'inputArr' was corrupted
I guess I dont read the input from the keyboard properly.
I will be happy for some guidness.
Thanks.
This error is a perfect illustration to the reason why gets has been deprecated: it is prone to buffer overruns, which corrupt stack or whatever memory happens to be near the end of your buffer. When the user enters more than two characters, the first three get placed into the buffer, and the rest go into whatever happens to be in the memory after it, causing undefined behavior.
You need to replace the call of gets with a call of fgets, which accepts the size of the buffer, end prevents user input from overrunning it:
fgets (inputArr, 3, stdin);
on every while iteration, the user hit enter and at the end, when he wants to stop, he hits only enter.
fgets considers '\n' part of the string, so when the user hits enter the only character in the returned string will be '\n':
while (inputArr[0] != '\n') { // The user didn't press "Enter"
...
}
The gets function in C is a classic buffer overflow function. gets is one of the functions which gives C a bad name for security. You are experiencing a buffer overflow. As long as you never intend to distribute this code, I won't object. However, you should never use gets for anything more than a toy program. The man page says as much, and informs you that no check for buffer overrun is performed. On my Mac, the man page say:
It is the caller's responsibility to ensure that the input line, if any, is sufficiently short to fit in the string.
As to why this happens, it happens because the user is inputting more data than your program can handle. Your program can handle two characters. It doesn't look like the newline character(s) should be counted. In a properly coded application, it should be impossible for user input to corrupt memory in this way.
Related
One problem I have writing console apps for real-world users in C is that I don't know how of a way to get keyboard input from the user in a safe, robust, simple way. For example, this program has several issues:
#include<stdio.h>
void main()
{
char name[8];
printf("Enter Your Name : ");
scanf("%s",&name);
printf("Your name is : %s\n", name);
return 0;
}
The program can't handle blank input.
The program drops text after a space.
The program goes beyond the array size and is unsafe.
I'd like to have a safe, robust (i.e. doesn't crash on unexpected input), simple function that can get a string from the user via keyboard input. I'm looking for something that works similar to Python's input() function. Does this exist in the C standard library, or is there a function I can copy/paste into my program? I'd prefer to not have to deal with loading another library.
Ideally, the function would include the following features:
The user types some text and presses Enter.
The function call blocks until the user presses Enter.
The left/right arrow keys move the cursor, and backspace & delete work normally.
The user can enter any amount of text. (Any excess text can be truncated, or some other sensible default behavior.)
The scanf() function isn't good enough. I need a function I can call that gets keyboard input and returns a string; it would just work.
ADDITIONAL NOTE: The fgets() function is also not what I'm looking for. If a user enters more text than is allocated for the buffer, then the remainder of the text is automatically used the next time fgets() is called.
First off, if you do not need ANSI C getline(NULL, 0, stdin) is the best solution.
Ok, new try to answer this right. I know this problem.
1.) First you need line input but getc violates your constraint to scroll back. It can only put one char back. So you need a function of the get family to do this. It is blocking and requires Enter as always on command line.
2.) Next you want to use any text length. But that is the problem in C as there are no Strings with variable lenght. The OS defines a maximal length (see Bash command line and input limit). So you can use this size as buffer and it will be save. Otherwise you could only take one char or block (see fread) after another which would violate your first constraint. (see 1.).
At least (if you don't want to use POSIX Calls) there might be a hack: Depending on what machine (x86 or other) you are using, you can pass either the Heap- or the Stack-Pointer. It might overwrite your process memory and it will crash then. But if this is the case, there was no chance to do it right with stdin either.
If your machine has not enough RAM you can only read blockwise and put the data into a file (e.g. on hard drive). You may want to use ungetc() to check if Enter was pressed or you might need some other file operations (see stdio.h). Don't forget that C was designed for UNIX, so "everything is a file" and you can use file operations on stdin (which is your console input).
Because of the overflow problem gets (stdio.h) was removed from the POSIX library: https://en.wikipedia.org/wiki/C_POSIX_library.
The easiest way in ISO C to read a whole line of input is to use the function fgets.
The user can enter any amount of text. (Any excess text can be truncated, or some other sensible default behavior.)
That is where is gets complicated. The easiest solution would simply report failure if it detects that the line is too long to fit in the buffer:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
//This function will return true on success, false on failure.
//The buffer must be two bytes larger than the actual length of
//the line. It needs an extra byte for the newline character
//(which will be removed) and for the terminating null
//character.
bool get_line_from_user( char *buffer, int buffer_size )
{
char *p;
if ( fgets( buffer, buffer_size, stdin ) == NULL )
{
fprintf( stderr, "Error reading from input\n" );
return false;
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( ( p = strchr( buffer, '\n' ) ) == NULL )
{
//a missing newline character is ok on end-of-file condition
if ( !feof( stdin ) )
{
int c;
fprintf( stderr, "Line input was too long!\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "Error reading from input\n" );
return false;
}
} while ( c != '\n' );
return false;
}
}
else
{
//remove newline character by overwriting it with null character
*p = '\0';
}
return true;
}
int main( void )
{
char line[20];
printf( "Please enter a line of input:\n" );
if ( get_line_from_user( line, sizeof line ) )
{
printf( "Input was valid. The input was:\n%s", line );
}
else
{
printf( "Input was invalid." );
}
}
This program has the following behavior:
Valid input:
Please enter a line of input:
This is a test.
Input was valid. The input was:
This is a test.
Input too long:
Please enter a line of input:
This is a test line that is too long to fit into the input buffer.
Line input was too long!
Input was invalid.
Of course, a buffer size of only 20 is obviously too small for most common tasks. I only set it this low in order to demonstrate the error message. Normally, I would set the buffer size to, maybe, 200.
Under most circumstances, it should be no problem to increase the buffer size to several kilobytes if necessary, even if the buffer is being allocated on the stack.
If you want to be able to read more than a few kilobytes in a single line (for example if the input is being redirected from a file), then it would probably be better to allocate a sufficiently sized array that is on the heap instead of the stack, by using the function malloc.
If you want the maximum line size to be truly unlimited, then you could call the function fgets multiple times per line, until it encounters the newline character, and resize the buffer as necessary. See this question for further information (credit goes to the comments section for this link).
ADDITIONAL NOTE: The fgets() function is also not what I'm looking for. If a user enters more text than is allocated for the buffer, then the remainder of the text is automatically used the next time fgets() is called.
That is why my program discards the remainder of the line from the input stream, if it detects that the line was too long. That way, you do not have this problem.
I'm recently working on simple chess game on the terminal using C, but I've ran into a small issue in regard to taking user input.
The following function takes in a 3-Dimensional array containing current chess piece placements, a pointer to a buffer that'll contain the user input, and the size of this buffer which I set to 7.
void next_move(char board[8][8][4], char* move, size_t buff_size){
char * move_1 = (char )malloc(sizeof(char)3);
char * move_2 = (char )malloc(sizeof(char)3);
char delim[]=" ";
getline(&move,&buff_size,stdin);
move_1=strtok(move,delim);
move_2=strtok(NULL,delim);
if(*move_1 == '\0'){
printf("invalid move !");
return ;
}
printf("%s%s\n",move_1,move_2);
if(!check_move(board, move_1, move_2)){
printf("valid move !\n");
}
}
The function check_move takes in both moves inputted by the user and verifies if they're valid chess moves (E.g "Nb1 Nc3").
My issue lies in the fact that when the user inputs no character or a string of characters not containing a space (the delimeter defined in strtok) it results in a segmentation fault when I try to do the check:
if(*move_1 == '\0')
Which is used mainly to handle the exception in the case that the move_1 and move_2 pointers are null.
I have two questions:
How can I check if a char pointer is null ? (I have already tried using move_1 == NULL)
Why the does the code continue execution and returns if I set the conditional statement to if(*move_1 != 0). Although this causes all input (even if it's the correct format) to not be valid.
Question 1
It sounds like maybe move is NULL, but your first call to strtok is supposed to have a non-NULL pointer. Therefore, right after you call getline, I think you should check to make sure move is not NULL. It would also be a good idea to check that move_1 and move_2 are not NULL. You can do these checks with code like this:
getline(&move,&buff_size,stdin);
if (move == NULL) {
// handle this case, probably with an early return
}
Note that the code above only shows a check for move, but I think you should probably do the same thing for move_1 and move_2, right after you assign to them, and before you use them or derefence them. (Some of these checks might turn out to be unnecessary upon further investigation, but for now I think the priority is to just fix all the segmenation faults so your program can run without crashing.)
Question 2
It sounds like you changed your code to the following and it started declaring all your input as invalid:
if(*move_1 != '\0'){
printf("invalid move !");
return;
}
Well, the explanation for that is simple. You are telling your compiler that if the first character of the move_1 string is not a null-termination character, that it should print "invalid move !" and return. Therefore, whenever move_1 is non-empty, it will do that. Maybe you meant to use == (equal) instead of != (not equals).
If you mean by entering no characters that you are pressing enter that means your condition should be like: if(*move_1 == '\n'), since the Enter in a new line feed to the command line which is '\n' escape character.
I wish I can see your full project and work together to complete it...
I have a small program I'm writing to practice programming in C.
I want it to use the getchar(); function to get input from the user.
I use the following function to prompt for user input, then loop using getchar() to store input in an array:
The function is passed a pointer referencing a struct's member.
getInput(p->firstName); //The function is passed an argument like this one
void getInput(char * array)
{
int c;
while((c=getchar()) != '\n')
*array++ = c;
*array = '\0'; //Null terminate
}
This function is called multiple times, as it is a part of a function that creates a structure, and populates it's array members.
However when the program executes, The first two calls to it work fine, but any subsequent calls to this function will cause every-other call to getchar() to not wait for keyboard input.
After some debugging I traced the bug to be that getchar(); was for some reason reading in the '\n' character instead of waiting for input, the while loop test fails, and the function returns essentially an empty string.
I have done some research and keep finding to use
while(getchar() != '\n');
at the end of the function in order to properly flush stdin, however, this produces undesirable results, as the program will prompt again for more input after I type ENTER. Pressing ENTER again continues the program, but every-other subsequent calls continue to read in this mysterious '\n' character right off the bat, causing the test to fail, and resulting in empty strings whenever it comes time to print the contents of the the structure.
Could anyone explain to me what is going on here? Why does getchar() keep fetching a '\n' even though I supposedly cleared the input buffer? I have tried just placing a getchar(); statement at the beginning and end of the function, tried 'do while' loops, and taken other jabs at it, but I can't seem to figure this out.
The code you have written has several drawbacks. I'll try to explain them as it is unclear where your code is failing (probably outside the function you posted)
First of all, you don't check for EOF in getchar() result value. getchar(3) doesn't return a char precisely to allow to return al possible char values plus an extra one, EOF, to mark the end of file (this can be generated from a terminal by input of Ctrl-D in unix, or Ctrl-Z on windows machines) That case must be explicitly contempled in your code, as you'll convert the result to a char and will lose the extra information you received from the function. Read getchar(3) man page to solve this issue.
Second, you don't check for input of enough characters to fill all the array and overflow it. To the function you pass only a pointer to the beginning of the array, but nothing indicates how far it extends, so you can be overfilling past the end of its bounds, just overwritting memory that was not reserved for input purposes. This normally results in something called U.B. in the literature (Undefined Behaviour) and is something you must care of. This can be solved by passing a counter of valid positions to fill in the array and decrementing it for each valid position filled. And not allowing more input once the buffer has filled up.
On other side, you have a standar function that does exactly that, fgets(3) just reads one string array from an input file, and stores it on the pointer (and size) you pass to it:
char *fgets(char *buffer, size_t buffer_size, FILE *file_descriptor);
You can use it as in:
char buffer[80], *line;
...
while (line = fgets(buffer, sizeof buffer, stdin)) {
/* process one full line of input, with the final \n included */
....
}
/* on EOF, fgets(3) returns NULL, so we shall be here after reading the
* full input file */
I am learning about heap overflow attacks and my textbook provides the following vulnerable C code:
/* record type to allocate on heap */
typedef struct chunk {
char inp[64]; /* vulnerable input buffer */
void (*process)(char *); /* pointer to function to process inp */
} chunk_t;
void showlen(char *buf)
{
int len;
len = strlen(buf);
printf("buffer5 read %d chars\n", len);
}
int main(int argc, char *argv[])
{
chunk_t *next;
setbuf(stdin, NULL);
next = malloc(sizeof(chunk_t));
next->process = showlen;
printf("Enter value: ");
gets(next->inp);
next->process(next->inp);
printf("buffer5 done\n");
}
However, the textbook doesn't explain how one would fix this vulnerability. If anyone could please explain the vulnerability and a way(s) to fix it that would be great. (Part of the problem is that I am coming from Java, not C)
The problem is that gets() will keep reading into the buffer until it reads a newline or reaches EOF. It doesn't know the size of the buffer, so it doesn't know that it should stop when it hits its limit. If the line is 64 bytes or longer, this will go outside the buffer, and overwrite process. If the user entering the input knows about this, he can type just the right characters at position 64 to replace the function pointer with a pointer to some other function that he wants to make the program call instead.
The fix is to use a function other than gets(), so you can specify a limit on the amount of input that will be read. Instead of
gets(next->inp);
you can use:
fgets(next->inp, sizeof(next->inp), stdin);
The second argument to fgets() tells it to write at most 64 bytes into next->inp. So it will read at most 63 bytes from stdin (it needs to allow a byte for the null string terminator).
The code uses gets, which is infamous for its potential security problem: there's no way to specify the length of the buffer you pass to it, it'll just keep reading from stdin until it encounters \n or EOF. It may therefore overflow your buffer and write to memory outside of it, and then bad things will happen - it could crash, it could keep running, it could start playing porn.
To fix this, you should use fgets instead.
You can fill up next with more than 64 bytes you will by setting the address for process. Thereby enable one to insert whatever address one wishes. The address could be a pointer to any function.
To fix simple ensure that only 63 bytes (one for null) is read into the array inp - use fgets
The function gets does not limit the amount of text that comes from stdin. If more than 63 chars come from stdin, there will be an overflow.
The gets discards the LF char, that would be an [Enter] key, but it adds a null char at the end, thus the 63 chars limit.
If the value at inp is filled with 64 non-null chars, as it can be directly accessed, the showlen function will trigger an access violation, as strlen will search for the null-char beyond inp to determine its size.
Using fgets would be a good fix to the first problem but it will also add a LF char and the null, so the new limit of readable text would be 62.
For the second, just take care of what is written on inp.
Im getting an error with free() every time I store input above the allocated space in the char*. Heres the error:
*** Error in ./input': free(): invalid next size (fast): 0x09713008 ***
When I remove the free(), the program runs perfectly even though I'm entering more than the allocated size. Why is this happening? How can I prevent it? Here is my code for reference:
int main(void){
float x; // used to store the float the user entered.
char c; // character used to check if the user entered a character after the float
int loop=0;
char * usr_input = malloc(50); //allocates memory to store the string from the stdin
// loops until the user enters a float and only a float
do{
//gets the input string from stdin
scanf("%s",usr_input);
if(usr_input==NULL)
printf("You've entered a large number that isnt supported. Please use at most 5 digits\n");
// parses the input received and checks if the user entered a float and only a float.
// breaks the loop if they did
else if(sscanf(usr_input,"%f %c",&x,&c) == 1){
if (x!=inf)
loop=1;
else
printf("Input was too large. Try again");
}
// tells the user they entered invalid input. Loop value doesnt change so function loops again
else{
printf("Invalid input. Try again\n");
}
}
while(loop==0); // condition for the loop
free(usr_input);//crashes here
return x; // returns the valid float that was entered
}
When I remove the free(), the program runs perfectly even though I'm entering more than the allocated size.
Entering more than allocated size is called undefined behavior. This is an error, despite the fact that your program may appear to be "running fine".
The main problem with undefined behavior is that your program does not fail fast. Essentially, the penalty for having undefined behavior is delayed until some future time - for example, when you allocate again, or when you free.
malloc stores some special information in the allocated block that lets free run. The "nvalid next size" error usually means that your code has written over some of that hidden block of data.
To fix this problem you need to change your code so that it never writes past the allocated length. If you are having trouble detecting precisely the spots that need to change, consider using valgrind or another memory profiler.
To prevent scanf from writing over your allocated size use the size in the format string:
scanf("%49s",usr_input); // Pass 49 for the length, because you have 50 bytes, and you need 1 byte for '\0'
the program runs perfectly even though I'm entering more than the
allocated size.
No, it does not run perfectly. In fact, the error you get is caused by writing past the bounds of the allocated buffer. Its a buffer overrun and introduces undefined behavior. Your program may work or may crash immediately, though in most cases it will cause problems later, problems that may look completely unrelated and therefore will be very hard to identify and correct.
Make sure you allocate a buffer large enough not to overwrite it.
On the other hand, it makes no sense for you to allocate that small buffer on the heap. It can be a static buffer on the stack and you'd avoid problems with memory allocation and release.