How to pass void pointer by reference - c

I want to have a void* as a function parameter and then inside a function modify that pointer (change it to NULL).
Code below doesn't change memory1 to null after function call. How can I change that.
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
void myFree(void**freeMemoryPointer){
/*some code*/
*freeMemoryPointer=NULL;
}
int main(){
void *memory1 = mmap(NULL, getpagesize() , PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);//example
printf("\nCurrent pointer: %p\n", memory1);
myFree(memory1);
printf("\nShould show null: %p\n", memory1);
}
I've also tried this and it works:
myFree((void*)&memory1);
However I need to set void* as a function parameter and not (void*)&void*.

As the question is stated, this is not possible in C.
Passing the value of the pointer memory1 passes a copy of the pointer. The function may use that to access whatever memory1 is pointing at, but it has no way of changing memory1 itself. To do that, the function will need a pointer to memory1, i.e. &memory1.

You could pass the pointer to the pointer to modify it.
void myFree(void**freeMemoryPointer){
/*some code*/
*freeMemoryPointer=NULL;
}
int main(void){
void *memory1 = mmap(NULL, getpagesize() , PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);//example
printf("\nCurrent pointer: %p\n", memory1);
myFree(&memory1);
printf("\nShould show null: %p\n", memory1);
}
Compiles without warning and executes correctly in C & C++ ( https://godbolt.org/z/fPxfY1YEP https://godbolt.org/z/8razoT9MT)

Related

Calling function from dynamic library?

I'm experimenting with using dynamic libraries and C on Linux. The following code will print wrong ouput:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **arg)
{
void *dl = dlopen("./lib.so", RTLD_NOW);
if (!dl) {
fprintf(stderr, "ERROR: %s\n", dlerror());
exit(1);
}
char *ver = dlsym(dl, "show_version");
printf("%s\n", ver);
}
If I make the following change the output will be correct:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **arg)
{
void *dl = dlopen("./lib.so", RTLD_NOW);
if (!dl) {
fprintf(stderr, "ERROR: %s\n", dlerror());
exit(1);
}
char *(*ver)() = dlsym(dl, "show_version");
printf("%s\n", ver());
}
I'm not sure what char *(*ver)() is doing and why it's needed? Can anyone explain?
dlsym(dl, "show_version") returns the address for the symbol show_version. Since show_version is a function, that is the address of the function.
char *ver = dlsym(…); puts that pointer in a char *, which is basically useless. The pointer to a function does not point to bytes that are useful to print. Then printf("%s\n", ver); says to print the bytes that ver points to as if they were a string. But the bytes there are (in a typical C implementation) machine code for the function. They are not the bytes of a character string you want to print.
char *(*ver)() = dlsym(…); defines ver to be a pointer to a function whose arguments are not specified and that returns a char *. To see this:
char something declares something to be a char.
char *something declares something to be a pointer to a char.
char *something() declares something to be a function whose arguments are not specified that returns a pointer to char.
char *(*something)() declares something to a pointer to such a function.
Then, in printf("%s\n", ver());, ver() calls this function. The char * it returns is passed to printf to be printed.
dlsym - obtain address of a symbol in a shared object or executable
This means that when you do dlsym(dl, "show_version"); you are not actually calling the function show_version in your shared library. You obtain the address of that function - which can be used to call the function over and over again.
To "decode" what char *(*ver)() means, you can use what is often called the Clockwise/Spiral Rule
+-----+
| V
char* (*ver) () ver is a
^ ^ | | pointer to
| | | | a function (taking no arguments)
| +-+ | returning char*
| |
+------------+
I assume the above matches the signature of the show_version function that you put in the shared library. Example:
// a function (taking no arguments), returning a char*
char *show_version(void) {
static char version[] = "1.0";
return version;
}
Using the same rule on your first attempt, char* ver:
char* ver
^ | ver is a
| | char*
+----+
You need a pointer to a function (with the correct signature) to be able to call the function and get the result you want. You can't call a char* and when you do printf("%s\n", ver); it'll just start reading the memory at the address (where your function is stored) until it finds a null terminator. You probably see just gibberish.
If you on the other hand have a proper function pointer, you can as you've noticed, call the function it points at with ver() and you get a char* in return which points at the string your dynamically loaded function returned.
You can also use function pointers in your programs without involving shared libraries.
#include <stdio.h>
long foo(short x, int y) {
return x + y;
}
int main() {
long(*foo_ptr)(short, int) = foo;
// foo_ptr is a pointer to a function taking (short, int) as
// arguments and returning a long
printf("%ld\n", foo(1, 2) ); // prints 3
printf("%ld\n", foo_ptr(1, 2) ); // also prints 3
}

Dereferencing void * just as (int) -- standard practice?

