snprintf() without format specifier? - c

I am writing a code like this using snprintf():
char myId[10] = "id123";
char duplicateId[10] = "";
snprintf(duplicateId, 10, myId);
As you can see, I am not specifying the format specifier %s explicitly.
Do I need to explicitly specify the format specifier in the above snprintf() statement like this snprintf(duplicateId, 10, "%s", myId);?

No, you don't have to, technically. But it's better practice to do so, because without a constant format string, your format string remains modifiable thus your code will be more prone to format string attacks.
Ah, and also use sizeof(duplicateId) instead of a constant 10 - also for security reasons (in order to avoid future buffer overflows when changing the size of the output buffer of sprintf).

No you dont, but it's generally considered a good idea especially if there's any chance of passing user-input text to snprintf(). If the user enters a string with % in it otherwise, there will be trouble:
const char *userString = "%";
snprintf(duplicateId, sizeof duplicateIt, userString); /* BAD */
const char *userString = "%s";
snprintf(duplicateId, sizeof duplicateIt, "%s", userString); /* GOOD. */

It will be better to use %s since it is more secured... Don't you get a warning for this?
try to compile in the highest warning level, as well.
read more here

Related

print text via pointer

i am learning now c and i come up with this example, where i can print a text using pointers.
#include <stdio.h>
main ()
{
char *quotes = "One good thing about music, when it hits you, you feel no pain. \"Bob Marley\"\n";
printf(quotes);
}
I get a warning from the compiler "format not a string literal and no format arguments" and when I execute the program it runs successfully.I read some other questions here that they had the same warning from the compiler but I didn't find an answer that fits me. I understood the reason why i get this message:
This warning is gcc's way of telling you that it cannot verify the format string argument to the printf style function (printf, fprintf... etc). This warning is generated when the compiler can't manually peek into the string and ensure that everything will go as you intend during runtime...
Case 3. Now this is somewhat your case. You are taking a string generated at runtime and trying to print it. The warning you are getting is the compiler warning you that there could be a format specifier in the string. Say for eg "bad%sdata". In this case, the runtime will try to access a non-existent argument to match the %s. Even worse, this could be a user trying to exploit your program (causing it to read data that is not safe to read).
(See the answer)
but what i have to add in my case to in order to have not warnings from the compiler?
Change it to printf("%s", quotes); which adds the specifier that quotes is a 'string', or array of char.
You need to tell printf what is it that you are printing. %s descriptor will tell printf that you are printing a string.
Format of printf = ("descriptor of what type of data you are printing",variable holding the data);
descriptor for strings is %s, for characters %c, for int %d
Change printf to:
printf("%s",quotes);
You have to specify format string - in simplest form:
char *quotes = "One good thing about music(...)\n";
printf("%s", quotes);
or, you can use format string to decorate output:
char *quotes = "One good thing about music(...)"; // no newline
printf("%s\n", quotes); // newline added here
or, if you don't want to mess with format strings:
char *quotes = "One good thing about music(...)"; // no newline
puts(quotes); // puts() adds newline
or
char *quotes = "One good thing about music(...)\n";
fputs(quotes,stdout);
This warning is gcc's way of telling you that it cannot verify the format string argument to the printf style function (printf, fprintf... etc). This warning is generated when the compiler can't manually peek into the string and ensure that everything will go as you intend during runtime. Lets look at a couple of examples.
So as other suggested explicitly use format specifier to tell the compiler...i.e.
printf("%s",quotes);
You are getting the warning because it is dangerous when the string you are printing contains '%'. In this line it makes no sense for percents but when you want to print this for instance:
int main ()
{
int percent = 10;
char *s = "%discount: %d\n";
printf(s, percent);
return 0;
}
your program will likely crash when printf encounters the second percent and it tries to pop a value from the stack from printf.
When you want to print a percent sign use: "%%discount:"
Try this:
#include <stdio.h>
main ()
{
char *quotes = "One good thing about music, when it hits you, you feel no pain. \"Bob Marley\"\n";
puts(quotes); //Either
printf("%s",quotes);//or
return 0;
}

Secure handling of string variables

