SIGSEGV (Segmentation fault) when passing a structure to callback in C - c

I got some strange behavior of my code.
I can`t pass a structure to the callback function.
#include <malloc.h>
#include "stdint.h"
typedef struct {
int test_rssi;
int setup_rssi;
} test_setup_scan_result;
typedef void (*WifiCallback)(uint8_t);
WifiCallback TestSetupCb;
void resume_configuration(test_setup_scan_result *result) {
if (result == NULL) {
printf("result is NULL\n");
return;
}
printf("result is not NULL\n");
printf("setup_rssi %d\n", result->setup_rssi);
printf("test_rssi %d\n", result->test_rssi);
printf("done");
}
void scan_test_setup_done_cb() {
printf("scan_done\n");
test_setup_scan_result *scan_result = malloc(sizeof(test_setup_scan_result));
printf("created structure\n");
scan_result->test_rssi = 1;
scan_result->setup_rssi = 1;
printf("filled structure\n");
if (TestSetupCb) {
printf("executing cb\n");
printf("setup_rssi %d\n", scan_result->setup_rssi);
printf("test_rssi %d\n", scan_result->test_rssi);
TestSetupCb((uint8_t) scan_result);
}
}
void scan_for_test_setup(WifiCallback cb) {
TestSetupCb = cb;
scan_test_setup_done_cb();
}
int main(void) {
printf("Hello World\n");
scan_for_test_setup((WifiCallback)resume_configuration);
return 0;
}
The code after I am trying to get values of the structure in resume_configuration function just not works. I am the newbie in c language so any links to useful articles are regarded.

Casting a function name to a function pointer type with incompatible parameter types is undefined behavior:
scan_for_test_setup((WifiCallback)resume_configuration);
// ^^^^^^^^^^^^^^
// Undefined behavior
This by itself is enough to get a crash. However, your program does another thing illegally - the call below
TestSetupCb((uint8_t) scan_result);
// ^^^^^^^^^^^
// Does not fit in uint8_t
would fail regardless of the function pointer cast, because a pointer does not fit in 8 bits.

The variable “scan_result” is pointer to struct with allocated memory space in heap region.
When the TestSetupCb() is called with argument “(uint8_t) scan_result” you actually casting address of “scan_result” to be uint8_t, which means to take a first byte of the address and pass it by value. In that case you lose data that you want process in resume_configuration() function.
For example: let’s say the “scan_result” struct it at address “0x004EE388” when you casting this address to uint8_t the result is “0x00000088” this address is invalid and creates issue in your program. Also, this kind of operation creates dangerous to your program.
To solve your problem just re-define function pointer in the following way:
typedef void(*WifiCallback)( test_setup_scan_result *);
and update your code: instead of TestSetupCb((uint8_t)scan_result); change to TestSetupCb(scan_result);

I have run it in Valgrind and I have identified a blatant error (which manifests in several places):
resume_configuration does not obey the WifiCallback pointer type; it takes a parameter of pointer type, not of uint8_t type which most likely has a different size (and it indeed has)
You call TestSetupCb((uint8_t) scan_result); -- you explicitly convert the scan_result pointer to a datatype smaller than a pointer. You have truncated a pointer, so now the result cannot be converted back into a valid pointer. The truncation on Intel systems is so bad, any resulting pointer will always be in the NULL page.

Related

Dereferencing NULL pointer warning in C even it is assigned already

I am trying to implement a unit cache structure and use calloc method(dynamic allocation) to give it memory space. I used the type-defined cache_unit as the type of the pointer to receive casted return type from calloc. Normally after calloc, all the bits in the allocated area should be 0. However my output is like random numbers instead of 0 and there're two warning messages.
Here's my code:
#include<stdio.h>
#include<stdlib.h>
#include <cstdint>
int main() {
typedef struct {
bool enabled;
uint8_t block[10];
int access_time;
} cache_unit;
cache_unit* cache = (cache_unit*) calloc(2, sizeof(cache_unit));
printf("%x ", *cache);
return 0;
}
Here are the warning messages on printf:
With printf("%x ", *cache);, "%x" expects a matching unsigned, not a cache_unit.
Try
printf("%d\n", cache->access_time);

Accessing struct element straight from function call in C

I don't fully understand if it's normal to get struct element straight from function call which returns struct (or pointer to struct) like in the following lines of code:
function().num
ptr_function(&var)->num
Below is code example I wrote which compiles and runs without any issues on my system.
#include <string.h>
#include <stdio.h>
#define LEN 32
typedef struct
{
int num;
char str[LEN];
} myType;
myType function( void )
{
myType var;
var.num = 10;
strncpy( var.str, "Hello!", LEN );
return var;
}
myType* ptr_function( myType* var )
{
var->num = 20;
strncpy( var->str, "Hello ptr!", LEN );
return var;
}
int main()
{
/* 1st example */
printf( "%d %s\n", function().num, function().str );
/* 2nd example */
myType var;
printf( "%d %s\n", ptr_function(&var)->num, ptr_function(&var)->str );
return 0;
}
And it returns the following:
10 Hello!
20 Hello ptr!
So my question is: Are there any issues or undefined behaviour which will arise from doing the following in c99 or c11?
function().num
ptr_function(&var)->num
Your example is technically correct and safe.
Do note that function() or ptr_function(&var) gets called twice. For some functions, that might not be desirable! And if you had different function calls such as outer(function1().value, function2().value), the order of the two function calls is not specified, so that could cause nasty surprises if they have interacting side effects.
Another possible catch to the pointer version of the pattern: If a function returns a pointer to allocated memory and expects the caller to free it, immediately using the return value result means the caller isn't keeping that pointer value and can't actually free it later.
[For a case like that, the code could still do:
someType *ptr;
outer_func((ptr = allocating_func())->field);
// ...
free(ptr);
but this is getting pretty strange and difficult to read. And since you need to declare ptr anyway, why not initialize it on the same line?]
This isn't an issue with the given example since the pointer actually points at var in main, so it doesn't need to be freed and is still valid when the -> operator is evaluated.

Defining a struct as a global variable

I am trying to define a pointer to a struct as a global variable and access the value of its variables in different functions. But I realized that the values are cleared after the next function call. Am I doing something wrong?
struct St {
double* varDouble;
};
struct St* StGlobal;
void Fun1(){
double initDouble[2][1] = {{1},{2}};
StGlobal = (struct St*)malloc(sizeof(struct St));
StGlobal->varDouble = *initDouble;
};
void Func2(){
for (i =0;i<2;i++){
printf("%d\n", StGlobal->varDouble);
}
};
int main(){
Func1();
Func2(); // value of StGlobal->varDouble is no longer what was assigned to it in Func1
};
void Fun1(){
double initDouble[2][1] = {{1},{2}};
StGlobal = (struct St*)malloc(sizeof(struct St));
// OK. StGlobal points to a memory that was returned by malloc.
// The memory will be valid after the function returns.
StGlobal->varDouble = *initDouble;
// Not OK. initDouble is a local 2D array. *initDouble is a pointer
// that is valid as long as initDouble is in scope. When the function
// returns the pointer is not valid.
};
And
void Func2(){
for (i =0;i<2;i++){
printf("%d\n", StGlobal->varDouble);
// StGlobal->varDouble is dangling pointer.
// Also, you are printing a pointer using %d. ???
// If you try to access the pointer here, the program will exhibit
// undefined behavior since it is a dangling pointer.
}
};
After you allocate memory for StGlobal, you'll have to:
Allocate memory for StGlobal->varDouble also using malloc, or
Assign it to some other pointer that will be valid after the function returns.
Also. Don't cast the return value of malloc in C. See Do I cast the result of malloc?.
Additional info
You can force MSVC to treat a file as a C program file by setting a compiler option. In VS2008, I can do that in the following dialog box.
There is probably a similar way to change the setting in MSVC 2010.

C: Passing array to pointer function

I'm not sure if the question has asked before, but I couldn't find any similar topics.
I'm struggeling with the following piece of code. The idea is to extend r any time later on without writing lots of if-else statements. The functions (func1, func2...) either take zero or one arguments.
void func1() {
puts("func1");
}
void func2(char *arg){
puts("func2");
printf("with arg %s\n", arg);
}
struct fcall {
char name[16];
void (*pfunc)();
};
int main() {
const struct fcall r[] = {
{"F1", func1},
{"F2", func2}
};
char param[] = "someval";
size_t nfunc = RSIZE(r); /* array size */
for(;nfunc-->0;) {
r[nfunc].pfunc(param);
}
return 0;
}
The code above assumes that all functions take the string argument, which is not the case. The prototype for the pointer function is declared without any datatype to prevent the incompatible pointer type warning.
Passing arguments to functions that do not take any parameters usually results in too few arguments. But in this case the compiler doesn't 'see' this ahead, which also let me to believe that no optimization is done to exclude these unused addresses from being pushed onto the stack. (I haven't looked at the actual assemble code).
It feels wrong someway and that's usually a recipe for buffer overflows or undefined behaviour. Would it be better to call functions without parameters separately? If so, how much damage could this do?
The way to do it is typedef a function with 1 argument, so the compiler could verify if you pass the correct number of arguments and that you do not pass something absolutely incompatible (e.g. a struct by value). And when you initialize your array, use this typedef to cast function types.
void func1(void) { ... }
void func2(char *arg) { ... }
void func3(int arg) { ... }
typedef uintptr_t param_t;
typedef void (*func_t)(param_t);
struct fcall {
char name[16];
func_t pfunc;
};
const struct fcall r[] = {
{"F1", (func_t) func1},
{"F2", (func_t) func2}
{"F3", (func_t) func3}
};
...
r[0].pfunc((param_t) "foo");
r[1].pfunc((param_t) "bar");
r[2].pfunc((param_t) 1000);
Here param_t is defined as uintpr_t. This is an integer type big enough to store a pointer value. For details see here: What is uintptr_t data type.
The caveat is that the calling conventions for param_t should be compatible with the function arguments you use. This is normally true for all integer and pointer types. The following sample is going to work, all the type conversions are compatible with each other in terms of calling conventions:
// No problem here.
void ptr_func(struct my_struct *ptr) {
...
}
...
struct my_struct struct_x;
((func_t) &ptr_func)((param_t) &struct_x);
But if you are going to pass a float or double argument, then it might not work as expected.
// There might be a problem here. Depending on the calling
// conventions the value might contain a complete garbage,
// as it might be taken from a floating point register that
// was not set on the call site.
void float_func(float value) {
...
}
...
float x = 1.0;
((func_t) &float_func)((param_t) x);
In this case you might need to define a function like this:
// Problem fixed, but only partially. Instead of garbage
// there might be rounding error after the conversions.
void float_func(param_t param) {
float value = (float) param;
...
}
...
float x = 1.234;
((func_t) &float_func)((param_t) x);
The float is first being converted to an integer type and then back. As a result the value might be rounded. An obvious solution would be to take an address of x and pass it to modified a function float_func2(float *value_ptr). The function would dereference its pointer argument and get the actual float value.
But, of course, being hardcore C-programmers we do not want to be obvious, so we are going to resort to some ugly trickery.
// Problem fixed the true C-programmer way.
void float_func(param_t param) {
float value = *((float *) &param);
...
}
...
float x = 1.234;
((func_t) &float_func)(*((param_t *) &x));
The difference of this sample compared to passing a pointer to float, is that on the architecture (like x86-64) where parameters are passed on registers rather than on the stack, a smart enough compiler can make float_func do its job using registers only, without the need to load the parameter from the memory.
One option is for all the functions accept a char * argument, and your calling code to always pass one. The functions that don't need an argument need not use the argument they receive.
To be clean (and avoid undefined behaviour), if you must have some functions that accept no argument and some functions that accept an argument, use two lists and register/call each type of function separately.
If the behaviour is undefined there's no telling how much damage could be caused.
It might blow up the planet. Or it might not.
So just don't do it, OK?

Problem with the following code

I want to the know the problems with the code presented below. I seem to be getting a segmentation fault.
void mallocfn(void *mem, int size)
{
mem = malloc(size);
}
int main()
{
int *ptr = NULL;
mallocfn(ptr, sizeof(ptr));
*ptr = 3;
return;
}
Assuming that your wrapper around malloc is misnamed in your example (you use AllocateMemory in the main(...) function) - so I'm taking it that the function you've called malloc is actually AllocateMemory, you're passing in a pointer by value, setting this parameter value to be the result of malloc, but when the function returns the pointer that was passed in will not have changed.
int *ptr = NULL;
AllocateMemory(ptr, sizeof(ptr));
*ptr = 3; // ptr is still NULL here. AllocateMemory can't have changed it.
should be something like:
void mallocfn(void **mem, int size)
void mallocfn(int **mem, int size)
{
*mem = malloc(size);
}
int main()
{
int *ptr = NULL;
mallocfn(&ptr, sizeof(ptr));
*ptr = 3;
return;
}
Because you need to edit the contents of p and not something pointed b p, so you need to send the pointer variable p's address to the allocating function.
Also check #Will A 's answer
Keeping your example, a proper use of malloc would look more like this:
#include <stdlib.h>
int main()
{
int *ptr = NULL;
ptr = malloc(sizeof(int));
if (ptr != NULL)
{
*ptr = 3;
free(ptr);
}
return 0;
}
If you're learning C I suggest you get more self-motivated to read error messages and come to this conclusion yourself. Let's parse them:
prog.c:1: warning: conflicting types for built-in function ‘malloc’
malloc is a standard function, and I guess gcc already knows how it's declared, treating it as a "built-in". Typically when using standard library functions you want to #include the right header. You can figure out which header based on documentation (man malloc).
In C++ you can declare functions that have the same name as already existing functions, with different parameters. C will not let you do this, and so the compiler complains.
prog.c:3: warning: passing argument 1 of ‘malloc’ makes pointer from integer without a cast
prog.c:3: error: too few arguments to function ‘malloc’
Your malloc is calling itself. You said that the first parameter was void* and that it had two parameters. Now you are calling it with an integer.
prog.c:8: error: ‘NULL’ undeclared (first use in this function)
NULL is declared in standard headers, and you did not #include them.
prog.c:9: warning: implicit declaration of function ‘AllocateMemory’
You just called a function AllocateMemory, without telling the compiler what it's supposed to look like. (Or providing an implementation, which will create a linker error.)
prog.c:12: warning: ‘return’ with no value, in function returning non-void
You said that main would return int (as it should), however you just said return; without a value.
Abandon this whole idiom. There is no way to do it in C without making a separate allocation function for each type of object you might want to allocate. Instead use malloc the way it was intended to be used - with the pointer being returned to you in the return value. This way it automatically gets converted from void * to the right pointer type on assignment.

Resources