I was trying to print a thread's return value and discovered that I'm still quite confused by the notion of double void-pointers.
My understanding was that a void* is a pointer to any datatype that can be dereferenced with an appropriate cast, but otherwise the "levels" of referencing are preserved like with regular typed pointers (i.e. you can't expect to get the same value that you put into **(int **)depth2 by dereferencing it only once like *depth2. ).
In the code (below) that I have scraped together for my thread-return-print, however, it seems that I'm not dereferencing a void pointer at all when I'm just casting it to (int). Is this a case of an address being used as value? If so, is this the normal way of returning from threads? Otherwise, what am I missing??
(I am aware that the safer way to manipulate data inside the thread might be caller-level storage, but I'm quite interested in this case and what it is that I don't understand about the void pointer.)
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *myThread(void *arg)
{
return (void *)42;
}
int main()
{
pthread_t tid;
void *res; // res is itself a void *
pthread_create(&tid, NULL, myThread, NULL);
pthread_join(tid, &res); // i pass its address, so void** now
printf(" %d \n", (int)res); // how come am i able to just use it as plain int?
return 0;
}
First of all, the purpose of pthread_join() is to update the void *
given through its second argument in order to obtain the result of the
thread function (a void *).
When you need to update an int as in scanf("%d", &my_var); the argument
is the address of the int to be updated: an int *.
With the same reasoning, you update a void * by providing a void **.
In the specific situation of your example, we don't use the returned
void * in a normal way: this is a trick!
Since a pointer can be thought about as a big integer counting the bytes in
a very long row, the trick is to assume that this pointer can simply store
an integer value which does no refer to any memory location.
In your example, returning (void *)42, is equivalent to saying
"you will find something interesting at address 42".
But nothing has ever been placed at this address!
Is this a problem? No, as long as nobody tries to dereference this
pointer in order to retrieve something at address 42.
Once pthread_join() has been executed, the variable res has
been updated and contains the returned void *: 42 in this case.
We perform here the reverse-trick by assuming that the information memorised
in this pointer does not refer to a memory location but is a simple integer.
It works but this is very ugly!
The main advantage is that you avoid the expensive cost of malloc()/free()
void *myThread(void *arg)
{
int *result=malloc(sizeof(int));
*result=42;
return result;
}
...
int *res;
pthread_join(tid, &res);
int result=*res; // obtain 42
free(res);
A better solution to avoid this cost would be to use the parameter
of the thread function.
void *myThread(void *arg)
{
int *result=arg;
*result=42;
return NULL;
}
...
int expected_result;
pthread_create(&tid, NULL, myThread, &expected_result);
pthread_join(tid, NULL);
// here expected_result has the value 42

Value of the variable passed as reference gets changed in threads

I wrote this small program for understanding pthread_create and pthread_join but I dont understand why the value of the variable data gets altered after thread_join. Its printed as 0 after the call to pthread functions.
#include <pthread.h>
#include <stdio.h>
void* compute_prime (void* arg)
{
int n = *((int*) arg);
printf("Argument passed is %d\n",n);
return (void *)n;
}
int main ()
{
pthread_t thread;
int data = 5000;
int value=0;
pthread_create (&thread, NULL, &compute_prime, &data);
pthread_join (thread, (void*) &value);
printf("The number is %d and return value is %d.\n", data, value);
return 0;
}
And the output is
Argument passed is 5000
The number is 0 and return value is 5000.
This is because pthread_join has the prototype void **. It expects a pointer to an object of type void *; it modifies this void * object. Now it so happens that you're running on a 64-bit arch, where data and value are both 32 bits, and laid out in memory sequentially. Modifying a void * object that is laid out in memory starting from the address of the int object value clobbers the int object data too, as these are both 32 bits - thus you will see that the data was overwritten. However, this is undefined behaviour so anything might happen.
Don't use casts as they will only serve to hide problems. Casting to a void * is especially dangerous as a void * can be converted to any other type implicitly, even to void **, even though usually it too would be incorrect. If you remove the cast, you most probably will get a warning or an error like
thrtest.c: In function ‘main’:
thrtest.c:16:31: error: passing argument 2 of ‘pthread_join’ from
incompatible pointer type [-Werror=incompatible-pointer-types]
pthread_join (thread, &value);
if compiling with warnings enabled.
If however you really want to do this, you must do it like this:
void *value;
pthread_join(thread, &value);
intptr_t value_as_int = (intptr_t)value;
Though it is not really portable either, as the conversion is implementation-defined.
The most portable way to return an integer is to return a pointer to a mallocated object:
int *return_value = malloc(sizeof (int));
*return_value = 42;
return return_value;
...
void *value;
pthread_join(thread, &value);
int actual = *(int *)value;
free(value);

Modify argument without return

I have a problem in C. I have this function :
int test(void *data);
I want to change data with this function but I don't want another prototype (not use void **). Actualy, data equals null out this function.
#include <stdio.h>
#include <stdlib.h>
int
test(void *data)
{
data = "toto";
return 1;
}
int
main()
{
void *d;
if (test(d) != 1) {
printf("erreur\n");
}
printf("résultat : %s\n", (char *) d); // displays "résultat : (null)"
return 0;
}
Help me please. ;)
In C arguments to function are passed by value. d is passed by value to function test. data is a local variable to function test and d is copied to data. The assignment
data = "toto";
makes pointer data to point to string literal toto, while d is unaffected of this assignment in main function. So, this assignment has no effect on d.
In main you are dereferencing an uninitialized pointer. This will result in undefined behavior.
In your test function, you change data, which doesn't affect d because data is just a local variable. If you really need to change d, then you need to let test return data and do d=test(d).
Moreover, in your test function, the value of data is never used. So what is the point to have data as a parameter of the function?
In printf("résultat : %s\n", (char *) d);, you try to cast d into pointer to char and then print the value of d. Although you don't dereference d, you are still printing a variable that hasn't been initialized, which is undefined behavior.
Any object pointer (i.e. non-function pointer) can be converted to a void * and back to the original type without altering the value. This means that you can pass any kind of (object) pointer to your test() function, it will be automatically converted to a void *, and you can then convert it back inside test().
#include <stdio.h>
int test(void *data)
{
char **s = data;
*s = "toto";
return 1;
}
int main()
{
char *res;
if (test(&res) != 1) {
printf("erreur\n");
}
printf("résultat : %s\n", res);
return 0;
}
You just need to make sure that the test() function knows what the original type was.

