This program causes a seg fault on my UNIX machine. I narrowed the cause down to the second call of memset().
Why is this behaviour occurring? The first "chunk" of code is almost the same as the second, isn't it? Why didn't the first call of memset segfault if the second one does?
I looked over other threads concerning segfaulting memset calls, but none of them were similar to this.
In case you were wondering why I wrote such a trivial program, it's adapted from another program I've been writing that I was using to teach myself how to apply memcpy() to structures.
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int x;
char text;
} FilesStruct;
int
main(int argc, char** argv)
{
FilesStruct *old_dir;
memset(old_dir,0,sizeof(FilesStruct));
old_dir->x = 3;
old_dir->text = 'c';
printf("old dir: %d,%c\n",old_dir->x,old_dir->text);
FilesStruct *new_dir;
memset(new_dir,0,sizeof(FilesStruct));
new_dir->x = 7;
new_dir->text = 'g';
printf("new dir: %d,%c\n",new_dir->x,new_dir->text);
return 0;
}
FilesStruct *old_dir;
memset(old_dir,0,sizeof(FilesStruct));
attempts to write to an uninitialised pointer. This results in undefined behaviour, including possibly a crash. Its just luck (good or bad, depending on how you look at it) that the first instance of this behaviour didn't crash.
You need to allocate memory for old_dir. The easiest way to do this is to declare it on the stack
FilesStruct old_dir;
memset(&old_dir,0,sizeof(old_dir));
or you could dynamically allocate on the heap (making sure to call free when you no longer need the object)
FilesStruct *old_dir = calloc(1, sizeof(*old_dir);
/* use old_dir */
free(old_dir);
The same applies to new_dir further down your code.
Neither old_dir nor new_dir are initialized, so this is undefined behavior. One solution would be to allocate both variables on the stack:
FilesStruct old_dir;
//...
FilesStruct new_dir;
and use the & operator to obtain the address when calling memset:
memset(&old_dir,0,sizeof(FilesStruct));
FilesStruct *old_dir;
This defines a FilesStruct pointer. It is uninitialized, so it doesn't actually point to any storage for a FilesStruct.
memset(old_dir,0,sizeof(FilesStruct));
Will tell memset to zero out whatever old_dir points at, but as the pointer is uninitialized, you get undefined behavior.
You'll need to provide storage for your pointer, e.g.
FilesStruct *old_dir = malloc(sizeof(FilesStruct));
In your case you don't really need a pointer or dynamically allocated memory, you might do
FilesStruct old_dir;
memset(&old_dir,0,sizeof(FilesStruct));
old_dir.x = 3;
old_dir.text = 'c';
printf("old dir: %d,%c\n",old_dir.x,old_dir.text);
Related
I'm writing this program to practice C programming, this is my code:
#include <stdio.h>
#include <stdlib.h>
struct s1 {
int i;
void * p;
};
static struct s1 *dmk;
int main(void) {
int tong(int a, int b);
int (*tinh)(int,int);
struct s2 {
int num;
int (*cal)(int a, int b);
};
if(dmk->p == NULL)
{
printf("NULL ALERT\n");
}
struct s2 *cl = dmk->p;
cl->cal = tong;
tinh = ((struct s2 *)(dmk->p))->cal;
printf("tinh 2, 4 ra %d\n",tinh(2,4));
puts("!!!Hello World!!!"); /* prints !!!Hello World!!! */
return EXIT_SUCCESS;
}
int tong(int a, int b)
{
return a + b;
}
When I compiled it, it didn't show any error or warning. But when I ran the program, the terminal told me that "core dumped" and did not show any result accept for the "NULL ALERT". Can anyone explain why I failed ? Thanks alot.
if(dmk->p == NULL)
fails as dmk is uninitialised initialised to NULL, points "no-where", so de-referencing it invokes undefined behaviour. Anything can happen afterwards.
dmk is a global (aka. static (this is not related to the static keyword!), variable, thus it is initialized to a null pointer. You do not change this value, so dkms->p dereferences a null pointer, which invokes undefined behaviour (UB).
So from here, it is speculation, as UB means anything can happen.
Apparently the printf passes, probably because the address can be read. The following write OTOH fails, generating the system messsage.
Bottom line is that what you're doing wrong is not assigning things to your various pointers before using them.
Your dmk is a global, so its initial value is NULL. You're never changing that value.
Later, you read dmk->p. You're now in Undefined Behavior (UB) territory. The program could easily have faulted right there, because you were reading from a NULL pointer.
Apparently it didn't, though, because you're seeing your NULL ALERT message, and so we continue.
Then you do this:
struct s2 *cl = dmk->p;
cl->cal = tong;
On the second line there, cl is completely indeterminate. It could be garbage, it could be NULL, whatever, because you're entered UB territory. Then you dereference it and write to the result. You could be trying to write anywhere. Writing to random pointers (or NULL pointers) tends to make core dumps and other Bad Things™ happen.
You need to actually assign values to your pointers before you use them.
You don't initialize dmk in your code. That dmk->p is NULL is pure luck. Anything could happen.
You need to allocate memory for your struct using, for instance, malloc(), and initialize the members properly.
I'm creating a source files containing buffer functionality that I want to use for my other library that I'm creating.
It is working correctly but I'm having trouble getting rid of the buffer structure that I'm creating in one of the functions. The following snippets should help illustrate my problem:
C header:
//dbuffer.h
...
typedef struct{
char *pStorage;
int *pPosition;
int next_position;
int number_of_strings;
int total_size;
}DBUFF;
...
C source:
//dbuffer.c
...
DBUFF* dbuffer_init(char *init_pArray)
{
//Find out how many elements the array contains
int size = sizeof_pArray(init_pArray);
//Initialize buffer structure
DBUFF *buffer = malloc(sizeof(DBUFF));
//Initialize the storage
buffer->pStorage = malloc( (sizeof(char)) * (size) );
strncpy( &(buffer->pStorage)[0] , &init_pArray[0] , size);
buffer->number_of_strings = 1;
buffer->total_size = size;
buffer->next_position = size; //size is the next position because array allocates elements from 0 to (size-1)
//Initialize the position tracker which keeps record of starting position for each string
buffer->pPosition = malloc(sizeof(int) * buffer->number_of_strings );
*(buffer->pPosition + (buffer->number_of_strings -1) ) = 0;
return buffer;
}
void dbuffer_destroy(DBUFF *buffer)
{
free(buffer->pStorage);
free(buffer);
}
...
Main:
#include <stdio.h>
#include <stdlib.h>
#include "dbuffer.h"
int main(int argc, char** argv)
{
DBUFF *buff;
buff = dbuffer_init("Bring the action");
dbuffer_add(buff, "Bring the apostles");
printf("BUFFER CONTENTS: ");
dbuffer_print(buff);
dbuffer_destroy(buff);
// Looks like it has been succesfully freed because output is garbage
printf("%s\n", buff->pStorage);
//Why am I still able to access struct contents after the pointer has been freed ?
printf("buff total size: %d\n", buff->total_size);
return (EXIT_SUCCESS);
}
Output:
BUFFER CONTENTS: Bring the action/0Bring the apostles/0
��/�
buff total size: 36
RUN SUCCESSFUL (total time: 94ms)
Question:
Why am I still able to access struct contents using the line below after the pointer to the struct has been freed ?
printf("buff total size: %d\n", buff->total_size);
Once you've called free() on the allocated pointer, attempt to make use of the pointer invokes undefined behavior. You should not be doing that.
To quote C11 standard, chapter §7.22.3.4, free() function
The free() function causes the space pointed to by ptr to be deallocated, that is, made
available for further allocation. [..]
It never say's anything about a cleanup, which you might be (wrongly) expecting.
Just to add clarity, calling free() does not always actually free up the allocated physical memory. It just enables that pointer (memory space) to be allocated again (returning the same pointer, for example) for successive calls to malloc() and family. After calling free(), that pointer is not supposed to be used from your program anymore but C standard does not guarantee of a cleanup of the allocated memory.
If any attempt is made to read memory that has been freed can crash your program. Or they might not. As far as the language is concerned, its undefined behaviour.
Your compiler won't warn you about it(or stop you from accessing it). But clearly don't do this after calling free -
printf("buff total size: %d\n", buff->total_size);
As a good practice you can set the freed pointer to NULL .
free() call will just mark the memory in heap as available for use. So you still have the pointer pointing to this memory location but it's not available anymore for you. Thus, the next call to malloc() is likely to assign this memory to the new reservation.
To void this situations normally once you free() the memory allocated to a pointer you should set it to NULL. De-referencing NULL is UB also but at least when debugging you can see tha pointer should not be used because it's not pointing to a valid memory address.
[too long for a comment]
To allow your "destructor" to set the pointer passed to NULL modify your code like this:
void dbuffer_destroy(DBUFF ** buffer)
{
if ((NULL == buffer) || (NULL == *buffer))
{
return;
}
free((*buffer)->pPosition);
free((*buffer)->pStorage);
free(*buffer);
*buffer = NULL;
}
and call it like this:
...
dbuffer_destroy(&buff);
...
typedef struct
{
char path[MAX_FILENAME*MAX_FOLDERS];
char filename[MAX_FILENAME];
time_t date;
off_t size;
} FILES;
This code works
FILES *fls = (FILES*)malloc(sizeof(FILES));
strcpy(fls[0].filename, "asd");
printf("%s\n", fls[0].filename);
fls = (FILES*)realloc(fls, 2);
strcpy(fls[1].filename, "asdfgh");
printf("%s\n", fls[0].filename);
printf("%s\n", fls[1].filename);
But here:
void allocateFileTree(FILES *tree,int i)
{
if(i==0)
tree = (FILES*)malloc(sizeof(FILES));
else
tree = (FILES*)realloc(tree, sizeof(FILES)*i);
}
in a loop
allocateFileTree(tree, i);
struct stat buff;
stat(entry -> d_name, &buff);
strcpy(tree[i].path, "whatever");//it gives segfault
i++;//this is never executed so realloc isn't the problem (yet)
Why and how can I solve this? What is so different that it crashes?
The code you say works really doesn't. One major problem is this line here
fls = (FILES*)realloc(fls, 2);
This reallocate the pointer to be two bytes. There's also a problem with this if the realloc call fails, as then you overwrite the only pointer you have with NULL, and therefore loose the original pointer and have a memory leak (besides the obvious problem of dereferencing a NULL pointer).
Your exact cause of the crash is because you don't allocate memory for the path member, so you're using an uninitialized pointer.
Both of the above leads to undefined behavior, which is a common cause of crashes.
And finally, in C you should not cast the return of malloc (and family).
While you allocate space for an array of FILES, you do not allocate storage for path in the code shown.
In the code
strcpy(tree[i].path, "whatever")
The value of tree[i].path is undefined. It might happen to point to space you can write to, or not.
This statement:
(FILES*)realloc(tree, sizeof(tree)*i);
allocates enough space for i pointers since tree is a FILES*. I think you want:
(FILES*)realloc(tree, sizeof(*tree)*i);
Your other problem is that you never actually update your tree pointer. The allocateFileTree() function only every updates it's local copy of the pointer to the new allocation.
You may want to try something like
FILES* allocateFileTree(FILES *tree,int i)
{
if(i==0)
tree = (FILES*)malloc(sizeof(FILES));
else
tree = (FILES*)realloc(tree, sizeof(FILES)*i);
return tree;
}
and call it like so:
tree = allocateFileTree(tree, i);
I have a question regarding this code. I write this code in my framework, and it caused the framework crashed. But when I rewrite this code below in a single file, but it works just fine. I was just wondering, is the code below is correct for memory allocation and freeing it? (especially for the part of msg->context_var.type = f;)
Thank you
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int value;
int price;
int old;
} type_t;
typedef struct {
type_t *type;
} context_t;
typedef struct {
context_t context_var;
} send_request;
void send_Message(send_request *msg)
{
type_t *f = 0;
f = malloc(sizeof(f));
msg->context_var.type = f;
msg->context_var.type->price = 1;
msg->context_var.type->value = 100;
msg->context_var.type->old =120;
printf("value of %d/n", msg->context_var.type->price);
free(f);
}
int main()
{
send_request *msg = 0;
msg = (send_request *) malloc(sizeof(send_request));
send_Message(msg);
free(msg);
return 0;
}
It's wrong.
f = malloc(sizeof(f)); /* Wrong */
f = malloc(sizeof(*f)); /* Better ? */
sizeof(f) will give you the size of a pointer on your machine; sizeof(*f) will give you the size of the object pointed to.
EDIT As requested by #Perception
When you allocate less than you need you're eliciting Undefined Behavior. Anything can happen (even the desired behavior) and it all depends on the platform, the environment (the moon phase, etc).
msg->context_var.type->value = 100; /* Writes beyond what's allocated. */
So, depending on the memory layout of the "framework" this might simply overwrite some memory and "work", or it could crash. Frankly I prefer when it crashes straight away.
You allocate an instance of context_t on the heap, and then msg->context_var.type gets the value of the resulting pointer f.
Since msg is a pointer parameter to the send_Message function, no reliable assumptions can be made about what is done with msg and its contents after your function exists. As such, when you go on to free the memory pointed to by f, you leave a dangling pointer in msg->context_var.type.
If the memory it points to is accessed after send_Message exists, there's a fair chance that you corrupt something vital (or read something crazy, like a pointer to 0xdeadbeef), as it might contain something completely different now.
Not only are you allocating wrong size (see cnicutar's answer)-- If you are attaching f to message that is passed by the framework, you probably don't want to free it before the function returns. You'll need to free it later, though-- probably through some other facility provided by the framework?
Due to my feeble understanding of allocating type memory to pointers, the following causes a bus error on the call to barrier_create ("hi" is never printed).
typedef struct barrier barrier_t;
typedef struct barrier *barrier_p;
barrier_p test_barrier_p;
int main(int argc, char *argv[]) {
barrier_create(*test_barrier_p);
}
int barrier_create(barrier_p *barrier_pointer) {
printf("hi\n");
barrier_p old_barrier, new_barrier;
int count;
old_barrier = (barrier_p) *barrier_pointer;
new_barrier = (barrier_p) malloc(sizeof(*new_barrier));
count = pthread_mutex_init(&new_barrier->lock, NULL);
new_barrier->is_valid = VALID_BARRIER;
new_barrier->counter = 0;
new_barrier->release_flag = 0;
*barrier_pointer = new_barrier;
return HAPPY_HAPPY_JOY_JOY;
}
What am I missing or mis-typing?
barrier_create(*test_barrier_p);
Since barrier_create takes address of a barrier_p, this should be &test_barrier_p, not *test_barrier_p.
printf("hi\n");
Inaccurate test of code reachability because stdout is likely buffered; I'd recommend fprintf(stderr, "hi\n"); instead.
new_barrier = (barrier_p) malloc(sizeof(*new_barrier));
I'd say sizeof(barrier_t). Again a * in an odd place, the _p notation may not be helping your type manipulation clarity.
For pedanticism, I would check the return value of malloc. I see little point in keeping the old value unless to recover in some way from a malloc error.
What is the purpose of count?
You're dereferencing a bad pointer in your main function. To get the address of the variable, you use the address & operator, not the dereferencing * operator. Rewrite main as:
barrier_create(&test_barrier_p);
The test_barrier_p variable is a pointer to a barrier structure which is never being initialized, so it's set to NULL (since it's at file scope).
You're de-referencing it at the call from main() to barrier_create().
For help beyond that, you'll need to tell us, in English, what you're trying to achieve.
The function int barrier_create(barrier_p *barrier_pointer) takes a pointer as an argument. However, you a passing in an actual barrier_p in your main since you dereference it - barrier_create(*test_barrier_p). I think you should be passing the address like barrier_create(&test_barrier_p)