Hello I'm quite new to C and in a nutshell I was doing the following as part of my assignment in class:
foo (char *var) {
printf(var);
}
I was told that this is bad practice and insecure but did not get much detailed information on this by my tutor. I assume that if the string value of var is controllable by the user it may be used to perform a bufferoverflow? How would I properly harden this code? Do I have to limit the str length or something?
Cheers & Thanks!
You should use:
printf("%s", var);
instead. The way you have it, I could enter %s as my input, and printf would read a random piece of memory as it looked for a string to print. That can cause any amount of unexpected behaviour.
This is UNSAFE because it could lead to a Format String Attack
Well, the first argument of printf is a format string. So the caller of your function could pass:
foo("%d")
and then printf would look for an integer which isn't there, and cause undefined behaviour. One possible fix would be for your function to call:
printf("%s", var);
which would have printf interpret var as a regular string (rather than a format).
Printf has the following signature:
int printf(
const char *format [,
argument]...
);
If the user inputs format characters for example %s all kinds of bad things will happen.
Use puts if you just want to output the string.

scanf("%[^\n]s",a) vs gets(a)

I have been told that scanf should not be used when user inputs a string. Instead, go for gets() by most of the experts and also the users on StackOverflow. I never asked it on StackOverflow why one should not use scanf over gets for strings. This is not the actual question but answer to this question is greatly appreciated.
Now coming to the actual question. I came across this type of code -
scanf("%[^\n]s",a);
This reads a string until user inputs a new line character, considering the white spaces also as string.
Is there any problem if I use
scanf("%[^\n]s",a);
instead of gets?
Is gets more optimized than scanf function as it sounds, gets is purely dedicated to handle strings. Please let me know about this.
Update
This link helped me to understand it better.
gets(3) is dangerous and should be avoided at all costs. I cannot envision a use where gets(3) is not a security flaw.
scanf(3)'s %s is also dangerous -- you must use the "field width" specifier to indicate the size of the buffer you have allocated. Without the field width, this routine is as dangerous as gets(3):
char name[64];
scanf("%63s", name);
The GNU C library provides the a modifier to %s that allocates the buffer for you. This non-portable extension is probably less difficult to use correctly:
The GNU C library supports a nonstandard extension that
causes the library to dynamically allocate a string of
sufficient size for input strings for the %s and %a[range]
conversion specifiers. To make use of this feature, specify
a as a length modifier (thus %as or %a[range]). The caller
must free(3) the returned string, as in the following
example:
char *p;
int n;
errno = 0;
n = scanf("%a[a-z]", &p);
if (n == 1) {
printf("read: %s\n", p);
free(p);
} else if (errno != 0) {
perror("scanf");
} else {
fprintf(stderr, "No matching characters\n"):
}
As shown in the above example, it is only necessary to call
free(3) if the scanf() call successfully read a string.
Firstly, it is not clear what that s is doing in your format string. The %[^\n] part is a self-sufficient format specifier. It is not a modifier for %s format, as you seem to believe. This means that "%[^\n]s" format string will be interpreted by scanf as two independent format specifiers: %[^\n] followed by a lone s. This will direct scanf to read everything until \n is encountered (leaving \n unread), and then require that the next input character is s. This just doesn't make any sense. No input will match such self-contradictory format.
Secondly, what was apparently meant is scanf("%[^\n]", a). This is somewhat close to [no longer available] gets (or fgets), but it is not the same. scanf requires that each format specifiers matches at least one input character. scanf will fail and abort if it cannot match any input characters for the requested format specifier. This means that scanf("%[^\n]",a) is not capable of reading empty input lines, i.e. lines that contain \n character immediately. If you feed such a line into the above scanf, it will return 0 to indicate failure and leave a unchanged. That's very different from how typical line-based input functions work.
(This is a rather surprising and seemingly illogical properly of %[] format. Personally, I'd prefer %[] to be able to match empty sequences and produce empty strings, but that's not how standard scanf works.)
If you want to read the input in line-by-lane fashion, fgets is your best option.

How to convert int to char/string and vice versa in linux(gcc)?