Passing pointer to a function and print its value when the function ends

#include <stdio.h>
#include <stdlib.h>
void printPrueba(char * prueba){
prueba = malloc(sizeof("dlkafñlasdjfñlasjdfñlasjdfñlasjdfñljasdlñfjaslñdfjsñladjfñlsadjf"));
sprintf(prueba, "dlkafñlasdjfñlasjdfñlasjdfñlasjdfñljasdlñfjaslñdfjsñladjfñlsadjf");
}
int main(){
char * prueba;
printPrueba(prueba);
printf(prueba);
free(prueba);
}
.
#include <stdio.h>
#include <stdlib.h>
void printPrueba(char * prueba){
prueba = malloc(sizeof("dlkafñlasdjfñlasjdfñlasjdfñlasjdfñljasdlñfjaslñdfjsñladjfñlsadjf"));
sprintf(prueba, "dlkafñlasdjfñlasjdfñlasjdfñlasjdfñljasdlñfjaslñdfjsñladjfñlsadjf");
printf(prueba);
}
int main(){
char * prueba;
printPrueba(prueba);
free(prueba);
}
Why is the second code working fine and the first not?
How can I write the code to "force" it work like the first way?
You are passing the pointer by value.
What it means?
It means that the functions copies the address that the original one is pointing, and then you allocate memory inside the function, but the original function has no idea about this new address.
Imagine the following:
Your original pointer (p1) holds the address 0x2444
Then you pass it by value to the function. What the function does is copy the 0x2444 to a new pointer (p2), then it allocates memory and change the address to 0x5555.
Now p2 points to 0x5555, but p1 still points to 0x2444, So whatever you put on p2 doesn't affect p1, p1 still points to the original location 0x2444.
That's why it's not printing what you expect after the function is finished.
To work the way you expect you can pass the pointer by reference
char**
Or you can return the new pointer from the function to the caller.
This simple change make your code works:
#include <stdio.h>
#include <stdlib.h>
void printPrueba(char ** prueba){
*prueba = malloc(sizeof("dlkafñlasdjfñlasjdfñlasjdfñlasjdfñljasdlñfjaslñdfjsñladjfñlsadjf"));
sprintf(*prueba, "dlkafñlasdjfñlasjdfñlasjdfñlasjdfñljasdlñfjaslñdfjsñladjfñlsadjf");
}
int main(){
char * prueba;
printPrueba(&prueba);
printf(prueba);
free(prueba);
}
And to test the original code to see how both pointers are pointing to a different location you can do this change:
#include <stdio.h>
#include <stdlib.h>
void printPrueba(char* prueba){
printf("P2 BEFORE ALLOC: %p\n", prueba);
prueba = malloc(sizeof("dlkafñlasdjfñlasjdfñlasjdfñlasjdfñljasdlñfjaslñdfjsñladjfñlsadjf"));
sprintf(prueba, "dlkafñlasdjfñlasjdfñlasjdfñlasjdfñljasdlñfjaslñdfjsñladjfñlsadjf");
printf("P2 AFTER ALLOC: %p\n", prueba);
}
int main(){
char * prueba;
printPrueba(prueba);
printf("P1: %p\n", prueba);
printf(prueba);
free(prueba);
}
You can see that both P1 and P2 before alloc points to the same address, but after the allocation they point to completely different addresses.
Memory allocation can be a bit tricky, but hope that those examples help you to understand :)
For first code to work refer the below example.
#include <stdio.h>
#include <stdlib.h>
void printPrueba(char **prueba){
*prueba = malloc(sizeof("dlkafñlasdjfñlasjdfñlasjdfñlasjdfñljasdlñfjaslñdfjsñladjfñlsadjf"));
sprintf(*prueba, "dlkafñlasdjfñlasjdfñlasjdfñlasjdfñljasdlñfjaslñdfjsñladjfñlsadjf");
}
int main(){
char * prueba;
printPrueba(&prueba);
printf(prueba);
free(prueba);
}
Here I am passing the address of the char pointer to the function. So that if in the function I change the value of the pointer it should also change in the caller function.
In your case the arguments to the function is passed using pass by
value, which now would be pass by reference

Resources