let's imagine I have this dynamically allocated 2D array:
//Example of a 3 row * 2 columns int array
int (*arr)[2] = malloc(sizeof(int[3][2]));
However, then I found that if I do:
arr[0][5] = 1;
The compiler does not complain, and at least testing with valgrind, it neither complains. It doesn't unless I try to access to a space which exceeds the size of the allocated space.
I found that the same happens for automatic arrays:
int arr[3][2];
arr[0][5] = 1; //Code works without errors
My question now is: what's the point of having for example declared: int arr[3][2]; if the compiler will accept arr[0][5] = 1; anyway?
I'm using GCC compiler
In general, don't write past the bounds of memory that you've allocated.
Clang will warn about both examples by default, while GCC will warn about neither without the variables actually being used (that's the fault of the dead code eliminator). You can enable the warning with -O2 -Wall -Wextra if the variable is used or is declared volatile.
With GCC and Clang it's sort of "safe" to do this; the same thing will happen each time.
However, this is undefined behavior, so it's a bad idea. It's entirely valid for a program that does this to make your computer grow legs and walk away.
An equivalent way of doing the assignment would be:
arr[2][1] = 1;
This goes based on the assumption that the array elements are stored sequentially in memory.
So, &arr[5][0] is technically the same as &arr[2][1], but it shouldn't be used.
My advice:
int arr[3][2];
int x, y;
for( x = 0; x < 3; x++ )
for( y = 0; y < 2; y++ )
arr[x][y] = x * y;
This is guaranteed to be safe.
In my pc Gcc 8.1.0
#include <stdio.h>
#include <stdlib.h>
int main(){
int i,j;
int (*arr)[2] = malloc(sizeof(int[3][2]));
printf("%p %d %d\n",arr,sizeof(int),sizeof(int[3][2]));
//in my computer print
//00C63E38 4 24
//legal memory from 00C63E38~00C63E4C
for(i=0;i<3;i++){
for(j=0;j<2;j++){
printf("%p ",&arr[i][j]);
}
printf("\n");
}
//00C63E38 00C63E3C
//00C63E40 00C63E44
//00C63E48 00C63E4C
printf("------------------\n");
for(i=0;i<3;i++){
for(j=0;j<2;j++){
printf("%p ",*(arr+i)+j);
}
printf("\n");
}
//00C63E38 00C63E3C
//00C63E40 00C63E44
//00C63E48 00C63E4C
//So arr[i][j] is equel *(arr+i)+j
printf("-------------\n");
for(i=0;i<6;i++){
printf("%p ",arr+i);
printf("\n");
}
printf("-------------\n");
//jump 4*2 pointer address per loop from 00C63E38
//00C63E38
//00C63E40
//00C63E48
//00C63E50
//00C63E58
//00C63E60
for(i=0;i<6;i++){
printf("%p ",arr[0]+i);
printf("\n");
}
//jump 4 pointer address per loop from 00C63E38
//00C63E38
//00C63E3C
//00C63E40
//00C63E44
//00C63E48
//00C63E4C
free(arr);
return 0;
}
Related
When I compile this code :
int main() {
int a = 10;
int *p = &a;
printf("%p",p) // or printf("%p",&a);
return 0;
}
it prints 0022ff38.
Then this code :
int a=10;
int *p =(int *)0x22ff38;
printf("%d",*p); //does not output 10;
should print 10, but it output another thing(2293560).
But when I edit the code, and add a single line :
int main() {
int a = 10;
int *p =(int *)0x22ff38;
printf("%p",&a);
printf("%d",*p); // Now it prints correctly:10
return 0;
}
Every thing is ok!.
Questions:
Why my code does not output a value in first code?
What is usage of this way addressing pointers? is it useful?
Edit :
I have no problem in Linux, because in Linux every time that I run the code, the variable address changes and program output segmentation fault. but in windows address remains the same, and it is expected that manual addressing work in windows.
Compilers are smarter than you think. For example, given this code:
int main() {
int a=10;
int *p =(int *)0x22ff38;
printf("%d",*p);
}
The compiler is going to see that a is never even used. So it will never bother to actually allocate any memory for it.
If you add a printf("%d", a), the compiler might only put a in a register and never in memory.
Fundamentally, you can't assume that two programs will put variables in the same place in memory.
I know sometimes compilers remove unused arrays.
But my question is do the affect on dynamic variables which are allocated using malloc or just the stack variables ?
Is malloc a compile time operation or runtime?
If it is runtime can compiler remove an array which is allocated using malloc or it can only remove the arrays which are fixed size ?
The compiler is allowed to remove malloc and its family because memory allocation is not an observable behavior.
For example, both gcc and clang optimize these functions to just return 42 with -O2:
int foo(){
malloc(10);
return 42;
}
int bar(){
int* p = (int*)malloc(10);
*p = 17;
return 42;
}
int qax(){
int* p = (int*)malloc(10);
*p = 17;
int a = *p + 25;
free(p);
return a;
}
Even a more complex one is successfully optimized to return 42 by clang:
void bar(int* xs){
for (int i = 0; i < 10; i++){
xs[i] = i + 35;
}
}
int foo(){
int* xs = (int*)malloc(40);
bar(xs);
return xs[7];
}
But you should not expect much: such optimizations are unusual and, in general, unreliable.
As you have changed the question:
variables with the external linkage will not be optimized out. Other potentially yes. They are not "removed" - they are optimised out - ie they do not exist in the compiled code
I think it is self explanatory.
#include <stdio.h>
void interrupt();
int main() {
int n = 8;
char c = 'Z';
interrupt();
printf("%d%c\n", n, c);
}
void interrupt() {
printf("Run normally\n");
//ADD CODE...
}
As it stands, this function will output "8Z" regardless of what the interrupt() method does. I am attempting to modify it such that it prints "3Y" without changing anything in the original main function, and only using the interrupt() function (not allowed to pass arguments!). I am allowed to use variables in the interrupt() function, but I am confused to as how you obtain the addresses of 'n' and 'c' without making a global variable, which would defeat the purpose of this question. Since the address of the stack changes every time this runs, there doesn't seem to be a way to do pointer arithmetic (which is what I need to do), and therefore I'm a bit confused and stuck.
Disclaimer: Don't attempt to use this in production code
I took this as a puzzle and proceeded to solve it. You said you are not allowed to modify main. I took the liberty of modifying main slightly -- to print the addresses of n and c.
int main()
{
int n = 8;
char c = 'Z';
printf("%p %p\n", &n, &c);
interrupt();
printf("%d%c\n", n, c);
}
I also modified interrupt a little bit, also to print the values of an address.
void interrupt() {
int i = 10;
char* np = (char*)&i;
char* cp = (char*)&i;
printf("%p %p\n", np, cp);
printf("%p\n", &i);
}
When I ran the program, I got the following output:
0x22cb0c 0x22cb0b
0x22cabc 0x22cabc
0x22cabc
8Z
From the output, I am able to compute the offset between &n in main and &i in interrupt, and the offset between &c in main and &i in interrupt. Now I can manipulate the offset to make np and cp in interrupt to point to n and c in main.
void interrupt() {
int i = 10;
char* np = (char*)&i;
char* cp = (char*)&i;
np += (0x22cb0c - 0x22cabc);
cp += (0x22cb0b - 0x22cabc);
*(int*)np = 3;
*cp = 'Y';
printf("%p %p\n", np, cp);
printf("%p\n", &i);
}
With the changes to interrupt, I get the following output:
0x22cb0c 0x22cb0b
0x22cb0c 0x22cb0b
0x22cabc
3Y
Mission accomplished by changing main a little bit. If you are not allowed to change it at all, you'll have to use a different program to compute the offsets.
By what #Alex Skalozub said, you can get the stack offset and modify the local variables in the calling function.
You can:
1. Study the compiler and OS manual to calculate the stack offset.
Or
2. Write a little function to get it at run-time. Like below.
int get_stack_offset(void)
{
long dummy1;
return dummy_call(&dummy1) + sizeof(dummy1);
}
int dummy_call(int address)
{
long dummy2;
return &dummy2 - address;
}
Then you can just
void interrupt() {
printf("Run normally\n");
int stack_offset = get_stack_offset();
char* c_address = (char*) (&stack_offset - stack_offset);
int* n_address = (int*) (c_address - sizeof(char));
// Then, modify them
*c_address = 'Y';
*n_address = 3;
// Other
// ...
}
*Assuming the stack is increasing. When it is decreasing you need reverse the +/- operator.
*I don't consider about alignment, which maybe you need to.
*And here is a great explanation you can reference.
Does stack grow upward or downward?
As we know, we can use int (*p)[10] to define a pointer which points to an int[10] array, so if we have p=0 and sizeof(int)==4, p+1 will be 0+10*4 = 40, this works because the compiler knows what p is when compiling.
And then what if we do it like this:
int main()
{
int sz = 10;
int (*p)[sz];
}
in other words, nobody would know the sz until the program runs there. I supposed this should not be working, but it does work..
So my question is, how it works? I mean, is there any place that store a value's type in c at runtime? If not, how this could work? Of this is just compiler-related?
I am using gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5), and you can test it with the following code.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
int COL ;
int ROW ;
scanf("%d %d", &COL, &ROW);
int (*p)[COL];
int *mem = (int*)malloc(sizeof(int)*COL*ROW);
memset(mem,0,sizeof(int)*COL*ROW);
p = (int (*)[10])mem;
printf("0x%p\n", p);
printf("COL=%d\n", p+1, (((int)(p+1))-((int)p))/sizeof(int));
mem[2*COL+0] = 1;
printf("%d\n", p[2][0]);
mem[2*COL+5] = 2;
printf("%d\n", p[2][5]);
mem[6*COL+7] = 3;
printf("%d\n", p[6][7]);
p[1][2] = 4;
printf("%d\n", mem[1*COL+2]);
free(p);
return 0;
}
I hope I am not asking a stupid question nor making stupid mistake...
Pointer arithmetic on variable length array types is well defined per 6.5.6:10, which has example code very similar to yours. Per 6.5.3.4:2, when sizeof is applied to a variable length array, the operand is evaluated at runtime to determine the size, so variable length array pointer arithmetic proceeds likewise.
Variable length arrays (6.7.6.2:4) have been part of the standard since the second edition (ISO/IEC 9899:1999 as amended); they are however an optional feature that conformant implementations do not have to support (6.10.8.3).
Consider the following C99 code (that uses the alloca extension.)
void print_int_list(size_t size, int x[size]) {
int y[size];
memcpy(y, x, size * sizeof *x);
for (size_t ii = 0; ii < size; ++ii)
printf("%i ", y[ii]);
printf("\n");
}
void print_int_list_2(size_t size, int x[size]) {
for (size_t ii = 0; ii < size; ++ii)
printf("%i ", x[ii]);
printf("\n");
}
void print_int(int x) {
int * restrict const y = alloca(sizeof x);
memcpy(y, &x, sizeof x);
printf("%d\n", *y);
}
void print_int_2(int x) {
printf("%d\n", *x);
}
In the code print_int is optimized to be exactly the same as print_int_2 on Clang version 3.0 but the function print_int_list is not optimized away to print_int_2. Instead the useless array copy is kept.
This sort of thing is not a problem for most people but it is for me. I intend to prototype a compiler by generating C code for use with Clang, (and later port it to LLVM directly), and I want to generate extremely stupid, simple, and obviously correct code, and let LLVM do the work of optimizing the code.
What I need to know is how one can make Clang optimize away useless array copies so that stupid code like print_int_list will get optimized into code like print_int_list_2.
First, I would go more carefully. There is a step inbetween the two cases that you have, arrays of fixed size. I think nowadays compilers can trace array components that are also indexed with a compile time constant.
Also don't forget that memcpy converts your arrays to pointers to the first element and then makes them void*. So it looses all information.
So I'd go
try fixed sized arrays
don't use memcpy but an assignment loop
and try to losen the constraints from there.