Is there anything you could supply to the atoi function that would produce an error (that may or may not crash the program)?
EDIT: An error is defined as anything that would produce a compilation error, or something that would cause the program to terminate during execution.
anything that would produce a compilation error
If the argument you supply to atoi() is of an incompatible type, you'll get a compile-time error.
something that would cause the program to terminate during execution
If you supply atoi() with an invalid const char* pointer, the behaviour of your code will be undefined. While nothing is guaranteed, if the pointer is NULL or points to unreadable memory the program will likely terminate (this depends on the OS and the hardware architecture).
I suspect the question is more along the lines of 'do I have to sanitize the input from a source I dont trust before passing it to atoi?'
The behavior of a correctly written atoi function is specified for most cases. It will convert characters to numbers until it hits something non numeric and then stop. However atoi is considered vulnerable to overflows
You should use strtol instead; its spec is tighter
Of course the implementation in your c runtime could be broken - but then there is not a lot you can do about that
Related
What if we just give format string in printf statement in c like:
printf("%d, %d, %d",a, b);
What does the third %d give In answer?
I did it but not able to understand the output of the code.
The third %d gives in answer undefined behavior because there is no corresponding argument.
From the C Standard (7.21.6.1 The fprintf function)
9 If a conversion specification is invalid, the behavior is
undefined.275) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
Pay attention to that the name of the standard function is printf not Printf.
In C, functions that take variadic arguments (i.e. the ... parameter) have no way of knowing beforehand the number or type of the arguments. They must be kept track of in some way. A separate length parameter is one way, but the printf-family functions use the number of format specifiers in the format string to keep track.
If you tell the function "hey, there's a third parameter" when you don't pass one, this is undefined behavior. Anything can happen. It may appear to not print anything. It may read a garbage value from the memory location or the register where it expects to find the value. It may crash.
Reasoning about what might happen when your code invokes undefined behavior is a waste of time. Just make sure your code is free of it.
You've told printf to expect 3 additional int arguments, but only passed 2. It's going to look for that third int argument somewhere, and depending on how printf is implemented on your system, you may get a runtime error, or you may see garbage output, or you may see no output, or something entirely different may happen.
Officially, the behavior is left undefined - neither the compiler nor the runtime environment the program is executing in are required to handle the situation in any particular way. The result isn't guaranteed to be predictable or repeatable.
There is no "should" here - any result is "correct" as far as the language definition is concerned.
According to my knowledge and some threads like this, if you want to print strings in C you have to do something like this:
printf("%s some text", value);
And the value will be displayed instead of %s.
I wrote this code:
char password[] = "default";
printf("Enter name: \n");
scanf("%s", password);
printf("%s is your password", password); // All good - the print is as expected
But I noticed that I can do the exact same thing without the value part and it will still work:
printf("%s is your password");
So my question is why does the %s placeholder get a value without me giving it one, and how does it know what value to give it?
This is undefined behavior, anything can happen included something that looks like correct. But it is incorrect.
Your compiler can probably tell you the problem if you use correct options.
Standard says (emphasized is mine):
7.21.6.1 The fprintf function
The fprintf function writes output to the stream pointed to by stream,
under control of the string pointed to by format that specifies how
subsequent arguments are converted for output. If there are
insufficient arguments for the format, the behavior is undefined. If
the format is exhausted while arguments remain, the excess arguments
are evaluated (as always) but are otherwise ignored. The fprintf
function returns when the end of the format string is encountered.
The printf() function uses a C language feature that lets you pass a variable number of arguments to a function. (Technically called 'variadic functions' - https://en.cppreference.com/w/c/variadic - I'll just say 'varargs' for short.)
When a function is called in C, the arguments to the function are pushed onto the stack(*) - but the design of the varargs feature provides no way for the called function to know how many parameters were passed in.
When the printf() function executes, it scans the format string, and the %s tells it to look for a string in the next position in the variable argument list. Since there are no more arguments in the list, the code 'walks off the end of the array' and grabs the next thing it sees in memory. I suspect what's happening is that the next location in memory still has the address of password from your prior call to scanf, and since that address points to a string, and you told printf to print a string, you got lucky, and it worked.
Try putting another function call (for example: printf("%s %s %s\n","X","Y","Z") in between your call to scanf("%s", password); and printf("%s is your password"); and you will almost certainly see different behavior.
Free Advice: C has a lot of sharp corners and undefined bits, but a good compiler (and static analysis or 'lint' tool) can warn you about a lot of common errors. If you are going to work in C, learn how to crank your compiler warnings to the max, learn what all the errors and warnings mean (as they happen, not all at once!) and force yourself to write C code that compiles without any warnings. It will save you a lot of unnecessary hassle.
(*) generalizing here for simplicity - sometimes arguments can be passed in registers, sometimes things are inlined, blah blah blah.
So, there are a lot of posts telling that you shouldn't do printf("%s is your password");, and that you were just lucky. I guess from your question that you somewhat knew that. But few are telling you the probable reason for why you were lucky.
To understand what probably happened, we have to understand how function parameters are passed. The caller of a function must put the parameters on an agreed upon place for the function to find the parameters. So for parameters 1...N we call these places r1 ... rN. (This kind of agreement is part of something we call a "Function Calling Convention")
That means that this code:
scanf("%s", password);
printf("%s is your password",password);
may be turned into this pseudo-code by the compiler
r1="%s";
r2=password;
call scanf;
r1="%s is your password";
r2=password;
call printf;
If you now remove the second parameter from the printf call, your pseudo-code will look like this:
r1="%s";
r2=password;
call scanf;
r1="%s is your password";
call printf;
Be aware that after call scanf;, r2 might be unmodified and still be set to password, therefore call printf; "works"
You might think that you have discovered a new way to optimize code, by eliminating one of the r2=password; assignments. This might be true for old "dumb" compilers, but not for modern ones.
Modern compilers will already do this when it is safe. And it is not always safe. Reasons for why it isn't safe might be thatscanf and printf have different calling conventions, r2 might have been modified behind your back, etc..
To better get a feeling of what the compiler is doing, I recommend to look at the assembler output from your compiler, at different optimization levels.
And please, always compile with -Wall. The compiler is often good at telling you when you are doing dumb stuff.
I am not sure why strcat works in this case for me:
char* foo="foo";
printf(strcat(foo,"bar"));
It successfully prints "foobar" for me.
However, as per an earlier topic discussed on stackoverflow here: I just can't figure out strcat
It says, that the above should not work because foo is declared as a string literal. Instead, it needs to be declared as a buffer (an array of a predetermined size so that it can accommodate another string which we are trying to concatenate).
In that case, why does the above program work for me successfully?
This code invokes Undefined Behavior (UB), meaning that you have no guarantee of what will happen (failure here).
The reason is that string literals are immutable. That means that they are not mutable, and any attempt of doing so, will invoke UB.
Note what a difficult logical error(s) can arise with UB, since it might work (today and in your system), but it's still wrong, which makes it very likely that you might miss the error, and get along as everything was fine.
PS: In this Live Demo, I am lucky enough to get a Segmentation fault. I say lucky, because this seg fault will make me investigate and debug the code.
It's worth noting that GCC issues no warning, and the warning from Clang are also irrelevant:
p
rog.c:7:8: warning: format string is not a string literal (potentially insecure) [-Wformat-security]
printf(strcat(foo,"bar"));
^~~~~~~~~~~~~~~~~
prog.c:7:8: note: treat the string as an argument to avoid this
printf(strcat(foo,"bar"));
^
"%s",
1 warning generated.
String literals are immutable in the sense that the compiler will operate under the assumption that you won't mutate them, not that you'll necessarily get an error if you try to modify them. In legalese, this is "undefined behavior", so anything can happen, and, as far as the standard is concerned, it's fine.
Now, on modern platforms and with modern compilers you do have extra protections: on platforms that have memory protection the string table generally gets placed in a read-only memory area, so that modifying it will get you a runtime error.
Still, you may have a compiler that doesn't provide any of the runtime-enforced checks, either because you are compiling for a platform without memory protection (e.g. pre-80386 x86, so pretty much any C compiler for DOS such as Turbo C, most microcontrollers when operating on RAM and not on flash, ...), or with an older compiler which doesn't exploit this hardware capability by default to remain compatible with older revisions (older VC++ for a long time), or with a modern compiler which has such an option explicitly enabled, again for compatibility with older code (e.g. gcc with -fwritable-strings). In all these cases, it's normal that you won't get any runtime error.
Finally, there's an extra devious corner case: current-day optimizers actively exploit undefined behavior - i.e. they assume that it will never happen, and modify the code accordingly. It's not impossible that a particularly smart compiler can generate code that just drops such a write, as it's legally allowed to do anything it likes most for such a case.
This can be seen for some simple code, such as:
int foo() {
char *bar = "bar";
*bar = 'a';
if(*bar=='b') return 1;
return 0;
}
here, with optimizations enabled:
VC++ sees that the write is used just for the condition that immediately follows, so it simplifies the whole thing to return 0; no memory write, no segfault, it "appears to work" (https://godbolt.org/g/cKqYU1);
gcc 4.1.2 "knows" that literals don't change; the write is redundant and it gets optimized away (so, no segfault), the whole thing becomes return 1 (https://godbolt.org/g/ejbqDm);
any more modern gcc choose a more schizophrenic route: the write is not elided (so you get a segfault with the default linker options), but if it succeeded (e.g. if you manually fiddle with memory protection) you'd get a return 1 (https://godbolt.org/g/rnUDYr) - so, memory modified but the code that follows thinks it hasn't been modified; this is particularly egregious on AVR, where there's no memory protection and the write succeeds.
clang does pretty much the same as gcc.
Long story short: don't try your luck and tread carefully. Always assign string literals to const char * (not plain char *) and let the type system help you avoid this kind of problems.
What will be the output of printf("%d"); or printf("%p"); statement?
Of course I know that I should pass argument as printf is expecting one but assuming that I will leave this empty what will happen?
I know that this will print some value read from stack (from the place where function argument should be placed). Assuming that I am running Linux machine can I expect that this will be some valid value (e.g. function return address)?
This is simply undefined behaviour. Anything could happen. It's impossible to give a more accurate answer.
The details depend on how printf is implemented by the library, and how variable arguments are implemented by your compiler. Look at the source of the library and/or the generated assembly to find out what's happening on your platform.
This invokes undefined behavior. By its very nature, this means you can't assume anything about what will happen.
This provokes undefinded behaviour. You might get printed out a random integer or a crash or ...
Undefined behavior. Which means your program can for example crash.
(C99, 7.19.6.1p2) "If there are insufficient arguments for the format, the behavior is
undefined."
can I expect that this will be some valid value? : NO.
I am having a compilation error on the following code:
printf((char *) buffer);
and the error message that I am getting is:
cc1: format not a string literal and no format arguments...
I suspect there are some libraries that I forgot to install, as I was able to compile and run the code without an error on the other machine...
PS: The question rises with the fact that I was able to run the same code on some other machine... I suspect a difference in gcc version might cause a problem like this?
Newer GCC versions try to parse the format string passed to printf and similar functions and determine if the argument list correctly matches the format string. It can't do this because you've passed it a buffer for the first argument, which would normally be a format string.
Your code is not incorrect C, it's just a poor usage of C. As others mentioned you should use "%s" as a format string to print a single string. This protects you from a class of errors that involve percentage signs in your string, if you don't control the input. It's a best practice to never pass anything but a string literal as the first argument to the printf or sprintf family of functions.
try
printf("%s", (char*) buffer);
;-)
This warning is generated by gcc if
-Wformat-nonliteral
is set. It's not part of -Wall or -Wextra (at least for version 4.4.0), so just drop it if you want the code to compile warning-free.
This is a warning for your safety, not an error. This new compiler is apparently being more strict about it. I don't think it's actually illegal in C, so the compiler should have an option to disable treating this as an error.
However, you pretty much never want to pass anything other than a string literal as the first argument to printf. The reason that doing so is such a horrible idea that the compiler has a special built-in check to warn you about it is this: Suppose the non-literal string that you pass as the first argument to printf happens to contain printf formatting characters. printf is then going to try to access second, third, fourth, etc, arguments that you didn't actually pass in, and may well crash your program by trying to do so. If the non-literal first argument is actually user-supplied, then the problem is even worse since a malicious user could crash your program at will.