understanding call a pointer to a function - c

I am trying to understand what is a pointer to a function in c.
I am wanting some detailed process of calling a pointer to function, thus, i could understand pointer to function better.
Could somebody explain why does my code below not crash and have some wired output?
To narrow down, I am seeking something like javap which could explain how does jdk compile
my code and jvm run my code
what is the relationship of a void return and number 14,15 or 16.
(the void function return)
is there any security problem to my second param or is it same as non-init val ?
test.c
#include <stdio.h>
#include <stdlib.h>
static void f(int x, int y){
printf("x = %d \n", x );
printf("y = %d \n", y );
}
typedef int (*FUNC)(int);
int main(void){
long int addr = (long int)f;
printf("%d \n", (int)((FUNC)addr)(1) );
return 0;
}
output on mac os compiled with i686-apple-darwin11-llvm-gcc-4.2
x = 1
y = 1479046720
16

The answer is undefined behavior. You're using two incompatible function pointer types and use one to call the other. (Not to mention storing the pointer in an integer, etc., etc.) Thus, your program invokes undefined behavior, and as such, anything can happen. And the values you get are most probably just random crap from the messed up stack and/or CPU registers.

You are causing undefined behavior all over the place:
You're storing the function pointer in a integer, which isn't guaranteed to work
You're casting said integer to a different type of function pointer (fewer parameters) with a different return type
You're calling the function with fewer parameters than it expects
You take a return value from a function returning void
Trying to make sense of this is just unreasonable, but as a guess since you're using x86:
x is populated correctly in the function with the 1 you passed
y isn't so it gets a random value, likely some leftover on the stack
there's no return value and you get whatever was left in the AX register
Could somebody explain why does my code below not crash and have some
wired output
Doing the wrong thing isn't guaranteed to crash your program - there are no guarantees.

The value 16 you get back in the last output is PROBABLY the number of characters written by printf - as that's what printf returns, and in this case, nothing else happens after that in the function. But like others have said, you're asking what happens, and nobody can really say - it may not work at all, crash and burn, or give you some "random" values as return and printout - it's not defined anywhere, and if you compile the code with a different compiler, different compiler settings or on a different type of hardware, the results will change.
Each time you run the code, it will most likely give you the same result, but make some changes to the code, and unpredictable results will occur.

To answer the question,
Could somebody explain why does my code below not crash
not all broken code actually crashes. Possibly the parameters (and the return values) of f are passed in registers instead of being pushed onto the stack, and therefore the mismatch between expected values and actual values does not translate into a stack misalignment. If you tried with more arguments, enough to require stack work, you would probably get that crash, or some possibly dangerous behaviour (a similar technique is used in some security exploits, after all).
Then to clarify usage of function pointers, I have taken the liberty of rewriting the code with a couple of comments.
#include <stdio.h>
#include <stdlib.h>
/* We want to be able to print a return value, so we make
f return something - a long, so as to tell it from int
- in order to be able to get something back.
*/
static long f(int x, int y){
printf("x = %d \n", x );
printf("y = %d \n", y );
return x + y;
}
/* We want the signature of a function returning long, and taking
two int's, since this is what f() is.
*/
typedef long (*FUNCPTR)(int, int);
typedef long (FUNC)(int, int);
int main(void)
{
/* We want a pointer to f - it works either way */
FUNCPTR addr = f;
FUNC *addr2 = f;
/* addr points to a function taking two ints, so we must pass it
two ints, and format return as long decimal */
printf("%ld\n", addr(5, 7));
/* addr2 is the same */
printf("%ld\n", addr2(5, 7));
return 0;
}
Expected output:
$ gcc -W -Wall -o test test.c
$ ./test
x = 5
y = 7
12
x = 5
y = 7
12

Related

Why function call only pass the first argument