I want to know the method of converting an integer into char/string and vice-versa also.
I have already used sprintf(&charvar,"%d",&intvar) but it produces wrong output, possibly garbage.
i have also heard atoi() in gcc has bugs.Reference:GCC atoi bug
What is the other method to convert string/char back to int ?
Actually i want to send an integer from one machine to another using SOCK_STREAM .
//EDIT : I forgot to tell that sprintf() does conversion and returns positive value.
If you want to send an integer to another machine you can send it as binary data, just by sending the intvar directly to the stream, you don't have to convert it to a char first. That will only introduce problems with knowing the length of the data as different values generate different lengths of strings.
Please read the manual of 'sprintf' and 'sscanf', and maybe their safer versions are proper for you.
Remove the ampersand before intvar:
sprintf(&charvar,"%d",intvar)
Two notes:
Here, I assume that &charvar is of correct type, which it probably isn't.
Even though it might not make much difference here, it's a good to get into the habit of using snprintf in preference to sprintf.
Here's some example code:
int intvar = ...;
char str[16];
snprintf(str, sizeof(str), "%d", intvar);
You cannot sprintf to a variable. You need a buffer for it, because of possible several digits and the trailing zero. Moreover, the argument should be the int variable, not its address.
Example:
char buffer[256];
int i = 42;
sprintf(buffer, "%d", i);
(buffer will be filled with '4', '2' and trailing '\0').
your sprintf is wrong.You should write sprintf(string,"%d",integer);
If you want to send an integer over the network and thats why you want to convert it into string have a look at htons
with these functions you can convert an integer to network format and avoid different endianness problems!
If you just want to convert it to bytes you can do something like this:
char buf[4];
memcpy(buf,&integer,4);
If you want your string to have the value of the int then you should use sprintf.

string input and output in C

