View Full Version : Safe input
GnuVince
09-17-2002, 02:17 PM
Hey guys, could anyone explain to me how to do safe input in C? (String input, integer input too) I don't think C has raw_input() or gets ;)
char *gets(char *str);
part of the standard C library.. defined in stdio.h
though:
"Since it is usually impossible to ensure that the next input line is less than some arbitrary length, and because overflowing the input buffer is almost invariably a security violation, programs should NEVER use gets()."
The 'safest' way would be to just getc() or similar until you hit a newline or the end of your buffer.
There's no distinction between integer and string input.. you'll have to convert it yourself. (atoi will do the trick)
You might want to look into readline() and whatnot.
gosper
09-17-2002, 08:46 PM
You can also use fgets,
char *fgets(char *s, int size, FILE *stream);
fgets is secure because you can specify the ammount to read in.
eg.
.....
char buf[21];
fgets(buf, 20, stdin);
Why not just:
char buf[21];
scanf( "%20s", buf );
The man page came out of the closet to say:
In addition to these flags [following %], there may be an optional maxi-
mum field width, expressed as a decimal integer, between
the % and the conversion.
Do NOT use gets(). fgets() or getc() are fine, but it's more work than necessary.
just by the way, scanf does integer input too.
int x;
scanf( "%d", &x );
exactly what you asked for, really. we're just dumb. thanks hawk. ;p
sans-hubris
09-22-2002, 02:38 AM
Originally posted by nex
just by the way, scanf does integer input too.
int x;
scanf( "%d", &x );
exactly what you asked for, really. we're just dumb. thanks hawk. ;p scanf() is dangerous, though. With getc(), at least you can stop taking in characters whenever you feel like it, even if the input buffer has more characters than you can take.
gosper
09-22-2002, 11:47 AM
scanf is vulnerable also, dont use it.
Originally posted by sans-hubris
scanf() is dangerous, though. With getc(), at least you can stop taking in characters whenever you feel like it, even if the input buffer has more characters than you can take.
scanf reads characters from stdin until the format string is exhausted or an input character doesn't match; how is that dangerous?
scanf() is NOT dangerous, if you specify a buffer length as in the example in my post earlier in the thread.
DANGEROUS
gets( buf );
scanf( "%s", buf );
SICKENINGLY INEFFICIENT
int bpos = 0;
while( (c = getc()) !== EOF ) {
buffer = c;
if( ++bpos >= bufferSize ) break;
}
[b]THE RIGHT WAY
scanf( "%20s", buf );
You can use "%*s" and supply an integer/constant/whatever, too.
l01yuk
09-25-2002, 09:43 AM
The thing is that you end up with magic numbers all over the place with scanf(). What if you reduce your buffer size? with fgets() you can use a #define to give the size, not so with scanf(). This leaves a dangerous problem for mods when you have to update it, and remember every location you want to change.
In summary, scanf() is safe in a very small program but it doesn't scale.
edit -
correct and efficient:
fgets(buff,ARR_SIZE,stdin);
Originally posted by l01yuk
In summary, scanf() is safe in a very small program but it doesn't scale.
You're right, it doesn't scale.
I said IN MY LAST POST:
You can use "%*s" and supply an integer/constant/whatever, too.
Oh, wait, yes it does.
scanf( "%*s", kConstant, buf );
Grrrrrrrrrr..
sans-hubris
09-25-2002, 11:59 AM
Originally posted by Hawk
You're right, it doesn't scale.
Oh, wait, yes it does.
scanf( "%*s", kConstant, buf );
Grrrrrrrrrr.. The point that l01yuk was trying to make is that if you have global constants in your program, you can't use them with scanf():
const int MYCONST=45;
...
scanf("%MYCONSTs", myString); //Oops, doesn't work...
The UNIX man page says the following in regards to %*:
Suppresses assignment. The conversion that follows
occurs as usual, but no pointer is used; the result
of the conversion is simply discarded.
file13
09-25-2002, 12:13 PM
Vince, what you're looking for simply dosen't exist in plain ol C. fgets is as close as it gets, but even it has problems. the main problem being it keeps the newline, but also because if you're reading something with a null in it, it'll stop. the best thing to do is use something like this:
http://home.att.net/~jackklein/ctips01.html
#include <stdio.h>
#include <string.h>
char *getsafe(char *buffer, int count)
{
char *result = buffer, *np;
if ((buffer == NULL) || (count < 1))
result = NULL;
else if (count == 1)
*result = '\0';
else if ((result = fgets(buffer, count, stdin)) != NULL)
if (np = strchr(buffer, '\n'))
*np = '\0';
return result;
}
in general if you're gonna do any C you'll usually have your own lib with safe versions that do all the tedious checking for you.
example:
FILE* Fopen(char* path, char* mode) {
FILE* file;
if((file = fopen(path, mode)) == NULL)
errQuit2("Fopen error: Unable to open file:", path);
return file;
}
(yeah, errQuit2 is another one....)
sure it just quits, but in your avarage prog that's adequate.
BTW:
http://www.cs.princeton.edu/~hains/languages/cstyle.html
note at the bottm the "safe" & "dangerous" functions.
but if you're looking for a saftey belt in C you better look at it's ugly cousin C++. while it's only a lap belt it's better then C. take away the OOP garbage and you still have, generics (templates), modules (namespaces), iostreams, string classes, and the standard library with essential goodies like vectors and lists.
Originally posted by sans-hubris
The UNIX man page says the following in regards to %*:
You're quite right. Oops.
You can still do this:
#define kConstant "20"
//...
scanf( "%"kConstant"s", buffer );
But that's a little kludgy; you'll have to make two changes to change a constant.
stuka
09-25-2002, 02:01 PM
/me can't wait to point out to file13 that the iostreams that he likes about C++ are part of the "OOP garbage" that he doesn't like! :D
file13
09-25-2002, 02:13 PM
Originally posted by Stuka
/me can't wait to point out to file13 that the iostreams that he likes about C++ are part of the "OOP garbage" that he doesn't like! :D
:D
i was more gearing that toward people who think OOP is overblown. jah, no classes and no templates = no fancy containers...but you can use the containers (and the iostreams) without knowing anything about OOP. ;)
file13
09-25-2002, 02:17 PM
BTW: example of what i meant below. look at the benifits of C++ over plain ol C .
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
namespace my_lib {
template<class T> void print_vector(const T& v) {
for(unsigned int i = 0; i < v.size(); i++)
std::cout << v[i] << std::endl;
}
}
int main() {
std::string tmp_name_holder;
std::vector<std::string> names;
std::cout << "Enter 3 First Names (no spaces)" << std::endl;
for(int i = 0; i < 3; i++) {
std::cin >> tmp_name_holder;
names.push_back(tmp_name_holder);
}
std::sort(names.begin(), names.end());
std::cout << "Alphabetically, the names are" << std::endl
<< "-----------------------------" << std::endl;
my_lib::print_vector(names);
}
to do something like that in C would take massive amounts of work.
:D
gosper
09-26-2002, 11:24 AM
/me still loves C and wouldnt give it up for C++ ever
vBulletin® v3.7.0, Copyright ©2000-2009, Jelsoft Enterprises Ltd.