I'm trying to call a function (on line 15) just via a cast but only the first argument is getting passed, how could I fix it?
I tried to change the float value "2" to 2.0f to declare it's a float and not an int but it's still not working.
!Note that the code is horrible because it's a code golf, the line 15 has to be in a dll form later, this code here is just a test program to avoid launching the target process multiples times. Here's my actual code with a score of 58 chars
DllMain(a,b,c){((int(*)(int,float))927309216)(‭7903472‬,2);}
#include <Windows.h>
#include <stdio.h>
char * sSkelModelStencil = "SkelModelStencil"; //here I reproduce the char like it is in the memory
void SetConsoleFloat(const char *sKey, float fVal) //this is the reproduction of SetConsoleFloat in CShell.dll
{
printf("arg1: %s arg2: %f\n", sKey, fVal); //printing the arguments getting passed into the function
return;
}
int main()
{
while (1) {
SetConsoleFloat("SkelModelStencil", 2); //calling the reproduction function
((int(*)())SetConsoleFloat)(sSkelModelStencil,2); //calling the reproduction function via a cast & using SetConsoleFloat addr
system("PAUSE");
}
}
In some architectures, the way arguments are passed depends on the way they're declared. For instance, special registers may be used for float parameters. It's the declaration of the function type that matters, not the declaration of the argument expression.
The parameter signature () is different from (const char *sKey, float fVal), and as a result the fVal argument is being passed differently from the way the function expects to receive it.
First of all - this is atrocious code, don't do that.
Secondly - compile your code with compiler warnings on, so the compiler can tell you where you might be going wrong. Of course, you need a proper C compiler (which MSVC is not, in case you were using that). gcc will tell you:
a.c:15:10: warning: function called through a non-compatible type
But, to answer your question: You're casting into the wrong type of function: You're using the function type void (); but you need void (const char*, float). So, try:
((void(*)(const char*, float))SetConsoleFloat)(sSkelModelStencil,2);
instead of your existing line 15. It's also a good idea to separate casts from type definitions of functions - for clarity - so you would have:
typedef void (*scf_function_t)(const char*, float);
earlier, and then:
((scf_function_t) SetConsoleFloat)(sSkelModelStencil,2);
but again - there's really no good reason to do any of this in the first place.

C Programming: Explanation of why the pointer is not giving the expected value

I am very new to pointers in C and I am having trouble making sense of this error or a pointer not accessing the memory to store an actual value.
#include <stdio.h>
int main() {
int a;
int *pA = &a;
a = 9;
*pA = 4;
int *pA2 = &a;
printf("pA = %p, *pA = %d, *pA2 = %d\n", *pA, *pA2);
}
In (virtual) reality, shouldn't `pA2 spit out 4 as well? Instead it is giving what looks like a number associated with memory address.
Thanks,
You have left off an argument to printf(). Consider the following:
#include <stdio.h>
int main() {
int a;
int* pA= &a;
a = 9;
*pA = 4;
int* pA2 = &a;
printf("pA=%p, *pA=%d, *pA2=%d\n", (void*) pA, *pA, *pA2);
}
It outputs a memory address, 4, and 4 again. Try it online.
For each % to be substituted, you must pass an extra argument to printf().
When you leave out an argument, the function will try to grab an argument anyway – this leads to undefined behaviour. In your case it managed to take a number (presumably from the stack). It could also crash the program – since the behaviour is undefined, there is no way to consistently predict it.
Also note that I have cast your pointer to a void* for the output – the %p format specifier requires it. Other pointers will work most of the time, but are not guaranteed to. Read more about printf() here.
To help you detect similar and other problems in the future, turn on compiler warnings. In the beginning, these may seem overwhelming, but they are really helpful. See your code compiled with the compiler flags suggested by #Davislor's comment here.
I have added -Werror to these. It forces you to actually deal with the warnings since the compiler won't generate an executable as long as your code generates warnings.
I have also added the same flags to the first link in my answer so you can see it does not generate any warnings.

