Hi every one : I try to skip instruction
void func(char *str) {
char buffer[24];
int *ret;
strcpy(buffer, str);
}
int main(int argc, char **argv) {
int x;
x = 0;
func(argv[1]);
x = 1;
printf("%d\n”, x);
}
How I can use the pointer *ret defined in funct() to modify the return address for the function in such away I can skip x=1
It's a bad idea to use this in production code! (Reasons copied from dvnrrs' comment.) This is undefined behavior; it is severely abusing (assumed) knowledge about the way the stack is laid out under the hood, and the size of the compiled instructions. This is doomed to failure, especially if optimization is turned on.
Please note that modifying the memory next to local variables this way is incorrect C code, and it makes undefined behavior. I think there is no standard C solution to your problem, so if you want to do that, your best bet is architecture-specific assembly code. The following code happens to work for me in C on i386 with my GCC, but it's still undefined behavior, so it's inherently fragile and can cease to work in any changes in the compiler or in the ABI.
This prints 42 for me:
#include <stdio.h>
void func(char *str) {
(&str)[-1] += 2;
}
int main(int argc, char **argv) {
(void)argc; (void)argv;
int x;
x = 42;
func(argv[1]);
x = 137;
printf("%d\n",x);
return 0;
}
Compile and run on Linux i386:
$ gcc -m32 -W -Wall -s -O0 t.c && ./a.out
42
You can't do this in C; the closest thing would be the setjmp() and longjmp() functions but those won't work for your exact case.
As others pointed out in comments, the best thing to do might be to give your function a return value, and then check that return value in the caller to decide what code to run next. Your sample code seems like a contrived test case so I'm not sure exactly what you're trying to accomplish.
Related
I have read about the evil of returning addresses of stack-based variables, but I am confused with the following case. In the function f I am returning the pointer p which holds the address of i, both of which are local variables. I expected to get some undefined behavior when I call the f function, but the call in the main function returns correctly the value of the local i namely 14. Is this just an accident and itself an undefined behavior, or why am I able to return that address to the outside world of the function?
#include <stdio.h>
char *f()
{
char *p;
char i =14;
p=&i;
return p;
}
int main()
{
printf("%d", *f());
return 0;
}
It is still undefined behavior and it just happens to work here.
The value of i is still on the stack because nothing has overwritten it yet
If you were to run it on a different architecture, or with different compiler settings it might not work.
If you were to do something like this, It no longer returns the correct value.
#include <stdio.h>
char *f()
{
char *p;
char i =14;
p=&i;
return p;
}
void g()
{
int a = 1;
int b = 3;
printf("%d",a+b);
}
int main()
{
char* c = f();
g();
printf("%s", c);
return 0;
}
If undefined behavior was guaranteed to give you wrong results, C programming would be so much easier.
Instead, you get weird behavior like this, where enabling basic optimizations breaks your program (Debian gcc 10.2.0-16):
$ gcc foo.c -o foo && ./foo
14
$ gcc -O foo.c -o foo && ./foo
0
Now your program will probably crash in prod, and any attempt to step through it in a debugger in dev will not show the problem.
I have strange problem, i allocated memory using malloc and returned address of this newly allocated memory. But this address is different before and after return (inside and outside function).
Here is the code (care only about 3 last lines):
char* InfoFile_getValue(char* projectName, char* key)
{
char* returnValue = NULL;
char projectInfoPath[200];
sprintf(projectInfoPath,"projects/%s/info.txt",projectName);
FILE* fp = fopen(projectInfoPath,"r");
if (fp != NULL) {
char* ptr;
size_t len = 0;
char* lineFromFile = NULL;
while(getline(&lineFromFile, &len, fp)!=-1)
{
if (strstr(lineFromFile,key))
{
ptr = lineFromFile + strlen(key);
ptr = ptr + strspn(ptr, ": ");
returnValue = malloc(strlen(ptr)+1);
strcpy(returnValue,ptr);
break;
}
}
free(lineFromFile);
fclose(fp);
}
printf("Inside size: %d\n",sizeof(returnValue));
printf("String address inside function %p\n", returnValue);
return returnValue;
}
And then i call this function using:
char* baseString = InfoFile_getValue(projectName, "base");
printf("Outside size: %d\n",sizeof(baseString));
printf("String address outside function: %p\n",baseString);
printf("%s\n", baseString);
I comipled this using CC and below flags:
pkg-config --cflags gtk+-3.0 -Wno-incompatible-pointer-types
-Wno-int-conversion -Wno-discarded-qualifiers pkg-config --libs gtk+-3.0 -lpthread -lm
And it gives following results:
Inside size: 8
String address inside function 0x5567d9ff4540
Outside size: 8
String address outside function: 0xffffffffd9ff4540
Naruszenie ochrony pamięci (zrzut pamięci)
It looks like it cuts this address to 4 bytes and prefixes it with 0xff, but i have no idea why, i have never came across problem like that. Any suggestions will be helpfull.
You seem to get a sign extension of the lower 32 bits of the address. Just a wild guess, but I think that the compiler saw InfoFile_getValue as a function returning an int while pointers are 64 bits long.
The rule is that a function has to be declared before it is used. If it is not, C assumes that it is declared as int func(), that is a function taking any parameters and returning an int. You should make sure that you have:
char* InfoFile_getValue(char* projectName, char* key);
before the function (maybe main) containing char* baseString = InfoFile_getValue(projectName, "base");
That looks like sign extension, so this very much smells like a C90 implicit int bug. That is, the compiler thinks that the function returns int with the value 0xd9ff4540, which on a 32 bit system is most likely a negative 2's complement number. Then somehow it gets converted to 64 bit because of %p and you get sign extension.
Easiest way to solve it this bug to stop using C90 already, it's bloody 30 years old, broken and dangerous. Getting rid of implicit int alone is reason enough to port your code to standard C.
In case you have to use it, make sure that the function declaration and definition are identical and that the caller can see the function declaration. Then maximize compiler warnings and pay attention to them.
Your experiencing value-truncation and sign-extension due to an ill-prepared caller. I.e. the caller isn't aware of the actual function return type due to lack of proper prototype. This can be aggravating unless you keeping a close watch in C, especially when dealing with a code base that seems to work just fine on platforms where int and void* are the same size.
The simplest case to repro this is below, and documents what must be going on.
main.c
#include <stdio.h>
int main()
{
void *p = foo();
printf("main: p = %p\n", p);
}
foo.c
#include <stdio.h>
void *foo()
{
static int x;
void *p = &x;
printf("foo: p = %p\n", p);
return p;
}
Executing the above code after build for both x86 (where int and void* are the typically the same size) and x64 (where int is typically 32bit and void is 64bit) will expose both the problem and the subtlety of how you can miss this in this former case. Both should exhibit warnings similar to this (which you should be treating as errors anyway)
1>main.c(13): warning C4013: 'foo' undefined; assuming extern returning int
1>main.c(13): warning C4047: 'initializing': 'void *' differs in levels of indirection from 'int'
The results of the run on both platforms (obviously the values here can vary on your system)
x86
foo: p = 00A38138
main: p = 00A38138
x64
foo: p = 00007FF7E7B0C160
main: p = FFFFFFFFE7B0C160
With that you can hopefully see how two things are critical:
Always ensure functions you're calling within your source are properly prototyped before their usage.
Always compile with warnings-as-errors to catch problems like this.
Probably the biggest thing to keep in the back of your head is, by not doing both items above, the code still appears to run fine on x86, and still compiles on x64. The former can lull you into a false sense of accomplishment, and the latter just further confirms that, making hunting down problems like this especially irritating. Let the compiler help you. Make sure (1) and (2) are in your routine.
As it is said that 8 mb of stack is given to each process.
This stack will be used to store local variables.
So if i take an array of size max than of the stack , it must overflow ??
int main()
{
int arr[88388608];
int arr1[88388608];
int arr2[88388608];
while(1);
return 0;
}
But i am unable to get the result !
Welcome to the world of optimizing compilers!
Because of the as-if rule, the compiler is only required to build something that would have same observable results as your original code.
So the compiler if free to:
remove the unused arrays
remove the empty loop
store the dynamic arrays from main outside of the stack - because main is a special function that shall be called only once by the environment
If you want to observe the stack overflow (the bad one, not our nice site :-) ),
you should:
use some code to fill the arrays
compile with all optimization removed and preferently in debug mode to tell the compiler do what I wrote as accurately as you can
The following code does SIGSEGV with CLang 3.4.1 when compiled as cc -g foo.c -o foo
#include <stdio.h>
#define SIZE 88388608
void fill(int *arr, size_t size, int val) {
for (size_t i=0; i<size; i++) {
arr[i] = val;
}
}
int main() {
int arr[SIZE];
int arr1[SIZE];
int arr2[SIZE];
fill(arr, SIZE, 0);
fill(arr1, SIZE, 0);
fill(arr2, SIZE, 0);
printf("%d %d %d\n", arr[12], arr1[15], arr2[18]);
return 0;
}
and even this code works fine when compiled as -O2 optimization level... Compilers are now too clever for me, and I'm not brave enough to thoroughly look at the assembly code which would be the only real way to understand what is actually executed!
When the following code is compiled with LLVM Compiler, it doesn't operate correctly.
(i doesn't increase.)
It operates correctly when compiling with GCC 4.2.
Is this a bug of LLVM Compiler?
#include <stdio.h>
#include <string.h>
void BytesFromHexString(unsigned char *data, const char *string) {
printf("bytes:%s:", string);
int len = (int)strlen(string);
for (int i=0; i<len; i+=2) {
unsigned char x;
sscanf((char *)(string + i), "%02x", &x);
printf("%02x", x);
data[i] = x;
}
printf("\n");
}
int main (int argc, const char * argv[])
{
// insert code here...
unsigned char data[64];
BytesFromHexString(data, "4d4f5cb093fc2d3d6b4120658c2d08b51b3846a39b51b663e7284478570bcef9");
return 0;
}
For sscanf you'd use %2x instead of %02x. Furthermore, %2x indicates that an extra int* argument will be passed. But you're passing an unsigned char*. And finally, sscanf takes a const char* as first argument, so there's no need for that cast.
So give this a try :
int x;
sscanf((string + i), "%2x", &x);
EDIT : to clarify why this change resolves the issue : in your code, sscanf tried to write sizeof(int) bytes in a memory location (&x) that could only hold sizeof(unsigned char) bytes (ie. 1 byte). So, you were overwriting a certain amount of memory. This overwritten memory could very well have been (part of) the i variable.
From the compiler side of things the reason for this code behaving differently is that gcc and llvm (or any other compiler) may lay out the stack differently. You were likely just clobbering something else on the stack before that you didn't need for this example, but with the different layout for the llvm compiler you were clobbering something more useful.
This is another good reason to use stack protectors when debugging a problem (-fstack-protector-all/-fstack-protector). It can help flush out these issues.
I'm experimenting with a piece of C code. Can anyone tell me why is VC 9.0 with SP1 crashing for me? Oh, and the code is meant to be an example used in a discussion why something like
void main (void)
is evil.
struct foo { int i; double d; } main (double argc, struct foo argv)
{
struct foo a;
a.d=0;
a.i=0;
return a.i;
}
If I put
return a;
compiler doesn't crash.
The code gives undefined behavior. This doesn't require the compiler to crash, it just says you've basically broken the rules, so the compiler hasn't done anything wrong, no matter what happens.
Edit: that said, as a quality of implementation issue, it's absolutely true that there's basically never an excuse for the compiler to crash -- reasonably speaking, it should always exit normally, no matter what data you feed it.
Ok you want to pose an esoteric question, then please construct a complete one.
How did you run the test?
What do you mean by crash?
What was your output?
Did you just compile, or compile and link, or compile and link and debug?
How is your compiler configured?
Where are you going with this experiment?
phrases like: "something like" "evil" are not informative enough to be useful
Follow UP:
Instinctively I'll guess that this crash is a consequence of a compiler
optimization switch with which you permit the the compiler to make
certain assumptions that you are not conforming to.
my suppositions:
1- The void main(void) (without ;) is part of a comment you are making, but not
part of the test you submitted.
2- Your program is incorrect, but this is deliberate in order to investigate
the behaviour of the compiler/linker/execution environment.
If this is indeed the case, you need to reduce the complexity of the test case.
Please simplify the test case to the bare minimum it takes to cause a crash.
I can't do it for you, I don't have the correct versions of software
installed, anyway, it's your experiment.
will this crash?
struct foo { int i; double d; };
struct foo main( void)
{
int a=0;
return a;
}
or even this most minimal example?
void * main(void)
{
return 0;
}
of is it this (I doubt it):
int main( double argc, char ** argv)
{
return 0;
}
You get the idea. reduce the crash to it's essence.
Come up with a program that is error free except for the
one thing that will make it crash.
Then report back.
put a semi colon between the end of your structure and main like so:
struct foo { int i; double d; }; main (double argc, struct foo argv)
you could also define a return type for main if your gonna return something:
struct foo { int i; double d; }; int main (double argc, struct foo argv)