Thread: How to use gets_s

  1. #16
    Registered User
    Join Date
    May 2008
    Posts
    22
    so, the only check in the line "if (gets_s( buff, BUFFSIZE ) == NULL )" is to see if there is an absence of input in which the error is caught and handled. But does not check whether or not the amount of input is more than the specified buffer size, instead it just bombs out.
    I rewrote the gets_s() function to behave the way that it should. It works but does anyone see any problems with it?

    Code:
    #include <stdio.h>
    
    char * getss ( char *s, int size ) ;
    
    int main ( int argc, char *argv[] )
    {
    	char buffer[10] ;
    	
    	printf ("Enter a string:  ") ;
    	
    	if (getss(buffer, 10) == NULL) printf ("Buffer Overloaded!") ;
    	else printf ("The line entered was: %s\n", buffer) ;
    	return 0 ;
    }
    
    char *getss(char *s, int size)
    {
        char *stringBuilder = (char *) malloc( size * sizeof( char )) ;
        int i, k;
        
        /* Read and store characters until reaching a newline or end-of-file */
        for (i = 0; k != EOF && k != '\n'; i++)
        {
            k = getchar() ;
        /* If a read error occurs, the resulting buffer is not usable. */
    	if (i > size) return NULL ;
            if (k == EOF && !feof(stdin)) return NULL;
       	stringBuilder[i] = k;
        }
        /* Null-terminate and return the buffer on success.
           The newline is not stored in the buffer. */
       //stringBuilder[i] = '\0';
    
        strcpy( s, stringBuilder ) ; 
        return s;
    }

  2. #17
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Yes.
    You never free stringBuilder.
    And why not just use fgets?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  3. #18
    Registered User
    Join Date
    May 2008
    Posts
    22
    Quote Originally Posted by Elysia View Post
    Yes.
    You never free stringBuilder.
    And why not just use fgets?
    Thanks, I'll make sure to free it and I see that it is not Null terminating the string also.
    I just tried fgets(). Unfortunately, it has the same response to finding more input than specified. it just dies. I understand bounds checking is good, but allow to handle the error instead of exiting the program. So, I would need to modify fgets() as well, to respect the size given in the parameter and return NULL if there is more input than expected instead of doing an assert. I mean, how am I to make a useful program if the program exits any time someone types one more character than the field is permitted?

    On an aside, I found this excellent ppt presentation that explains the dangers or arc-injection, code-injection, and various mitigation techniques for buffer overflows, I think it would be helpful for anyone trying to learn how to program in C securely.

  4. #19
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by gwarf420 View Post
    I just tried fgets(). Unfortunately, it has the same response to finding more input than specified. it just dies.
    No, it doesn't. It reads up to a maximum of the specified characters - 1 and appends null to the end.
    So how do we know if fgets read the entire line or not? Simple.
    First, check the return of fgets. Does it return 1? If yes, then it means it read successfully (ie, not end of file). Then check the last character before the null in the buffer. Is it '\n'? If yes, then fgets read the entire line. If not, read some more.

    I understand bounds checking is good, but allow to handle the error instead of exiting the program.
    Usually, because it means it's a programmer error. C is very unfriendly when it comes to buffers. Sometimes it is mostly the programmer's fault for not providing big enough buffers. And it's better than nothing.

    So, I would need to modify fgets() as well, to respect the size given in the parameter and return NULL if there is more input than expected instead of doing an assert.
    No you don't, see above.

    On an aside, I found this excellent ppt presentation that explains the dangers or arc-injection, code-injection, and various mitigation techniques for buffer overflows, I think it would be helpful for anyone trying to learn how to program in C securely.
    Nice catch. Let's investigate this one and see if we can put it somewhere.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #20
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Elysia View Post
    No, it doesn't. It reads up to a maximum of the specified characters - 1 and appends null to the end.
    So how do we know if fgets read the entire line or not? Simple.
    First, check the return of fgets. Does it return 1? If yes, then it means it read successfully (ie, not end of file). Then check the last character before the null in the buffer. Is it '\n'? If yes, then fgets read the entire line. If not, read some more.
    Erm, fgets(), like gets(), returns a pointer to the buffer, or NULL if EOF was encountered. It will never ever return 1 [For the pedants: unless you have a system where memory address 1 is a valid address, and that's what you passed to fgets() - but that rules out most modern 32-bit OS's at least].

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  6. #21
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    >> First, check the return of fgets. Does it return 1? If yes, then it means it read successfully (ie, not
    >> end of file).

    fgets returns the buffer or NULL, not a number.

    gwarf, it sounds like you need to roll your own. If you know how realloc works you can make an input function that reads an entire line up to '\n'

  7. #22
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by matsp View Post
    Erm, fgets(), like gets(), returns a pointer to the buffer, or NULL if EOF was encountered. It will never ever return 1 [For the pedants: unless you have a system where memory address 1 is a valid address, and that's what you passed to fgets() - but that rules out most modern 32-bit OS's at least].
    Quote Originally Posted by citizen View Post
    >> First, check the return of fgets. Does it return 1? If yes, then it means it read successfully (ie, not
    >> end of file).

    fgets returns the buffer or NULL, not a number.
    Oops, yes, I was thinking of fread.
    Still, that presentation is pretty good. Just beware of the void main in there.
    And not surprisingly, it does mention that Visual Studio catches some common errors such as some buffer overruns and stack smashing.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #23
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    Quote Originally Posted by Elysia View Post
    It means it's a programmer error. C is very unfriendly when it comes to buffer overflows. It is the programmer's fault, for whatever reason (not considering implementation deficiencies).
    fixed.
    Quote Originally Posted by Elysia View Post
    Oops, yes, I was thinking of fread.
    fread does not guarantee return of 1 on success.

  9. #24
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by robwhit View Post
    fixed.
    If you like it better that way...

    fread does not guarantee return of 1 on success.
    No, it doesn't, it returns "count," but it was a simplification since I always use fread(whatever, size, 1, file).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #25
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    Quote Originally Posted by Elysia View Post
    If you like it better that way...
    I find it less inflammatory.

  11. #26
    Registered User
    Join Date
    May 2008
    Posts
    22
    [QUOTE]
    I just tried fgets(). Unfortunately, it has the same response to finding more input than specified. it just dies.[/QOUTE]

    My bad, I was using a function that tested gets_s() and then fgets() right after it. So, it was not fgets that was causing the assert. It was my useless friend gets_s().

    fgets() works well, but seems to cause its own complications:
    1. The '\n' is stored in the string (which is fine if I'm just dumping input to a file). In order to use input for variables, I would have to go through each input string and NULLify the '\n' characters.
    2. If there is more input than the length of the buffer, I would need to flush the rest of the input line.

    I believe the least complex way of accepting input is to implement this function that is similar in behavior to C++'s getline which is stack safe and dynamic (then I can validate the input length, format, etc):
    Code:
    char * getstring ()
    {
    	FILE *tempFile = tmpfile() ;
    	int i, k = 0 ;
            char *s = NULL ;
        
        if (tempFile)
    	{
    		/* Read and store characters until reaching a newline or end-of-file */
    		for (i = 0; k != EOF && k != '\n'; i++)
    		{
    			k = getchar() ;
    		
    		/* If a read error occurs, the resulting buffer is not usable. */
    		if (k == EOF && !feof(stdin)) return NULL;
    		
    		if (k == '\n') fputc( '\0', tempFile ) ;  //substitute NULL termination for newline
    		else fputc( k, tempFile ) ;
    		
    		}
    		
    		s = (char *) realloc( s, ++i * sizeof( char ) ) ;
    		rewind( tempFile ) ;
    		fgets( s, i, tempFile ) ;
    		fclose( tempFile ) ;
    		tempFile = NULL ;
    		return s;
    	}
    	else return NULL ;
    }
    Anybody have any idea why if I pass a character pointer into this function and realloc the passed pointer, it does not retain the new info back in the main function?
    Last edited by gwarf420; 05-24-2008 at 11:33 AM. Reason: Added my other issue with fgets()

  12. #27
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    If you want to modify a pointer, you need a pointer to pointer, because you can only modify something if you have a pointer to it (you need to know the original address of the thing you want to modify).

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Tags for this Thread