So I'm writing a bill handling system. The data currently sits in a Stack structure that I've written.
I have this partially written function that writes out a report:
void GenerateReport(Bill* bill)
{
PrintBillHeading(bill);
//CallEntry* collatedEntries = CollapseCallStack(bill->callEntries);
//TODO
}
Which works fine as long as I leave the second line commented out. If I uncomment it I get a SIGSEGV fault within the PrintBillHeading() function where indicated below.
void PrintBillHeading(Bill* bill)
{
printf("Big Brother Telecom\n");
printf("Bill Date: %s\n\n",DateTimeToISOString(bill->date));
printf("Contract Holder: %s %s\n", bill->title, bill->name);
printf("Address:\n");
char* addressSeg;
char* addressCpy;
strcpy(addressCpy,bill->address); //This line throws the SIGSEGV
while ((addressSeg = strtok_r(addressCpy,";",&addressCpy)))
{
printf("%s\n\0",addressSeg);
}
}
and for completeness here is my CollapseCallStack() function, this is uncomplete, entirely untested and probably doesn't work.
CallEntry* CollapseCallStack(Stack* calls)
{
int size = calls->topIndex;
CallEntry* collatedSet = malloc(sizeof(CallEntry) * size);
CallEntry* poppedCall;
int curIndex = 0;
while (PopStack(calls,poppedCall))
{
bool found = false;
for (int i = 0; i < size; i++)
{
CallEntry* arrItem = collatedSet + i * sizeof(CallEntry);
if (StringEquals(arrItem->phoneNumber,poppedCall->phoneNumber))
{
found = true;
arrItem->minutes += poppedCall->minutes;
}
}
if (!found)
{
memcpy(collatedSet,poppedCall,sizeof(CallEntry)); //
}
}
}
And the CallEntry struct:
typedef struct{
char* phoneNumber;
int minutes;
DateTime* callDateTime;
} CallEntry;
My question is this: how can a function that hasn't yet been called cause a SIGSEGV fault to be expressed earlier on in a program?
Once I've got past this, I can debug the CollapseCallStack() function myself, although if anyone sees any glaring problems I would appreciate a comment on that.
In function PrintBillHeading(), the statement strcpy(addressCpy,bill->address) uses the value of an uninitialized variable addressCpy. This is undefined behavior. Undefined behavior means that the program may crash in any random place. If the program contains undefined behavior the entire program is invalid.
In addition to the correct answer by AlexP, I'd like to point out another (lurking) undefined behaviour:
void GenerateReport(Bill* bill)
{
PrintBillHeading(bill);
CallEntry* collatedEntries = CollapseCallStack(bill->callEntries);
//TODO
}
Now, CollapseCallStack in your current implementation does not return anything. It will still be called, and actually something will be assigned to your collatedEntries pointer upon your initialization of it.
The problem is that when CollapseCallStack is called, memory for the return value is being allocated, but it never gets assigned a meaningful value, since the return statement is missing. So, essentially your collatedEntries pointer will be initialized with a random garbage value, and if you'd try to dereference it, it would cause UB.
Related
I'm trying to use realloc function in C, to dynamically operate on a char array of strings (char**).
I usually get a realloc():invalid old size error after 41st cicle of the for loop and I really can't understand why.
So, thanks to everyone who will help me ^-^
[EDIT] I'm trying to make the post more clear and following your advices, as a "new active member" of this community, so thank you all!
typedef struct _WordsOfInterest { // this is in an header file containing just
char **saved; // the struct and libraries
int index;
} wordsOfInterest;
int main() {
char *token1, *token2, *save1 = NULL, file[LEN], *temp, *word, **tokenArr;
int n=0, ch,ch2, flag=0, size, init=0,position,currEdit,init2=0,tempEdit,size_arr=LEN,
oldIndex=0,totalIndex=0,*editArr,counterTok=0;
wordsOfInterest toPrint;
char **final;
toPrint.index = 0;
toPrint.saved = malloc(sizeof(char*)*LEN);
editArr = malloc(sizeof(int)*LEN);
tokenArr = malloc(sizeof(char*)*LEN);
final = malloc(sizeof(char*)*1);
// external for loop
for(...) {
tokenArr[counterTok] = token1;
// internal while loop
while(...) {
// some code here surely not involved in the issue
} else {
if(init2 == 0) {
currEdit = config(token1,token2);
toPrint.saved[toPrint.index] = token2;
toPrint.index++;
init2 = 1;
} else {
if((abs((int)strlen(token1)-(int)strlen(token2)))<=currEdit) {
if((tempEdit = config(token1,token2)) == currEdit) {
toPrint.saved[toPrint.index] = token2;
toPrint.index++;
if(toPrint.index == size_arr-1) {
size_arr = size_arr*2;
toPrint.saved = realloc(toPrint.saved, size_arr);
}
} else if((tempEdit = config(token1,token2))<currEdit) {
freeArr(toPrint, size_arr);
toPrint.saved[toPrint.index] = token2;
toPrint.index++;
currEdit = tempEdit;
}
}
}
flag = 0;
word = NULL;
temp = NULL;
freeArr(toPrint, size_arr);
}
}
editArr[counterTok] = currEdit;
init2 = 0;
totalIndex = totalIndex + toPrint.index + 1;
final = realloc(final, (sizeof(char*)*totalIndex));
uniteArr(toPrint, final, oldIndex);
oldIndex = toPrint.index;
freeArr(toPrint,size_arr);
fseek(fp2,0,SEEK_SET);
counterTok++;
}
You start with final uninitialized.
char **final;
change it to:
char **final = NULL;
Even if you are starting with no allocation, it needs a valid value (e.g. NULL) because if you don't initialize a local variable to NULL, it gets garbage, and realloc() will think it is reallocating a valid chunk of memory and will fail into Undefined Behaviour. This is probably your problem, but as you have eliminated a lot of code in between the declaration and the first usage of realloc, whe cannot guess what is happening here.
Anyway, if you have indeed initialized it, I cannot say, as you have hidden part of the code, unlistening the recommendation of How to create a Minimal, Reproducible Example
.
There are several reasons (mostly explained there) to provide a full but m inimal, out of the box, failing code. This allows us to test that code without having to provide (and probably solving, all or part) the neccesary code to make it run. If you only post a concept, you cannot expect from us complete, full running, and tested code, degrading strongly the quality of SO answers.
This means you have work to do before posting, not just eliminating what you think is not worth mentioning.
You need to build a sample that, with minimum code, shows the actual behaviour you see (a nonworking complete program) This means eliminating everything that is not related to the problem.
You need (and this is by far more important) to, before sending the code, to test it at your site, and see that it behaves as you see at home. There are many examples that, when eliminated the unrelated code, don't show the commented behaviour.
...and then, without touching anymore the code, send it as is. Many times we see code that has been touched before sending, and the problem dissapeared.
If we need to build a program, we will probably do it with many other mistakes, but not yours, and this desvirtuates the purpose of this forum.
Finally, sorry for the flame.... but it is necessary to make people read the rules.
I don't believe this is a duplicate because the function does return in the happy path. Using the attribute no-return allows the compiler to optimise on the assumption that the function never returns, which is not the case here.
I have come C code that either returns a pointer or calls another function to exit out of the program. This is in an if statement, so either it returns the result or exits. As the function returns a void *, the compiler warns that it's possible the function won't return a value (which is of course true):
error: control reaches end of non-void function [-Werror=return-type]
I can get around this by just adding return *temp; to the end of the function but I'd like to be clear in my intent by having something like the unused variable attribute:
__attribute__((__unused__))
That way I can leave -Wall on and not have to add unnecessary or possibly confusing code.
I'd also be up for rewriting the code if there's a better way to express this intent.
The code looks something like:
void *get_memory() {
void *temp = malloc(100);
if (temp) {
// do some setup work
return temp;
} else {
exit_program_with_epic_fail();
}
// Compiler warns if the following line isn't present
return temp;
}
There are 2 ways to get rid of the warning:
tag the exit_program_with_epic_fail() function with the appropriate attribute, _Noreturn in C11, but there is no portable way to do this to pre-C11 compilers. Many compilers support __attribute__((noreturn)), notably gcc, clang and tinycc, but it is an compiler specific extension.
reorganise the code to let the compiler see the function always return.
Here is a modified version:
void *get_memory(void) {
void *temp = malloc(100);
if (!temp) {
exit_program_with_epic_fail();
}
// do some setup work
return temp;
}
This seems to be a pure design problem.
The warning/error "control reaches end of non-void function" isn't the problem, it is rather just an indicator telling you where the actual problem is.
You could/should simply rewrite the function as
void *get_memory (void)
{
void *temp = malloc(100);
if(temp != NULL)
{
// do stuff
}
return temp;
}
And leave error handling to the caller. Because it is not an allocation function's job to terminate the application - that's bad design.
Alternative version with detailed error handling:
typedef enum
{
OK,
ERR_OUTOFMEMORY,
...
} err_t;
err_t get_memory (void** mem)
{
*mem = malloc(100);
if(*mem == NULL)
{
return ERR_OUTOFMEMORY;
}
// do stuff
return OK;
}
Ive been dabbling in some c code and initialized a cat structure like so
typedef struct
{
int age;
char *name;
char *favoriteQuote;
} Cat;
I created two functions, one to initialize the cat object and one to zero out the memory that look like so
Cat initialize_cat_object(void)
{
Cat my_cat;
my_cat.age = 3;
my_cat.favorite_quote = "A day without laughter is a day wasted";
my_cat.name = "Chester";
return my_cat;
}
Cat destroy_cat_object(void)
{
Cat my_cat;
memset(&my_cat, 0, sizeof(my_cat));
//--forgot to return 'my_cat' here--
}
my main function looks like so
void main(void)
{
Cat my_cat;
my_cat = initialize_cat_object();
printf("Creating cat\n")
printf("Name: %s\nFavoriteQuote: %s\nAge: %d\n", my_cat.name,
my_cat.favorite_quote, my_cat.age);
my_cat = destroy_cat_obect();
printf("CAT DESTRUCTION\n");
printf("Name: %s\nFavoriteQuote: %s\nAge: %d\n", my_cat.name,
my_cat.favorite_quote, my_cat.age);
}
The output of the program was the expected output of
It wasn't until I went back to the source code that I noticed I had forgotten to return the Cat object who's memory was zeroed out, However the program still shows the expected output, but if I try to omit the return statement of the 'initialize_cat_object' function, the output of the data is corrupt
The only thing I can think of is that 'destroy_cat_object' returns the zeroed out memory, but how could this be?
destroy_cat_object doesn't have a return statement. C11 6.9.1p12 says:
If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined.
It is however perfectly OK C-standard-wise to have a function with a return type but which doesn't have a return statement before the closing bracket. Calling such a function is also perfectly OK.
What is not OK however is using the return value of the function call if the function didn't terminate with a return statement that explicitly returns a value.
You might want to enable some extra diagnostics in your compiler settings if you do not get a message for this.
Registers aside. There are three places where your data may be stored in C:
Constant data which is read only and is stored inside your binary;
Data on the stack;
Data stored in dynamic memory retrieved by the means of memory allocation functions.
In your case we are talking about stack. Stack is a LIFO queue elements of which are valid and accessible so long as they are not popped out of it. So if you have a function like this:
typedef struct {
int a_val;
float b_val;
char c_val;
} a_t;
a_t* func(void) {
a_t a = {1, 1., 'a'};
return &a;
}
"a" would be residing in stack until func returns, hence after func returns it's pointer becomes invalid and points someplace in stackspace. On the most systems stack won't be zeroed therefore until some other data overwrites it it may be possible to get some data by that pointer, which may be misleading.
So what should you do? Something like this:
void initialize_cat(Cat*);
void clear_cat(Cat*);
int main() {
Cat my_cat;
initialize_cat(&my_cat);
// do kitty stuff
clear_cat(&my_cat); // cat's private data must not be compromised
}
When function returns a structure this is actually achieved with a cooperation from a caller (I'm talking SysV x64 ABI here and may be wrong for other cases). Basically caller allocates space on stack enough to store the returned structure and passes pointer to it as an implicit first parameter. callee is using this pointer to write data later on.
So the two cases:
Cat callee(void) {
Cat my_cat = { .age = 5 };
return cat;
}
void caller(void) {
Cat my_cat = callee();
}
And:
void callee(Cat *my_cat) {
my_cat->age = 5;
return cat;
}
void caller(void) {
Cat my_cat;
callee(&my_cat);
}
Are pretty much the same.
I have a problem that i can even start to work on because i don't get it how can be done.
So we have a code
int test_handler() {
printf("Test handler called\n");
return 1;
}
// Test your implementation here
int main()
{
register_irq_handler(30, &test_handler);
do_interrupt(29); // no handler registered at this position, should return zero
do_interrupt(30); // calls handler at position 30, expected output: Test handler called
return 0;
}
I need to make those functions register_irq_handler, do_interrupt(29).
But i have no clue how to start, i am looking for a little help to send me on the right direction.
How i store 30 to point to this function when we don't have a global variable to store that "connection" or i am missing something.
You can't do it without a global variable (why would having a global variable be a problem?).
You probably need something like this:
// array of 30 function pointers (all automatically initialized to NULL upon startup)
static int(*functionpointers[30])();
void register_irq_handler(int no, int(*fp)())
{
functionpointers[no] = fp;
}
int do_interrupt(int no)
{
if (functionpointers[no] != NULL)
{
// is registered (!= NULL) call it
return (*functionpointer[no])();
}
else
{
// not registered, just return 0
return 0;
}
}
Disclaimer
This is non tested non error checking code just to give you an idea.
Actually i developing using unit test.
But i break down my code in other form to ask for the error that i faced.
I have these declaration in my header file
typedef struct
{
void *topOfStack;
}Stack;
typedef enum {NUMBER,OPERATOR,IDENTIFIER}Token;
int operatorEvaluate(Stack *numberStack , Stack *operatorStack);
void * pop(Stack *stack);
The following is the respective source file
#include "try.h"
void *pop(Stack *numberStack)
{
Token *newToken = NUMBER;
return newToken;
}
int operatorEvaluate(Stack *numberStack , Stack *operatorStack)
{
Token *first = (Token*)pop (numberStack);
if(numberStack != operatorStack)
{
if(*first == NUMBER)
return 1;
}
return 0;
}
This is the source file that i call the functions which is main
#include "try.h"
#include <stdio.h>
int main ()
{
Stack numberStack;
Stack operatorStack;
int num;
num = operatorEvaluate(&numberStack , &operatorStack);
printf("This is the returned value: %d",num);
return 0;
}
When i tried to compile, the unit test tell me that bad memory access.
So i try to use eclipse to compile these, and windows tells that the .exe had stop working.
Hope someone can help me, i stuck for a long time...
Enable compiler warnings.
In particular, this makes zero sense:
Token *newToken = NUMBER;
That's a pointer, and you're assigning a value.
I cannot propose a fix, as I have no idea what you're doing.
That pop() function isn't touching the stack, and is returning an enum converted to a pointer. If you try to access anything through that pointer, it's going to provoke undefined behavior.
Your pop function is wrong in a few ways. You probably want it to actually pop your stack, rather than return a constant (which it isn't doing either, by the way!)...something like this:
void *pop(Stack *numberStack)
{
return numberStack->topOfStack;
}
but if you do that it'll still crash, because you never initialize your stack OR fill the topOfStack pointer.