I have this snippet of the code:
char* receiveInput(){
char *s;
scanf("%s",s);
return s;
}
int main()
{
char *str = receiveInput();
int length = strlen(str);
printf("Your string is %s, length is %d\n", str, length);
return 0;
}
I receive this output:
Your string is hellàÿ", length is 11
my input was:
helloworld!
can somebody explain why, and why this style of the coding is bad, thanks in advance
Several questions have addressed what you've done wrong and how to fix it, but you also said (emphasis mine):
can somebody explain why, and why this style of the coding is bad
I think scanf is a terrible way to read input. It's inconsistent with printf, makes it easy to forget to check for errors, makes it hard to recover from errors, and is incompatable with ordinary (and easier to do correctly) read operations (like fgets and company).
First, note that the "%s" format will read only until it sees whitespace. Why whitespace? Why does "%s" print out an entire string, but reads in strings in such a limited capacity?
If you'd like to read in an entire line, as you may often be wont to do, scanf provides... with "%[^\n]". What? What is that? When did this become Perl?
But the real problem is that neither of those are safe. They both freely overflow with no bounds checking. Want bounds checking? Okay, you got it: "%10s" (and "%10[^\n]" is starting to look even worse). That will only read 9 characters, and add a terminating nul-character automatically. So that's good... for when our array size never needs to change.
What if we want to pass the size of our array as an argument to scanf? printf can do this:
char string[] = "Hello, world!";
printf("%.*s\n", sizeof string, string); // prints whole message;
printf("%.*s\n", 6, string); // prints just "Hello,"
Want to do the same thing with scanf? Here's how:
static char tmp[/*bit twiddling to get the log10 of SIZE_MAX plus a few*/];
// if we did the math right we shouldn't need to use snprintf
snprintf(tmp, sizeof tmp, "%%%us", bufsize);
scanf(tmp, buffer);
That's right - scanf doesn't support the "%.*s" variable precision printf does, so to do dynamic bounds checking with scanf we have to construct our own format string in a temporary buffer. This is all kinds of bad, and even though it's actually safe here it will look like a really bad idea to anyone just dropping in.
Meanwhile, let's look at another world. Let's look at the world of fgets. Here's how we read in a line of data with fgets:
fgets(buffer, bufsize, stdin);
Infinitely less headache, no wasted processor time converting an integer precision into a string that will only be reparsed by the library back into an integer, and all the relevant elements are sitting there on one line for us to see how they work together.
Granted, this may not read an entire line. It will only read an entire line if the line is shorter than bufsize - 1 characters. Here's how we can read an entire line:
char *readline(FILE *file)
{
size_t size = 80; // start off small
size_t curr = 0;
char *buffer = malloc(size);
while(fgets(buffer + curr, size - curr, file))
{
if(strchr(buffer + curr, '\n')) return buffer; // success
curr = size - 1;
size *= 2;
char *tmp = realloc(buffer, size);
if(tmp == NULL) /* handle error */;
buffer = tmp;
}
/* handle error */;
}
The curr variable is an optimization to prevent us from rechecking data we've already read, and is unnecessary (although useful as we read more data). We could even use the return value of strchr to strip off the ending "\n" character if you preferred.
Notice also that size_t size = 80; as a starting place is completely arbitrary. We could use 81, or 79, or 100, or add it as a user-supplied argument to the function. We could even add an int (*inc)(int) argument, and change size *= 2; to size = inc(size);, allowing the user to control how fast the array grows. These can be useful for efficiency, when reallocations get costly and boatloads of lines of data need to be read and processed.
We could write the same with scanf, but think of how many times we'd have to rewrite the format string. We could limit it to a constant increment, instead of the doubling (easily) implemented above, and never have to adjust the format string; we could give in and just store the number, do the math with as above, and use snprintf to convert it to a format string every time we reallocate so that scanf can convert it back to the same number; we could limit our growth and starting position in such a way that we can manually adjust the format string (say, just increment the digits), but this could get hairy after a while and may require recursion (!) to work cleanly.
Furthermore, it's hard to mix reading with scanf with reading with other functions. Why? Say you want to read an integer from a line, then read a string from the next line. You try this:
int i;
char buf[BUSIZE];
scanf("%i", &i);
fgets(buf, BUFSIZE, stdin);
That will read the "2" but then fgets will read an empty line because scanf didn't read the newline! Okay, take two:
...
scanf("%i\n", &i);
...
You think this eats up the newline, and it does - but it also eats up leading whitespace on the next line, because scanf can't tell the difference between newlines and other forms of whitespace. (Also, turns out you're writing a Python parser, and leading whitespace in lines is important.) To make this work, you have to call getchar or something to read in the newline and throw it away it:
...
scanf("%i", &i);
getchar();
...
Isn't that silly? What happens if you use scanf in a function, but don't call getchar because you don't know whether the next read is going to be scanf or something saner (or whether or not the next character is even going to be a newline)? Suddenly the best way to handle the situation seems to be to pick one or the other: do we use scanf exclusively and never have access to fgets-style full-control input, or do we use fgets exclusively and make it harder to perform complex parsing?
Actually, the answer is we don't. We use fgets (or non-scanf functions) exclusively, and when we need scanf-like functionality, we just call sscanf on the strings! We don't need to have scanf mucking up our filestreams unnecessarily! We can have all the precise control over our input we want and still get all the functionality of scanf formatting. And even if we couldn't, many scanf format options have near-direct corresponding functions in the standard library, like the infinitely more flexible strtol and strtod functions (and friends). Plus, i = strtoumax(str, NULL) for C99 sized integer types is a lot cleaner looking than scanf("%" SCNuMAX, &i);, and a lot safer (we can use that strtoumax line unchanged for smaller types and let the implicit conversion handle the extra bits, but with scanf we have to make a temporary uintmax_t to read into).
The moral of this story: avoid scanf. If you need the formatting it provides, and don't want to (or can't) do it (more efficiently) yourself, use fgets / sscanf.
scanf doesn't allocate memory for you.
You need to allocate memory for the variable passed to scanf.
You could do like this:
char* receiveInput(){
char *s = (char*) malloc( 100 );
scanf("%s",s);
return s;
}
But warning:
the function that calls receiveInput will take the ownership of the returned memory: you'll have to free(str) after you print it in main. (Giving the ownership away in this way is usually not considered a good practice).
An easy fix is getting the allocated memory as a parameter.
if the input string is longer than 99 (in my case) your program will suffer of buffer overflow (which is what it's already happening).
An easy fix is to pass to scanf the length of your buffer:
scanf("%99s",s);
A fixed code could be like this:
// s must be of at least 100 chars!!!
char* receiveInput( char *s ){
scanf("%99s",s);
return s;
}
int main()
{
char str[100];
receiveInput( str );
int length = strlen(str);
printf("Your string is %s, length is %d\n", str, length);
return 0;
}
You have to first allocate memory to your s object in your receiveInput() method. Such as:
s = (char *)calloc(50, sizeof(char));

Resources