Slab cache allocate stack of structures without predefined functions - c

I'm writing a module that creates stack in kernel space using kmem_cache_create and kmem_cache_alloc however it doesn't work. Maybe I've done something bad with the pointers or I don't undestand the whole concept of slab allocating. I've shown the code to the classmates and also my laboratory leader, sadly anyone wasn't able to help me.
Here is my code allocating 5 structures on "stack"
#include<linux/module.h>
#include<linux/slab.h>
#include<linux/string.h>
static struct example_struct {
unsigned int id;
char example_string[10];
struct example_struct *next;
} *example_struct_pointer;
static struct example_struct *top = NULL;
static struct kmem_cache *example_cachep;
static void example_constructor(void *argument)
{
static unsigned int id;
static char test_string[] = "Stack";
struct example_struct *example = (struct example_struct *)argument;
example->id = id;
strcpy(example->example_string,test_string);
example->next = top;
top = example;
id++;
}
void print_example_struct(struct example_struct *example)
{
pr_notice("Struct id: %u\n",example->id);
pr_notice("String field content: %s\n",example->example_string);
}
static int __init slabmod_init(void)
{
example_cachep = kmem_cache_create("example cache", sizeof(struct example_struct),0, SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, example_constructor);
if(IS_ERR(example_cachep)) {
pr_alert("Error creating cache: %ld\n",PTR_ERR(example_cachep));
return -ENOMEM;
}
for(i=1 ; i<6 ; i++)
{
printk(KERN_ALERT "i: %d\n",i);
example_struct_pointer = (struct example_struct *) kmem_cache_alloc(example_cachep,GFP_KERNEL);
if(IS_ERR(example_struct_pointer)) {
pr_alert("Error allocating from cache: %ld\n", PTR_ERR(example_struct_pointer));
kmem_cache_destroy(example_cachep);
return -ENOMEM;
}
}
return 0;
}
static void __exit slabmod_exit(void)
{
struct example_struct *tmp = example_struct_pointer;
if(example_cachep) {
while(example_struct_pointer != NULL) {
print_example_struct(example_struct_pointer);
tmp = example_struct_pointer;
example_struct_pointer = tmp->next;
kmem_cache_free(example_cachep,tmp);
}
kmem_cache_destroy(example_cachep);
}
}
module_init(slabmod_init);
module_exit(slabmod_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kostek888888");
MODULE_DESCRIPTION("A module demonstrating use of the slab allocator.");
MODULE_VERSION("1.0");
I also have debug version of this code:
#include<linux/module.h>
#include<linux/slab.h>
#include<linux/string.h>
static struct example_struct {
unsigned int id;
char example_string[10];
struct example_struct *next;
} *example_struct_pointer;
static struct example_struct *top = NULL;
static struct kmem_cache *example_cachep;
static unsigned int i;
static void example_constructor(void *argument)
{
static unsigned int id;
static char test_string[] = "Stack";
struct example_struct *example = (struct example_struct *)argument;
example->id = id;
strcpy(example->example_string,test_string);
example->next = top;
top = example;
id++;
}
void print_example_struct(struct example_struct *example)
{
pr_notice("Struct id: %u\n",example->id);
//pr_notice("String field content: %s\n",example->example_string);
printk(KERN_ALERT "example_struct_pointer: %p\n",example_struct_pointer);
//printk(KERN_ALERT "top: %p\n",top);
printk(KERN_ALERT "i: %d\n",i);
i++;
}
static int __init slabmod_init(void)
{
example_cachep = kmem_cache_create("example cache", sizeof(struct example_struct),0, SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, example_constructor);
if(IS_ERR(example_cachep)) {
pr_alert("Error creating cache: %ld\n",PTR_ERR(example_cachep));
return -ENOMEM;
}
for(i=1 ; i<6 ; i++)
{
printk(KERN_ALERT "i: %d\n",i);
example_struct_pointer = (struct example_struct *) kmem_cache_alloc(example_cachep,GFP_KERNEL);
if(IS_ERR(example_struct_pointer)) {
pr_alert("Error allocating from cache: %ld\n", PTR_ERR(example_struct_pointer));
kmem_cache_destroy(example_cachep);
return -ENOMEM;
}
}
return 0;
}
static void __exit slabmod_exit(void)
{
struct example_struct *tmp = example_struct_pointer;
i = 1;
if(example_cachep) {
while(example_struct_pointer != NULL) {
print_example_struct(example_struct_pointer);
printk(KERN_ALERT "tmp: %p\n",tmp);
printk(KERN_ALERT "next: %p / %p\n\n",top->next,*(top->next));
tmp = example_struct_pointer;
example_struct_pointer = tmp->next;
kmem_cache_free(example_cachep,tmp);
}
printk(KERN_ALERT "tmp: %p\n",tmp);
printk(KERN_ALERT "next: %p\n\n",top->next);
printk(KERN_ALERT "example_struct_pointer: %p\n",example_struct_pointer);
kmem_cache_destroy(example_cachep);
}
}
module_init(slabmod_init);
module_exit(slabmod_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kostek888888");
MODULE_DESCRIPTION("A module demonstrating use of the slab allocator.");
MODULE_VERSION("1.0");
In output I'm getting 12 elements in range 0-11 when I only do kmem_cache_alloc 5 times in range 1-5 and also message "Slab cache still has objects".
Here is screenshot demonstrating words above
After that I'm getting Call Trace message so something with memory is wrong. Sometimes it halts whole virtual machine.
I've swapped the pointer in __exit's while loop for "top" pointer to check what it will show - I had 122 elements and same message so that's probably a whole slab (but maybe not whole because of message?). Pointer "next" always has the same value 122 in DEC - is structure 122 bytes wide? Sizeof structure gave me some huge value above 1,000,000 with %d.
Original code which allocates only one structure and works like a charm:
#include<linux/module.h>
#include<linux/slab.h>
#include<linux/string.h>
static struct example_struct {
unsigned int id;
char example_string[10];
} *example_struct_pointer;
static struct kmem_cache *example_cachep;
static void example_constructor(void *argument)
{
static unsigned int id;
static char test_string[] = "Test";
struct example_struct *example = (struct example_struct *)argument;
example->id = id;
strcpy(example->example_string,test_string);
id++;
}
void print_example_struct(struct example_struct *example)
{
pr_notice("Example struct id: %u\n",example->id);
pr_notice("Example string field content: %s\n",example->example_string);
}
static int __init slabmod_init(void)
{
example_cachep = kmem_cache_create("example cache", sizeof(struct example_struct),0, SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, example_constructor);
if(IS_ERR(example_cachep)) {
pr_alert("Error creating cache: %ld\n",PTR_ERR(example_cachep));
return -ENOMEM;
}
example_struct_pointer = (struct example_struct *) kmem_cache_alloc(example_cachep,GFP_KERNEL);
if(IS_ERR(example_struct_pointer)) {
pr_alert("Error allocating form cache: %ld\n", PTR_ERR(example_struct_pointer));
kmem_cache_destroy(example_cachep);
return -ENOMEM;
}
return 0;
}
static void __exit slabmod_exit(void)
{
if(example_cachep) {
if(example_struct_pointer) {
print_example_struct(example_struct_pointer);
kmem_cache_free(example_cachep,example_struct_pointer);
}
kmem_cache_destroy(example_cachep);
}
}
module_init(slabmod_init);
module_exit(slabmod_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Arkadiusz Chrobot <***>");
MODULE_DESCRIPTION("A module demonstrating useing of the slab allocator.");
MODULE_VERSION("1.0");
I've checked books like Linux Device Drivers and similar - everywhere is just plain function with example for one element.
I'm using kernel 3.16.0-4-686-pae but in kernel 4.9 situation is the same.
I will be grateful for every response :)

You incorrectly assume that ctor() (last argument to the kmem_cache_create()) is called every time you call kmem_cache_create().
Actually, this callback function is called only for pre-initialize "garbage" memory before an allocator takes control over it.
In this sequence:
kmem_cache_alloc(), returns pointer p.
kmem_cache_free(p) (assume allocator remains control over p).
kmem_cache_alloc(), returns pointer p.
the callback function is called only ONCE, at the step 1. The allocator assumes that at the step 2 (freeing) the object pointed by p is already in initialized state, so step 3 doesn't require initialization.
Proper way for implement list with kmem_cache would be:
static void example_constructor(void *argument)
{
static unsigned int id;
static char test_string[] = "Stack";
struct example_struct *example = (struct example_struct *)argument;
/*
* This only garantee that at any time every element in the stack has unique id.
* New element may have same id as previously deleted one.
*/
example->id = id;
// All elements will have given string.
strcpy(example->example_string,test_string);
// Appending into the stack cannot be performed in the constructor.
// example->next = top;
// top = example;
id++;
}
/* Push allocated element into the stack and return that element. */
struct example_struct* push(void)
{
struct example_struct* example = kmem_cache_alloc(example_cachep,GFP_KERNEL);
if(example) {
// Add to the stack here
example->next = top;
top = example;
}
return example;
}
/* Pop element from the stack and free the element. */
void pop(void)
{
// Take the first element.
struct example_struct *example = top;
// Remove the element from the stack
top = example->next;
// In given example re-initialization actions before freeing the element are not needed.
kmem_cache_free(example_cachep, example);
}
static int __init slabmod_init(void)
{
...
// Test the stack.
for(i=1 ; i<6 ; i++) {
printk(KERN_ALERT "i: %d\n",i);
example_struct_pointer = push();
if(!example_struct_pointer)) {
...
}
}
return 0;
}
static void __exit slabmod_exit(void)
{
...
// Clean the stack
while(top) pop();
...
}

Related

Graph containing node structure with two pointers

I am trying to write a simple graph for storing sizes of created tables. I am new to C so I am sorry if I miss some simple pointer operations.
My graph is containing previous and next pointers, where first next will point to the last node and serve as a iterator to grab next->next. I don't want to store any more information then those two pointers and size of the graph, so one can reach the nodes only trough the iteration of next pointer.
Here is a minimal reproducible example of my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct GC {
uint data;
uint size;
struct GC *next;
struct GC *prev;
};
void build_gc_root(struct GC **self) {
// Build root node
printf("Allocating gc.\n");
struct GC *tmp = malloc(sizeof *tmp);
tmp->size = 0;
tmp->data = 666;
tmp->prev = tmp;
tmp->next = tmp;
printf("Saving allocation of gc.\n");
(*self) = tmp;
}
void gc_clean(struct GC **self) {
uint _;
printf("Cleaning the gc table.\n");
for (_ = 0; _ < (*self)->size + 1; ++_) {
printf("Free node %hd.\n", (*self)->next->next->data);
free((*self)->next->next);
++(*self)->next;
}
printf("Free last node %hd.\n", (*self)->next->data);
free((*self)->next);
}
void gc_store(struct GC **self, uint data) {
printf("Storing GC value node.\n");
(*self)->next = malloc(sizeof *(*self)->next);
(*self)->next->data = data;
(*self)->next->prev = (*self)->prev;
(*self)->next->next = (*self);
(*self)->prev = (*self)->next;
++(*self)->size;
}
typedef struct {
void (*clean)();
void (*get_size)(uint size);
void (*print_table)();
struct GC *gc;
}__controller;
__controller controller;
void controller_clean() {
gc_clean(&controller.gc);
}
void controller_get_size(uint size) {
gc_store(&controller.gc, size);
}
void controller_print_table() {
uint index;
printf("GC catch: \n");
for (index = 0; index < controller.gc->size + 1; ++index) {
printf(" %hd\n", controller.gc->next->next->data);
--controller.gc->next;
}
putchar('\n');
}
__controller controller = {
controller_clean, controller_get_size, controller_print_table
};
int main (void) {
build_gc_root(&controller.gc);
controller.get_size(1);
controller.get_size(2);
controller.get_size(3);
controller.print_table();
controller.clean();
return 0;
}
After running this, the controller.print_table() method will output only two first node's data and end up with segmentation fault.
Basically you are creating a stack that is linked via prev pointer. The next is rather useless and you should think about removing it.
When it comes to printing or deleting the content, you have used wrong mechanism to iterate over your list.
Operators ++ and -- used on pointers move them to the next/previous consecutive element in memory. This is only valid within an array which you do not use.
Instead you need to follow the links in your structure to reach the next element.
This would look like this:
void gc_clean(struct GC** self) {
uint _;
printf("Cleaning the gc table.\n");
struct GC* gc = (*self)->prev;
for (_ = 0; _ < (*self)->size; ++_) {
printf("Free node %hd.\n", gc->data);
struct GC* tmp = gc;
gc = gc->prev;
free(tmp);
}
printf("Free last node %hd.\n", gc->data);
free(gc);
}
void controller_print_table() {
uint index;
printf("GC catch: \n");
struct GC* gc = controller.gc->prev;
for (index = 0; index < controller.gc->size + 1; ++index) {
printf(" %hd\n", gc->data);
gc = gc->prev;
}
putchar('\n');
}
Please note that this also removes the initial element from your stack which you added during creation. Also the pointers of your controller.gc are not valid any more. You need to initialize again after cleaning the list.
As a side node, you should think about naming.
The function to add an element to your stack, is called get_size which is confusing to put it mildly...
I post the working code bellow in case someone wanna see a working stack:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// Garbage collector stack
struct GC {
uint data;
uint size;
struct GC *prev;
};
void build_gc_root(struct GC **self) {
// Build root node
printf("Allocating gc.\n");
struct GC *tmp = malloc(sizeof *tmp);
tmp->size = 0;
tmp->data = 666;
tmp->prev = tmp;
printf("Saving allocation of gc.\n");
(*self) = tmp;
}
void gc_clean(struct GC **self) {
uint _;
printf("Cleaning the gc table.\n");
struct GC *gc = (*self)->prev;
for (_ = 0; _ < (*self)->size; ++_) {
printf("Free node %hd\n", gc->data);
struct GC* tmp = gc;
gc = gc->prev;
free(tmp);
}
printf("Free the last node %hd\n", gc->data);
free(gc);
}
void gc_store(struct GC **self, uint data) {
printf("Storing GC value node.\n");
struct GC *node;
node = malloc(sizeof *(*self)->prev);
node->data = data;
node->prev = (*self)->prev;
(*self)->prev = node;
++(*self)->size;
}
void gc_print(struct GC *self) {
uint index;
struct GC *gc = self->prev`;
printf("GC catch: ");
for (index = 0; index < self->size + 1; ++index) {
printf(" %hd", gc->data);
gc = gc->prev;
}
putchar('\n');
}
typedef struct {
void (*clean)();
void (*get_size)(uint size);
void (*print_table)();
struct GC *gc;
}__controller;
__controller controller;
void controller_clean() {
gc_clean(&controller.gc);
}
void controller_get_size(uint size) {
gc_store(&controller.gc, size);
}
void controller_print_table() {
gc_print(controller.gc);
}
__controller controller = {
controller_clean, controller_get_size, controller_print_table
};
int main (void) {
build_gc_root(&controller.gc);
controller.get_size(1);
controller.get_size(2);
controller.get_size(3);
controller.print_table();
controller.clean();
return 0;
}

kernel crash for spinlock concurrency in linux-kernel

I want to clear a list which type is defined by Kernel. I have two main structs, num_wrapper and num. num_wapper has a list of num, and kernel crashs when I do the del_all_node() function.
I try to mark the list_del, and the kernel will not be crash. I don't understand why there will be crash problem since I have use spin_lock to protect this num_list.
Any tips will be appreciate.
The following is the simplified code.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/slab.h>
struct num_wrapper {
struct list_head num_list;
spinlock_t list_lock;
u8 check_num;
};
struct num {
struct list_head node;
int number;
struct num_wrapper* num_w_ptr;
};
s32 del_all_node(struct num_wrapper *number_wrap)
{
struct num *tmp;
struct num *num_head;
spin_lock(&number_wrap->list_lock);
list_for_each_entry_safe(num_head, tmp, &number_wrap->num_list, node) {
printk("num_head is %d\n", num_head->number);
list_del(&num_head->node);//this line seems to have problem
}
spin_unlock(&number_wrap->list_lock);
return 0;
}
static int __init hello_init(void)
{
/*Setup Scenario*/
struct num_wrapper *number_wrap = kzalloc(sizeof(struct num_wrapper)
, GFP_KERNEL);
struct num *number = kzalloc(sizeof(struct num), GFP_KERNEL);
number->number = 10;
number_wrap->check_num = 20;
INIT_LIST_HEAD(&number->node);
INIT_LIST_HEAD(&number_wrap->num_list);
list_add_tail(&number->node, &number_wrap->num_list);
del_all_node(number_wrap);
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Good, haha\n");
}
module_init(hello_init);
module_exit(hello_exit);
update
After doing some debug, I seems to find root cause...
my scenario is as follows :
I have a private data struct which is included in the net_device struct.
And the following is the simplified scenario:
struct xx_if *xx_if; //this is private data in net_device
struct xx_if *tmp;
list_for_each_entry_safe(xx_if, tmp, xx_if_wrap->if_list, list) {
free_netdev(xx_if->ndev);
list_del(&xx_if->list);
}
Since free_netdev will also free the private data xx_if, the code broken...
My fix is change the sequence to these two statements, and it fix the crash problem.
Still strange thing is I have check whether xx_if is NULL, but still lead to crash if I don't interchange these two statements.
I don't clearly understand following code:
INIT_LIST_HEAD(&number->node);
INIT_LIST_HEAD(&number_wrap->num_list);
list_add_tail(&number->node, &number_wrap->num_list);
You init two different structures, then you add one type of list to another type of list.
Is that the way you can do?
I think, that you need something like this:
struct num{
u8 check_num;
struct list_head list;
};
struct num_wrapper{
struct num* num_ptr;
spinlock_t list_lock;
};
int init_num_wrapper(struct num_wrapper** prt){
if(!ptr && *ptr){
return -EINVAL;
}
*ptr = kzalloc(sizeof(struct num_wrapper), GFP_KERNEL);
if(!*ptr){
return -ENOMEM;
}
INIT_LIST_HEAD(& (*ptr)->num_ptr->list);
... init spinlock
return 0;
}
int add_num(num_wrapper* prt_wrap, u8 check_num){
... checking pointers
struct num num* = NULL;
num = kmalloc(sizeof(struct num), GFP_KERNEL);
if(! num){
return -ENOMEM;
}
INIT_LIST_HEAD(&num->list);
num->check_num = check_num;
spin_lock(&prt_wrap->list_lock);
list_add_tail(&num->list, &prt_wrap->num_ptr.list);
spin_unlock(&prt_wrap->list_lock);
return 0;
}
int remove_all_nodes(num_wrapper* prt_wrap){
... checking pointer
struct num *tmp = NULL;
struct num *num_head = NULL;
spin_lock(&number_wrap->list_lock);
list_for_each_entry_safe(num_head, tmp, &prt_wrap->list, list)
{
printk("num_head is %d\n", num_head->number);
list_del(&num_head->node);//this line seems to have problem
}
spin_unlock(&num_wrapper->list_lock);
return 0;
}
Update
Then, you can use above functions for manipulating of num_wrapper.
For example:
//...
struct num_wrapper* nums = NULL;
init_num_wrapper(&nums); // after this call, you will have inited nums var, which can be used with others functions for manipulating with num_wrapper list.
u8 num = 2;
add_num(nums, num); // after this call new node with num will be added to num_wrapper
//...

struct assignment: segment fault 11

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
union value {
long long i;
unsigned long long u;
double d;
long double ld;
void *p;
void (*g) ();
};
struct foo {
struct {
union value max;
union value min;
}limits;
};
struct bucket_info {
void *p; // free position
void *limit; // end position
struct bucket_info *next; // next bucket
};
#define NODES 8192
void * my_malloc(size_t size)
{
void *p = malloc(size);
if (!p)
exit(1);
memset(p, 0, size);
return p;
}
void * alloc_bucket(size_t size)
{
struct bucket_info *pb;
pb = my_malloc(sizeof(struct bucket_info) + size);
pb->p = pb + 1;
pb->limit = (char *)pb->p + size;
return pb;
}
void * alloc_for_size(struct bucket_info *s, size_t size)
{
void *ret;
while (s->next)
s = s->next;
if ((char *)s->p + size > (char *)s->limit) {
struct bucket_info *pb = alloc_bucket(size * NODES);
s->next = pb;
s = pb;
}
ret = s->p;
s->p = (char *)s->p + size;
return ret;
}
static void * alloc_node(struct bucket_info **s, size_t size)
{
if (!*s)
*s = alloc_bucket(size * NODES);
return alloc_for_size(*s, size);
}
static struct bucket_info *foo_info;
void * alloc_foo_node()
{
void *ret = alloc_node(&foo_info, sizeof(struct foo));
return ret;
}
struct foo * new_foo()
{
return alloc_foo_node();
}
void test(int t, struct foo *foo1)
{
struct foo *foo2 = new_foo();
// Crash at this line
*foo2 = *foo1;
// comment this switch statement, it works. why?
switch (t) {
case 1:
break;
default:
break;
}
}
int main(int argc, const char * argv[]) {
struct foo *foo1 = new_foo();
test(10, foo1);
return 0;
}
Above is the complete code. And I've compiled it with clang, got a 'Segment Fault 11' at line:
*foo2 = *foo1;
Then, change this line to:
memcpy(foo2, foo1, sizeof(struct Foo));
It works.
Then I've tried compiled these two cases with gcc, there is no problem.
The value returned by alloc_foo_node may not be correctly aligned for struct foo.
On my system, printing _Alignof(struct foo) gives 16, but the pointers foo1 and foo2 are not multiples of 16.
So it causes undefined behaviour to convert the unaligned result of alloc_foo_node to have type struct foo *.
To fix this you have to muck around a lot more with your allocation code, to make sure that it only ever hands out space that is on the correct boundary for struct foo. You could use max_align_t to help with this (it is defined so that _Alignof(max_align_t) is the biggest possible alignment required).

Complex generic stack

I have been assigned to program a generic stack in ANSI C. It is meant to be for primitive datatypes. Until here there was no big problem whatsoever.
Afterwards I was asked to reprogram my application so that even complex data types can be used on my stack. I have searched and researched for the last week and I found nothing that could be helpful enough.
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stddef.h>
#include "genstacklib.h"
void (*freefn) (void*);
/*
* ToDo
*/
void GenStackNew(genStack *s, int elemSize, void (*freefunk) (void*))
{
s->elems = malloc (elemSize * GenStackInitialAllocationSize);
freefn = freefunk;
assert (s->elems != NULL);
s->elemSize = elemSize;
s->logLength = 0;
s->allocLength = GenStackInitialAllocationSize;
}
/*
* ULStackPush adds an element to the stack and allocates new memory if
* needed. If there is not enough memory, ULStackPush does nothing.
*/
void GenStackPush (genStack *s, const void *elemAddr)
{
/*assert (sizeof(*elemAddr) == s->elemSize);*/
assert (s->elems != NULL);
if (s->logLength == s->allocLength)
{
void *temp = NULL;
temp = realloc (s->elems, 2 * s->allocLength * s->elemSize);
assert (temp != NULL);
s->allocLength = 2 * s->allocLength;
s->elems = temp;
}
memcpy(currentval(s), elemAddr, s->elemSize);
s->logLength = s->logLength + 1;
}
void GenStackPop (genStack *s, const void *elemAddr)
{
assert (s->elems != NULL);
assert (s->logLength != 0);
(s->logLength)--;
memcpy((void *)elemAddr, currentval(s), s->elemSize);
}
void *currentval(genStack *s)
{
assert (s->elems != NULL);
return ((size_t*)s->elems + s->logLength * s->elemSize);
}
bool GenStackEmpty (const genStack *s)
{
assert (s->elems != NULL);
return s->logLength == 0;
}
void GenStackDispose (genStack *s)
{
assert (s->elems != NULL);
s->logLength = 0;
free (s->elems);
freefn();
}
/*
* ToDO
*/
void *freefn (void *) {
free
And my header data is:
#ifndef GENSTACKLIB_H
#define GENSTACKLIB_H
#include <stdbool.h>
#define GenStackInitialAllocationSize 4
typedef struct
{
void *elems;
int elemSize;
int logLength;
int allocLength;
} genStack;
void GenStackNew (genStack * s, int elemSize);
bool GenStackEmpty (const genStack * s);
void GenStackPush (genStack * s, const void *elemAddr);
void GenStackPop (genStack * s, const void *elemAddr);
void GenStackDispose (genStack * s);
void *currentval(genStack *s);
#endif
In the first block of code, I believe that what has to be done is in the ToDo markings.
How can I make it to use my stack for complex data types?
Thanks in advance
I dont see any problem with "complex" types like strings... there is no real difference bewteen pointer to string and pointer to int. So just store pointers (or pointers to pointers) and that should work.
So instead of element to be "int".. element is pointer to pointer.
Basic idea in form of very "pseudo" C code
typedef struct Wrapper
{
void * primitiveData;
} Wrapper;
void PrimitivePush(void * data)
{
Wrapper * w = malloc();
w->primitiveData = malloc();
memcpy(w->primitiveData, data);
ClassicComplexTypePush(&w)
}
ClassicComplexTypePush(void ** data)
{
push data to stack
}
Consider using a singularly linked list for implementation, since when
using a stack, we don't know how many items may be needed.
Use a byte* or (char*) to store the contents of memory, instead of a void* (which would also work, but we may need to pad the allocation, to include structs)
Copy memory into a new allocation, which is pushed onto the stack,
then delete that used upon pop.
each node has to be of the same type, or at-least the same size,
errors using wrong type though may be undesired
pop can be either used to check if the stack is empty by passing (NULL)
or to actually pop the stack, by referencing the memory you want to set.
typedef unsigned char byte;
Create the structures which will be used to keep track of the stack
struct gStackNode {
byte *data;
struct gStackNode *next;
};
struct gStack {
unsigned size;
struct gStackNode *head;
};
Initialize the stack, including the size of the type we will be using
void stack_initalize(struct gStack *stk, unsigned size) {
if (!stk)
return;
stk->size = size;
stk->head = (void*)0;
}
Always, we need to manually free the stack, in-case not all were popped
void stack_free(struct gStack *stk) {
if (!stk)
return;
struct gStackNode *temp;
/* step through the remaining stack, deleting each item */
while(stk->head) {
temp = stk->head->next;
free((byte*)stk->head->data);
free((struct gStackNode *)stk->head);
stk->head = temp;
}
}
push an item onto the stack
void stack_push(struct gStack *stk, void *data) {
struct gStackNode *node = (struct gStackNode*)malloc(sizeof(struct gStackNode));
struct gStackNode *temp = stk->head;
node->next = temp;
node->data = (byte*)malloc(sizeof(byte)*(stk->size));
byte * src = (char*)(data);
byte * dest = (char*)(node->data);
unsigned n = stk->size;
/* fill the new allocation with source data */
for(;n;n--)
*(dest++) = *(src++);
/* the node becomes the new head */
stk->head = node;
}
Sometimes we don't want to use a local variable ie: stack_pop_(stack, &type) we can use stack_push_arg_no_ref(stack, 10).
void stack_push_arg_no_ref(struct gStack *stk, void *data) {
stack_push(stk, &data);
}
Now we can pop, and use the same to peek, passing (NULL) to data will result in a peek,
returning (1) if there is an item in the stack, and a (0) if its empty
int stack_pop(struct gStack *stk, void * data) {
if (!stk)
return 0;
if (!stk->head)
return 0;
if (data == (void*)0) {
/*
simply check to see if the stack is empty or not
don't actually pop the stack
*/
return ((!stk->head == (void*)0));
} else {
struct gStackNode *next = stk->head->next;
struct gStackNode *node = stk->head;
unsigned i;
byte *c_temp = (byte*)data;
for(i=0;i<stk->size;i++)
*c_temp++ = node->data[i];
free((byte*)node->data);
free((struct gStackNode*)node);
stk->head = next;
}
}
Finally we can implement the stack
using any ANSI C data types
the size of a character string needs to be fixed
structs can also be used
Using a character string
CAUTION, for this example, the strings need to be NULL terminated, though
it is possible to use non-NULL terminated strings
char ta[32] = "ta: text 1";
char tb[32] = "tb: text 2";
char tc[32];
struct gStack stack_char; stack_initalize(&stack_char, sizeof(ta));
stack_push(&stack_char, ta);
stack_push(&stack_char, tb);
while (stack_pop(&stack_char, &tc))
printf("%s\n", tc);
be sure to free the stack
stack_free(&stack_char);
Using integers
int a = 120, b = -32, c;
struct gStack stack_int; stack_initalize(&stack_int, sizeof(int));
stack_push(&stack_int, &a);
stack_push(&stack_int, &b);
/* or we can use */
stack_push_arg_no_ref(&stack_int, 1776);
/* we can now see the contents of the stack */
while (stack_pop(&stack_int, &c))
printf("%d\n", c);
stack_free(&stack_int);

Segmentation fault debugging help

I'm trying to implement a simple stack. It works fine on MacOSX but crashes on linux(Ubuntu). Can someone help me to know why?
MYStack.h
#ifndef MYSTACK_H_
#define MYSTACK_H_
typedef struct Element *element;
typedef struct Stack *stack;
struct Element {
struct Element *next;
void *data;
};
struct Stack {
struct Element *head;
unsigned int count;
void (*dump) (void *);
};
/* Define boolean type */
typedef signed char bool;
#define YES (bool)1
#define NO (bool)0
/* utility macro */
#define ELEMENT_NEXT(E) ((E) = (E)->next)
#define ELEMENT_DATA(E) ((E)->data)
#define STACK_HEAD(S) ((S)->head)
#define STACK_SIZE(S) ((S)->count)
/* Functions prototypes */
bool push( stack , void * );
bool pop( stack , void ** );
bool create_stack( stack , void (*) (void*) );
bool delete_stack( stack );
void dump_stack( stack );
#endif /* MYSTACK_H_ */
MYStack.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "MYStack.h"
/* Creating the stack */
bool create_stack( stack new_stack, void (*dump_function) (void*))
{
new_stack->head = NULL;
new_stack->dump = dump_function;
new_stack->count = 0;
return YES;
}
/* Deleting the stack */
bool delete_stack( stack this_stack )
{
element next_element;
while (this_stack->head) {
next_element = this_stack->head->next;
free(this_stack->head->next);
this_stack->head = next_element;
}
return YES;
}
/* Dump the stack */
void dump_stack(stack this_stack)
{
element e;
int i;
e = STACK_HEAD(this_stack);
if (this_stack->dump ) {
for (i = 0; i < this_stack->count; i++) {
(this_stack->dump) (e->data);
if (e->next != NULL)
e = e->next;
}
}
}
/* Adding element to the stack */
bool push( stack this_stack, void *data )
{
element new_element;
void (*temp_dump) (void *);
this_stack->dump = temp_dump;
new_element = (element ) malloc(sizeof(element *));
if (new_element == NULL) {
fprintf(stdout, "malloc() new element failed : %d\n", errno);
return NO;
}
new_element->data = data;
new_element->next = (this_stack)->head;
(this_stack)->head = new_element;
this_stack->dump = temp_dump;
(this_stack)->count++;
#ifdef DEBUG
fprintf(stdout, "Inserting at the stack in the address %p\n", new_element->data);
#endif
return YES;
}
/* Remving element from the stack */
bool pop( stack this_stack, void **data )
{
element delete_me;
void (*temp_dump) (void *);
this_stack->dump = temp_dump;
delete_me = this_stack->head;
if (delete_me == NULL) {
fprintf(stdout, "stack is empty\n");
return NO;
}
*data = delete_me->data;
this_stack->head = delete_me->next;
this_stack->dump = temp_dump;
this_stack->count--;
free(delete_me);
#ifdef DEBUG
fprintf(stdout, "Removing from the stack in the address %p\n", delete_me->data);
#endif
return YES;
}
/* Dump function test */
void dump_ints(void* data)
{
int* int_data_ptr = (int*)data;
printf("We are dumping an int data : %d\n", *int_data_ptr);
}
/* To test our stack */
int main (int argc, char const **argv)
{
stack new_stack;
void (*dump_func_ptr) (void*);
int i;
int stack_ints[] = {1, 2, 3, 4};
void *deleted_item;
#ifdef DEBUG
fprintf(stdout, "We are in debug mode...\n");
#endif
new_stack = (stack) malloc(sizeof(stack *));
dump_func_ptr = dump_ints;
create_stack( new_stack, dump_func_ptr);
/* Insert to the stack */
for (i = 0; i < 4; i++)
push( new_stack, &stack_ints[i]);
/* Print the number of elements */
printf("Our stack contain %d elements\n", new_stack->count);
/* Dump the stack */
dump_stack(new_stack);
/* Removing some data */
pop(new_stack, &deleted_item);
/* Dump the stack */
dump_stack(new_stack);
/* Deleting the stack */
//delete_stack(new_stack);
free(new_stack);
return 0;
}
There are a couple of incorrect allocations. They are only allocating memory the size of a pointer (4 bytes on a 32-bit system) and subsequent initialization of those pieces of memory will overwrite past the end of the allocated memory. The ones I noticed are these:
new_element = (element ) malloc(sizeof(element *));
and
new_stack = (stack) malloc(sizeof(stack *));
They should be something like this:
new_element = (element ) malloc(sizeof(struct Element));
new_stack = (stack) malloc(sizeof(struct Stack));
next_element = this_stack->head->next;
free(this_stack->head->next);
this_stack->head = next_element;
On the next iteration of the loop, you access this_stack->head, which has just been freed.

Resources