Disclaimer: I am new to C arrived here from other languages. What I observe breaks my head I do not even have a starting point to explain the observed behavior.
Scenario: Play around with a self-written stack implementation to get a feeling for the language and to compare different approaches.
Compiler in use:
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
Minimized code example:
#include <stdio.h>
struct stack_entry
{
struct stack_entry *next;
int *item;
};
struct stack
{
struct stack_entry *first;
};
void push_to_stack(struct stack *s_ptr, int *item)
{
struct stack_entry new_entry = {.next = s_ptr->first, .item = item};
s_ptr->first = &new_entry;
printf("item_address#push_to_stack %p\n", s_ptr->first->item);
}
void pop_from_stack(struct stack *s_ptr)
{
printf("item_address#pop_from_stack %p\n", s_ptr->first->item);
int* result = NULL;
}
int main()
{
printf("\n--stack test--\n");
struct stack s = {};
struct stack *s_ptr = &s;
int value = 42;
push_to_stack(s_ptr, &value);
printf("item_address#main: %p\n", s_ptr->first->item);
pop_from_stack(s_ptr);
return 0;
}
Unexpected output:
--stack test--
item_address#push_to_stack 0x7fffa759b67c
item_address#main: 0x7fffa759b67c
item_address#pop_from_stack 0x7fffa759b680
As one observes the item_address#pop_from_stack differs for some reason. I expect the output:
--stack test--
item_address#push_to_stack 0x7ffdc30ee19c
item_address#main: 0x7ffdc30ee19c
item_address#pop_from_stack 0x7ffdc30ee19c
To receive the expected output I need to remove the pointer declaration+initialization. In case I leave it in place the unexpected output occurs. So the following does the change:
// int* result = NULL;
But why? This totally puzzles me.
This will trigger undefined behavior later on:
struct stack_entry new_entry = {.next = s_ptr->first, .item = item};
s_ptr->first = &new_entry;
because new_entry will die when push_to_stack() ends.
But why? This totally puzzles me.
When compiled without optimizations, that line is likely making the compiler allocate space for result in the pop_from_stack() frame. Such a thing will make the behavior of the program change due to the undefined behavior shown above.
Related
I am attempting to implement my own version of a semaphore into a linux vm and am running into a crash when I attempt to lock a spinlock inside the down function. Using GDB I found that the down is called immediately after the create function so the problem is definitely there.
Here is the create function:
asmlinkage long sys_create(int value, char name[32], char key[32]){
struct sem *new_sem = (struct sem*) kmalloc(sizeof(struct sem), GFP_ATOMIC);
struct sem_node *new_sem_node = (struct sem_node*) kmalloc(sizeof(struct sem_node), GFP_ATOMIC);
struct sem_node *curr_sem = sem_list_head;
new_sem_node->sem = new_sem;
spin_lock(&sem_lock);
new_sem->sem_id = IDcntr++;
spin_lock_init(&(new_sem->lock));
strncpy(new_sem->key, key, 32);
strncpy(new_sem->name, name, 32);
if(curr_sem == NULL)
{
sem_list_head = new_sem_node;
}
else
{
while(curr_sem->next != NULL)
{
curr_sem = curr_sem->next;
}
curr_sem->next = new_sem_node;
}
spin_unlock(&sem_lock);
return new_sem->sem_id;
}
Functions spin_lock, spin_unlock, and spin_lock_init are working as intended. The down function calls:
spin_lock(&(sem_list_head->sem->lock));
right at the beginning and freezes. To be more specific, in the gdb terminal, I try and get to the next line and it stops and in the actual machine it's completely stopped. No other functions are called between the create and down function. Below is the header file that defines the sem_node, process_node, and sem objects used in the create and down functions:
int IDcntr = 1;
DEFINE_SPINLOCK(sem_lock);
struct sem_node
{
struct sem* sem;
struct sem_node* next;
};
struct process_node
{
struct process_node* next;
struct task_struct* task;
};
struct sem
{
int value;
long sem_id;
spinlock_t lock;
char key[32];
char name[32];
struct process_node* head;
struct process_node* tail;
};
struct sem_node* sem_list_head = NULL;
Through independent testing the function DEFINE_SPINLOCK and object spinlock_t are working as intended. After thorough debugging the problem is in the create function. I freely admit that I am still learning how semaphores work so chances are I didn't set variables correctly or define things correctly. Any help in pointing me the right way would be greatly appreciated.
I want to create an array of struct pointers and set each pointer to null. Eventually I want to have the pointers in the array point to my struct. I believed I had the write code to this but I keep getting a seg fault.
Code:
//struct in my .h
struct bin{
double cac; // current available capacity
struct node *list //pointer to linked list... bin struct points to linked list struct
}
//main file
void main(){
struct bin *bArray[20];
struct bin *binTemp, *pTemp;
for(i=0;i<20;i++) bArray[i]= NULL;
}
I assumed this would create an array of bin pointers, but I'm getting a seg fault here. Shouldn't I be able to make all the pointers NULL regardless of what type of pointer they are?
Eventually I want to make these all point to bin structs and I thought I could do this without having to make the pointers NULL first so i tried:
for(i=0;i<20;i++){
binTemp = (struct bin *)malloc(sizeof(struct bin));
binTemp->cac = 1.0;
binTemp->list = NULL;
bArray[i] = binTemp;
}
Once again I got a seg fault. I have no idea whats going on here. I know seg faults means I'm trying to write to an illegal memory location which makes me think I would have to set the size of the array indexes with malloc. However,
for(i=0;i<20;i++) bArray[i]= malloc(sizeof(struct bin));
also gives me a seg fault. I have no idea what I'm doing wrong.
Actual code I ran:
//Header File
#ifndef hBin_h
#define hBin_h
#include <stdio.h> // stdio used for file io
#include <stdlib.h> // standard c library
#define MAX_S 20
//bin struc
struct bin {
double cac; //current available capacity
struct node *list; // pointer to linked list
};
//linked list node struct
struct node{
char *name; //name of item
double size; // weight of item
struct node *next; //pointer to next
};
//insert the new item into a node in its appropriate location using alphabetical ordering of item names
struct node *oInsert(char *item, double size, struct node *head);
//print the items of the list out along with the list’s capacity
void traverse(struct node *head);
// deallocate the nodes of the list
void destory(struct node *head);
//input info from file - name of object, weight of object
void input(FILE *inFile, char item[], double *weight);
#endif // hBin_h
#include "hBin.h"
void main(){
FILE *inFile;
char *item;
double *weight;
struct bin *bArray[20];
int i;
struct bin *binTemp, *pTemp;
inFile = fopen("run1.txt", "r"); //open file
printf("HERE1\n");
for(i=0;i<20;i++){
binTemp = (struct bin *)malloc(sizeof(struct bin));
binTemp->cac = 1.0;
binTemp->list = NULL;
bArray[i] = binTemp;
}
/*while(!feof(inFile)){
input(inFile, item, weight);
printf("%s, %.2f\n", item, *weight);
}*/
}
I used gdb (not totally sure what I'm doing here):
(gdb) run
Starting program: /home/Christopher/CSC362/Pass_F/Main
[New Thread 813244.0xc7590]
[New Thread 813244.0xc6ce0]
[New Thread 813244.0xc7320]
[New Thread 813244.0xc5994]
HERE1
0 [main] Main 813244 cygwin_exception::open_stackdumpfile: Dumping stack trace to Main.exe.stackdump
[Thread 813244.0xc7320 exited with code 35584]
[Thread 813244.0xc6ce0 exited with code 35584]
[Inferior 1 (process 813244) exited with code 0105400]
(gdb) where
No stack.
(gdb) for(i=0;i<20;i++){
binTemp->cac = 1.0;
binTemp->list = NULL;
bArray[i] = binTemp;
} /usr/src/debug/cygwin-2.2.1-1/winsup/cygwin/crt0.c: No such file or directory.
(gdb) binTemp = (struct bin *)malloc(sizeof(struct bin));
Undefined command: "binTemp". Try "help".
(gdb) binTemp->cac = 1.0;
Undefined command: "binTemp->cac". Try "help".
(gdb) binTemp->list = NULL;
Undefined command: "binTemp->list". Try "help".
(gdb) bArray[i] = binTemp;
Undefined command: "bArray". Try "help".
(gdb) } for(i=0;i<20;i++){
Undefined command: "". Try "help".
(gdb) binTemp = (struct bin *)malloc(sizeof(struct bin));
Undefined command: "binTemp". Try "help".
(gdb) binTemp->cac = 1.0;
Undefined command: "binTemp->cac". Try "help".
(gdb) binTemp->list = NULL;
Undefined command: "binTemp->list". Try "help".
(gdb) bArray[i] = binTemp;
Undefined command: "bArray". Try "help".
(gdb) } for(i=0;i<20;i++){
binTemp->cac = 1.0;
Undefined command: "". Try "help".
(gdb) binTemp = (struct bin *)malloc(sizeof(struct bin));
Undefined command: "binTemp". Try "help".
(gdb) binTemp->cac = 1.0;
Undefined command: "binTemp->cac". Try "help".
(gdb) binTemp->list = NULL;
Undefined command: "binTemp->list". Try "help".
(gdb) bArray[i] = binTemp;
Undefined command: "bArray". Try "help".
Reading your code you commented out, you pass the variable weight to the input function and right after dereference it in your call to printf. There is a major problem here, and that is that the variable weight is not initialized, and that passing it to a function passes it by value, which means that the variable is copied and the function only operates on the copy and not the original, meaning that the weight variable in your main function will still be uninitialized when you dereference it and that leads to undefined behavior and a probable crash.
If you intend to emulate pass by reference (you can only emulate since C doesn't have passing by reference), you should declare weight as a normal variable, and use the address-of operator when calling the function:
double weight;
...
input(inFile, item, &weight);
// ^
// |
// Note ampersand here
You have a similar problem with the item variable. It's uninitialized and doesn't point anywhere special. Using it in any way except to initialize it will lead to undefined behavior. And if you try to initialize it in the input function then you have the same problem as described above, and you need to pass a pointer to the pointer using the address-of operator.
If you don't initialize the item pointer in the input function, but use it like it's already pointing to some valid memory (using e.g. strcpy or similar function) then you also have undefined behavior.
The actual crash you experience might be totally unrelated to the problems I describe above, since you seem to be doing something involving linked lists, which of course means pointers, and pointers used wrongly will give you many chances for further undefined behaviors and crashes.
The first thing you should do is enable more warning when building, as the compiler is usually very good at finding suspect behavior that can lead to UB. You do that by adding e.g. the flags -Wall -Wextra -pedantic when building.
So here is my issue, I have been trying to figure this out for the last 5 hours, I have a header file, a tester file, and a c source file. I would really like to understand what is happening and why so I can avoid the issue in the future. The header file declares the struct but does not define it:
typedef struct Stack *StackP;
and in my source file, Stack.c I have defined the stack:
struct Stack
{
int top;
int capacity;
int count;
ItemT items;
};
where ItemT is defined as char *
in the tester file, the call goes:
StackP stackPtr = newStack();
and what I have for my newStack function located in the c source file is:
StackP newStack(void) {
struct Stack stack1;
StackP stackPtr = &stack1;
(stackPtr->items) = (ItemT)malloc(DEFAULT_CAPACITY*sizeof(ItemT));
(stackPtr->top) = -1;
(stackPtr->capacity) = DEFAULT_CAPACITY;
(stackPtr->count) = 0;
fprintf(stderr, "\nSuccesfully allocated memory to items...\n");
return stackPtr;
}
now, my push function is:
void pushStack(StackP stackPtr, ItemT item) {
if ((stackPtr->count) == (stackPtr->capacity)) {
fprintf(stderr, "\nERROR: Full stack.\n");
}
else {
stackPtr->items = item;
fprintf(stderr, "\nSuccessfully pushed %s on to the stack...\n", stackPtr->items);
(stackPtr->items)++;
(stackPtr->top)++;
(stackPtr->count)++;
}
}
My question is this: Have I don't something wrong in any of these blocks of code.
If I call a function that says:
return (stackPtr->count);
it will return a random set of numbers instead of 0, or 1. For instance, if I push 2 strings to the stack, instead of count being 2, count is 479622 or some other random long number. Why is this happening?
Again, I would like to know what I'm doing wrong and not just correct syntax because I really HAVE to understand this.
The program has undefined behaviour as it is returning the address of a local variable from a function:
StackP newStack(void) {
struct Stack stack1;
StackP stackPtr = &stack1;
return stackPtr;
}
stack1 no longer exists when newStack exits. stackPtr must point to dynamically allocated memory if it is to exist beyond the scope of the function:
StackP newStack(void) {
struct Stack stack1;
StackP stackPtr = malloc(sizeof(*stackPtr));
if (stackPtr)
{
}
return stackPtr;
}
See Do I cast the result of malloc?
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.
I'm admittedly a straight-C newbie, but this has got me stumped. I'm working on a linked list implementation for practice, and I'm getting a segfault by simply adding a variable to the split_node function:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Node {
struct Node *child;
char *content;
};
void print_list(struct Node node);
void split_node(struct Node *node, int position);
int main() {
struct Node head, second, third;
head.content = "first";
second.content = "second";
third.content = "i'm third";
head.child = &second;
second.child = &third;
print_list(head);
split_node(&head, 3);
print_list(head);
return 0;
}
void print_list(struct Node node) {
printf("%s\n", node.content);
if(node.child) print_list(*node.child);
}
/*
Split node into two nodes, with the first position characters of the node's content remaining with node, and the remainder being copied to the new node. (It doesn't yet truncate the first node's string, but does do the copy.)
*/
void split_node(struct Node *node, int position) {
if(position >= strlen((*node).content)) return;
struct Node newNode;
newNode.child = (*node).child;
(*node).child = &newNode;
int length = (strlen((*node).content) - position);
newNode.content = malloc(sizeof(char) * (length + 1));
strncpy(newNode.content, (*node).content + sizeof(char) * position, length);
newNode.content[length] = '\0';
//int foo;
}
This code compiles (gcc -Wall -o list list.c) and runs fine:
$ ./list
first
second
i'm third
first
st
second
i'm third
But if I uncomment int foo at the end of split_node, compile and run, I get:
$ ./list
first
second
i'm third
first
st
Segmentation fault
gdb gives me this backtrace:
#0 0x91d6ae70 in strlen ()
#1 0x91dd3126 in puts ()
#2 0x00001f21 in print_list (node={child = 0xbcec815b, content = 0x8b000000 <Address 0x8b000000 out of bounds>}) at list.c:41
#3 0x00001f3c in print_list (node={child = 0x8fe0154b, content = 0x1ff6 "i'm third"}) at list.c:42
#4 0x00001f3c in print_list (node={child = 0xbffff568, content = 0x1fef "second"}) at list.c:42
#5 0x00001f3c in print_list (node={child = 0xbffff570, content = 0x1fe9 "first"}) at list.c:42
#6 0x00001ee0 in main () at list.c:33
Why would adding a variable definition cause a segfault? It appears to be smashing the content pointer of the newly created node. I'm confused; any help?
You need to dynamically allocate your nodes (using malloc).
As you have it, your new node is declared on the stack. When the split function returns, that new node is no longer valid memory.
Adding a variable causes a segfault because that variable changes the layout of the stack causing slightly different behavior when the function returns.
Try setting the Nodes child property to NULL, C doesn't automagically zero out memory so it looks like your may have garbage in child (or your could use calloc instead of malloc). SoapBox's answer is also correct.
Valgrind is a great tool to help find these types of problems. You can just do "valgrind myappname" from the command line and it will give you details on these types of errors.