type conversion in embedded C [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
x is a variable, and its type is int, and I need to convert the type of x from int to long or float. But a simple typecasting (long) x; is not working. Only the following line is working: ((long) &(x)); (I copy it from another parts of the code.)
int x;
(long) x; --> it is not working
*((long*) &(x)); --> it is working
I know what (long) x; means, but...
Could you please describe in detail what *((long*) &(x)); mean exactly? How does it work?
Why it is working and why the simple version not?
It is an embedded code, and I am new in embedded system developing.
main(){
float k;
int i=1, j=2;
k = GetSum(i,j);
}
float GetSum(int x, int y){
float z;
z = *((float*) &(x)) + *((float*) &(y)); /*it is working --> compile with this line*/
z = (float)x + (float)y; /*it is not working --> not compile with this line*/
return z;
}
The type of variables is fixed when they are declared. Type conversion doesn't affect that.
So
int x;
(long)x;
doesn't change the type of x. It converts the value of x to a long. So, if y is of type long.
y = (long)x;
converts the value of x to a value of type long, and stores the result of that conversion in y.
To understand what *((long*) &(x)) does ....
Firstly &(x) computes the address of x (the () are unnecessary). That address is of type int *, since x is of type int.
The (long *) then converts that pointer to be a pointer to long (i.e. a long *)
The * around ((long*) &(x)) then dereferences that long *. This effectively tells the compiler to act as if that memory location which contains an int actually contains a long.
If you then use that, for example;
y = *((long*) &(x)); /* store the value retrieved into y
or
*((long*) &(x)) = 42L; /* treat the memory occupied by x AS IF it is a long,
and write 42L to that memory */
then the result in both cases is formally undefined behaviour. The C standard does not describe any constraints on what happens.
The first treats the memory occupied by x as if it contains a long. The problem is that a long may occupy more memory than an int. A typical symptom in such a case is a garbage value stored in y.
The second writes the value 42L to the memory occupied by x, treating that memory AS IF it contains a long. If long is larger than an int, two common results are program crashes (the program modifying memory past x and the operating system therefore terminating the program) or data poisoning (an unrelated variable in your program, that happens to be located in memory just after x, has its value changed).
If it "seems to work" (however you define "work") with your testing then you are getting lucky - for example, long and int happen to be the same size and same representation WITH YOUR PARTICULAR COMPILER. However, the behaviour is still undefined, anything can actually happen - such as code working with one compiler, but crashing when built with another.
Compile with warnings enabled. The reason for failure must be that you're using an obsolete compiler that supports implicit function declarations that were forbidden by C99, i.e. 18 years ago , and C thinks that it is int GetSum() and since the function actually returns float, your code just has undefined behaviour.
Your function would "work" with the latter, i.e.
z = (float)x + (float)y;
if you changed the return type to int.
Please just stop writing code that uses conventions that belong to Dark Middle Ages. If you use gcc, compile with -std=c99 or -std=c11 or similar, and with -pedantic-errors. The year is 2017 (for a few more days).
int x; is a declaration of a variable; you reserve storage space for it.
Your other lines are not declarations. They are expressions. These expressions can only be used in another expression or in the assignment to another variable, for example:
long l = (long) x;
double d = (double) ((long)x/1234);

Passing float to a function with int argument (that is not declared beforehand)

I have read Garbage value when passed float values to the function accepting integer parameters answers. My question goes a bit deeper. I could have also asked there had I more than 50 reputation point. I am adding my code for more clarification:
#include <stdio.h>
#include <string.h>
void p2(unsigned int tmp)
{
printf("From p2: \n");
printf("tmp = %d ,In hex tmp = %x\n", tmp, tmp);
}
int main()
{
float fvar = 45.65;
p1(fvar);
p2(fvar);
printf("From main:\n");
printf("sizeof(int) = %lu, sizeof(float) = %lu\n", sizeof(int),
sizeof(float));
unsigned int ui;
memcpy(&ui, &fvar, sizeof(fvar));
printf("fvar = %x\n", ui);
return 0;
}
void p1(unsigned int tmp)
{
printf("From p1: \n");
printf("tmp = %d ,In hex tmp = %x\n", tmp, tmp);
}
The output is:
From p1:
tmp = 1 ,In hex tmp = 1
From p2:
tmp = 45 ,In hex tmp = 2d
From main:
sizeof(int) = 4, sizeof(float) = 4
fvar = 4236999a8
Passing a float value to a function that is declared beforehand (i.e. p2) with int arguments gives the correct result. When trying the same with a function that is not declared beforehand (i.e. p1) gives incorrect values. And I know the reason that compiler won't assume any type or arity of arguments for the function not declared before handed. That's why float value does not get typecasted to int in the case of p2.
My confusion is, in the case of p2, how exactly does float value get copied to local int variable tmp.
If it is 'bit by bit copy' than reading those locations should yield something (except 1) in hex at least (if not in integer). But that does not sound the case as output shows. I know that float representation is different.
And how p2 may read registers/stack locations that floats weren't copied to? as simonc suggested in the linked question?
I have included the size of int and float both and my compiler is gcc if that helps.
The C programming language is essentially a single-scan language - a compiler doesn't need to reread the code but it can assemble it line by line, retaining information only on how identifiers were declared.
The C89 standard had the concept of implicit declaration. In absence of a declaration, the function p1 is declared implicitly as int p1(); i.e. a function that returns an int and takes unspecified arguments that go through default argument promotions. When you call such a function giving it a float as an argument, the float argument is promoted to a double, as called for by default argument promotions. It would be fine if the function was int p1(double arg); but the expected argument type is unsigned int, and the return value is not compatible either (void vs int). This mismatch will cause the program to have undefined behaviour - there is no point in reasoning what is happening then. However, there are many old C programs that would fail to compile, if the compilers wouldn't support the archaic implicit declarations - thus you just need to consider all these warnings as errors.
Notice that if you change the return value of p1 into an int, you will get less warnings:
% gcc implicit.c
implicit.c:14:5: warning: implicit declaration of function ‘p1’ [-Wimplicit-function-declaration]
p1(fvar);
^~
But the observed behaviour on my compiler would be mostly the same.
Thus the presence of mere warning: implicit declaration of function ‘x’ is quite likely a serious error in newly written code.
Were the function declared before its use, as is case with p2, then the compiler knows that it expects an unsigned long as the argument, and returns void, and therefore it would know to generate correct conversion code from float to unsigned long for the argument.
The C99 and C11 do not allow implicit function declarations in strictly-conforming programs - but they also do not require a conforming compiler to reject them either. C11 says:
An identifier is a primary expression, provided it has been declared as designating an object (in which case it is an lvalue) or a function (in which case it is a function designator).
and a footnote noting that
Thus, an undeclared identifier is a violation of the syntax.
However, it doesn't require a compiler to reject them.
This,
void p1(unsigned int tmp);
would be implicitly declared as
int p1();
by the compiler.
Although the compiler does not throw an error, it should be considered one as you can read in the linked post.
In any event, this is undefined behavior and you can't expect a predictable output.
In binary level, float and int don't look alike at all.
When trying to copy a float into a int, there's an implicit conversion, that's why when you call a function that takes int as argument but you provide a float you get the integer part of it, but in the final test you get to see how ugly it really look like. That's no garbage, that's how a float looks like in memory if you'd print it in hexadecimal. See IEEE 754 for details.
The issue with p1() however is that you are trying to call a function that has not been declared, so it's automatically declared as int p1(). Even though you later define it as void p1(unsigned int tmp), it has already been declared as int p1() (not taking any parameters) so it doesn't work (behavior is undefined). I'm pretty sure the compiler is screaming with warnings and errors about that, those errors aren't meant to be ignored.
Notice there's a big difference between declaring and defining a function. It is perfectly legal to define a function later, the way you are doing, but if you want it to work properly it has to be declared before any attempt to use it.
Example:
// declare functions
void p1(unsigned int tmp);
void p2(unsigned int tmp);
// use functions
int main()
{
p1(1);
p2(1);
}
// define functions
void p1(unsigned int tmp)
{
// do stuff
}
void p2(unsigned int tmp)
{
// do stuff
}

Extern and global variable

I am unable to understand the weird behaviour of the program. It throws a warning but the output is surprising. I have 3 files, file1.c, file2c, file1.h
file1.c :
#include "file1.h"
extern void func(void);
int main(void)
{
func();
printf("%d\n",var);
return 0;
}
file2.c:
int var;
void func(void)
{
var = 1;
}
and file1.h is :
#include<stdio.h>
extern double var;
When I compile and run, it shows a warning as expected but on printing prints 1. But how is it possible when I am changing the var declared in file2.c
You seem to have undefined behavior -- but one that is probably innocuous on many machines much of the time.
Since your extern declaration says var is a double, when it's actually an int, attempting to access it as a double causes undefined behavior.
In reality, however, in a typical case, a double will be eight bytes, where an int is four bytes. This means when you pass var to printf, 8 bytes of data will be pushed onto the stack (but starting from the four bytes that var actually occupies).
printf will then attempt to convert the first four bytes of that (which does correspond to the bytes of var) as an int, which does match the actual type of var. This is why the behavior will frequently be innocuous.
At the same time, if your compiler was doing bounds checking, your attempt at loading 8 bytes of a four-byte variable could easily lead to some sort of "out of bounds" exception, so your program wouldn't work right. It's just your misfortune that most C compilers don't do any bounds-checking.
It's also possible that (probably on a big-endian machine) instead of the bytes corresponding to var happening to be in the right place on the stack for printf to access them as an int, that the other four bytes that would make up a double will end up in that place, and it would print garbage.
Yet another possibility would be that the bit pattern of the 8 bytes would happen to correspond to some floating point value that would cause an exception as soon as you tried to access it as a floating point number. Given the (small) percentage of bit patterns that correspond to things like signaling NaN's, chances of that arising are fairly small though (and even the right bit pattern might not trigger anything, if the compiler just pushed 8 bytes on the stack and left it at that).
Just setting the type on an extern definition doesn't change the value stored in memory - it only changes how the value is interpreted. So a value of 0x0001 is what is stored in memory no matter how try to interpret it.
Once you've called func() you've stored the value 0x0001 in the location where a is stored. Then in main when a is passed to printf the value stored at location a plus the next 4 bytes (assuming 32bits) is pushed onto the stack. That is the value 0x0001xxxx is pushed onto the stack. But the %d treats the value passed in as an int and will read the first 4 bytes on the stack, which is 0x0001 so it will print 1.
Try changing your code as follows:
file1.c :
#include "file1.h"
extern void func(void);
int main(void)
{
func();
printf("%d %d\n",var);
return 0;
}
file2.c:
int var;
int var2;
void func(void)
{
var = 1;
var2 = 2;
}
and file1.h is :
#include<stdio.h>
extern double var;
You will probably get the output 1 2 (although this depends on how the compiler stores the variables, but it's likely it will store them in adjacent locations)

Resources