getting SEGFAULT when reading an array from shared memory - c

I'm new to using shared memory and for the first file the implementation is working fine but for the second file it is unable to read some of the structures from the shared memory . I think the problem is in my mmap but not quite sure what exactly
first file which works nicely:
struct Sh_Mem* open_res(int nb_tables)
{
size_t mem_size = MEM_SIZE(nb_tables);
int shm_fd=shm_open(MEM_NAME,O_RDWR|O_CREAT | O_TRUNC, 0600);
if(shm_fd<0)
raler("shm_open");
ftruncate(shm_fd,mem_size);
struct Sh_Mem * res=mmap(NULL,mem_size,PROT_READ| PROT_WRITE,MAP_SHARED,shm_fd,0);
if(res == NULL)
raler("mmap");
res->nb_tables=nb_tables;
res->size = mem_size;
return res;
}
int main(int argc, char const *argv[])
{
if (argc < 3)
raler("Usage : ./restaurant <duree_repas> <capacite_des_tables>");
int dinner_time = atoi(argv[1]);
int nb_tables = argc -2;
int fermeture=0;
struct table* tables=malloc(nb_tables*sizeof(struct table));
if (dinner_time < 100 )
raler("Duree de repas tres courte");
struct Sh_Mem* res=open_res(nb_tables);
res->table = malloc(nb_tables*sizeof(struct table));
for(int i = 2; i < (argc); i++)
{
if(atoi(argv[i])>6 || atoi(argv[i])<1 )
{
printf("\nERROR : %s\n ",argv[i] );
raler("Max Capacity of Tables is 6 ");
}
tables[i-2].size = atoi(argv[i]);
}
res->table=tables;
shm_unlink(MEM_NAME);
return 0;
}
Second file which give me a segmentation fault :
struct Sh_Mem* first_guest(char * nom)
{
int shm_fd=shm_open(MEM_NAME,O_RDWR, 0600);
if(shm_fd<0)
raler("shm_open");
struct stat stat;
if(fstat(shm_fd, &stat) < 0) {
perror("fstat");
exit(1);
}
struct Sh_Mem * guests=mmap(NULL,stat.st_size,PROT_READ| PROT_WRITE,MAP_SHARED,shm_fd,0);
if(guests == NULL)
raler("mmap");
return guests;
}
int main(int argc, char const *argv[])
{
if (argc != 3)
raler("Usage : ./convive <nom_du_convive> <nombres_de_personnes_dans_le_groupe/nom_du_premier_convive>");
if(strlen(argv[1])>10)
raler("Name has to be less or equal to 10 char ");
if(isdigit(argv[1][0]))
raler("First argument has to start with a character");
if (isdigit(argv[2][0]))
{
struct Sh_Mem* res=first_guest((char*)argv[1]);
for (int i = 0; i < res->nb_tables; i++)
{
if(res->table[i].used==1)
{
continue;
}
if(res->table[i].size == atoi(argv[2]))
{
found =1;
res->table[i].name=(char *)argv[1];
res->table[i].used =1;
}
printf("%s\n",res->table[i].name );
}
the error happens whenever i pass by a res->tables.
i tested if it was equal to null but it isn't
also here is the struct:
void raler(char *msg)
{
perror(msg);
exit(1);
}
struct table
{
int id;
int size;
char* name;
int nb_left;
int used;
};
struct Sh_Mem{
int nb_tables;
size_t size;
struct table* table;
};
#define MEM_NAME "/guest"
#define MEM_SIZE(nb_table) sizeof (struct Sh_Mem) + (nb_table)*sizeof (struct convive)+ (nb_table)*sizeof (struct table)

res->table[i].name=(char *)argv[1];
}
printf("%s\n",res->table[i].name );
This doesn't work. You are putting a pointer into the current process' address space into shared memory. This means nothing to any other process.
You can fix this by making name a fixed-length array or by allocating some shared memory and having name point to that. Just be careful -- each process will have to compute the correct local pointer to the shared memory since different processes may map the same shared memory segment at different addresses.

All i had to do is change the struct from dynamic to static and it works fine
struct Sh_Mem{
int nb_tables;
size_t size;
struct table table[];
};

Related

Segmentation fault in a c code, involving multithread

I have problems with my code. It's a multithreading program that executes the following Linux command "# cat | sort | uniq -c | sort -nr". When I try to run the program in a virtual machine, I get a segmentation error, no core dumped. I have tried everything to fix this, but I still get the error. I see that the problem is in the main function and I don't know what it is. Could be either in pthread_join or maybe could be the max number of threads, declared globally. Can someone help me out? This is my code.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#define MAX_THREADS 0x40
#define MAX_STRING 124ULL
struct string_count_entry {
char* string;
int count;
};
struct string_count {
int nb_string;
struct string_count_entry* entries;
};
struct string_count* string_count_init() {
struct string_count* sc;
sc = malloc(sizeof(sc));
sc->entries = NULL;
sc->nb_string = 0;
return sc;
}
int addstring(struct string_count* pt, char* s) {
int i;
for (i = 0; i < pt->nb_string; i++) {
if (strcmp(pt->entries[i].string, s))
break;
}
if (i == pt->nb_string) {
pt->entries = realloc(pt->entries,
pt->nb_string + 1 * sizeof(pt->entries[0]));
if (pt->entries == NULL)
return -1;
pt->nb_string++;
pt->entries[i].string = s;
}
pt->entries[i].count++;
return 0;
}
static inline int Compare(const void* pt1, const void* pt2) {
struct string_count_entry* a = malloc(sizeof(pt2));
struct string_count_entry* b = malloc(sizeof(pt1));
if (a->count == b->count)
return strcmp(a->string, b->string);
return a->count - b->count;
}
void string_count_pint(struct string_count* sc) {
int i;
qsort(sc->entries, sc->nb_string, sizeof(struct string_count), Compare);
i = 0;
while (i < sc->nb_string) {
printf("%d %s\n", sc->entries[i].count, sc->entries[i].string);
i++;
}
}
void string_count_free(void* pt) {
struct string_count* sc = malloc(sizeof(pt));
char i;
for (i = 0; i < sc->nb_string; i++) {
free(sc->entries[i].string);
}
free(sc->entries);
}
char* readline(void) {
int i = 0;
char c;
char* linebuf = (char*)malloc(MAX_STRING);
while (read(0, &c, 1) != 0) {
if (c == '\n') {
linebuf[i] = '\0';
return linebuf;
}
linebuf[i++] = c;
}
return NULL;
}
void* thread_main(void* arg) {
struct string_count* sc = malloc(sizeof(arg));
char* line;
while ((line == readline()) != '\0') {
addstring(sc, line);
}
return NULL;
}
int main(int argc, char** argv) {
int nbthreads;
int i;
pthread_t threads[MAX_THREADS];
struct string_count* sc;
if (argc != 1) {
fprintf(stderr, "usage: %s <nb threads>\n", argv[0]);
return EXIT_FAILURE;
}
nbthreads = atoi(argv[1]);
sc = malloc(sizeof(nbthreads));
for (i = 0; i < nbthreads; i++) {
pthread_create(&threads[i], NULL, thread_main, sc);
}
do {
pthread_join(threads[nbthreads--], NULL);
} while (nbthreads > 0);
string_count_free(sc);
string_count_pint(sc);
return EXIT_SUCCESS;
}
I suspect the bug is in this line: sc = malloc(sizeof(nbthreads));
You probably wanted sc = malloc(sizeof(string_count));
I'm also not sure if struct string_count* sc = malloc(sizeof(arg)); does what you intended in thread_main.
You probably need the sc in main be an array and pass a different item in it to each thread and then aggregate them after the join.
Here are the first few errors I have spotted, in no particular order.
Unprotected modification of data structures from multiple threads. Read something about multithreading. Pay attention to the word "mutex".
pthread_join(threads[nbthreads--], NULL); goes out of bounds.
struct string_count* sc = malloc(sizeof(arg)); makes no sense. sizeof(arg) is the size of a pointer (8 on most PC-like systems). This is not enough to hold one struct string_count.
struct string_count_entry* a = malloc(sizeof(pt2)); apparently has even less sense. You are allocating something in a string comparison function, using a wrong size, then you are using the allocated memory without initializing it, and without even trying to compare the things passed to the function.
while ((line == readline()) != '\0') does not assign anything.
pt->entries = realloc(pt->entries, pt->nb_string + 1 * sizeof(pt->entries[0])); is missing a couple of parentheses.

Getting core dumps when free() is used

I'm doing a school assignment and the driver was given to me along with the header file. My job is to complete the functions that read data from a text file and then search it for a name and return the email address. It's a huge exercise in using pointers and structures.
The program reads in a text file of names and email addresses then dynamically creates a structure array using malloc(). The struct Card is built of two char pointers and I find the length of the data using strlen(), malloc() memory for that size and assign the struct to the memory address given.
It all seems to work fine until the end after it has printed the name and email and is about to free() the memory. I get an Aborted (core dump) message every time. Don't know what the issue could be.
I've placed a printf() just before the free() to try and track down where the issue is but it appears to be happening either during the name/email printout or just after it happens because my printf() test point that is one line before the free() is never executed.
I'm assuming the driver program is okay and it has something to do with my functions.
Anyone care to take a stab at it?
//Main
#include <stdio.h>
#include <stdlib.h>
#include "lab9utils.h"
int main(int argc, char * argv[]) {
// Variable declarations.
struct Card * cards;
int size;
int k;
char * email;
// Make sure we have 2 extra command-line paramgers.
if (argc < 3) {
printf("Usage: ./lab9.exe <data_filename> <name_to_lookup>");
return 0;
}
// Get the cards and do the lookup.
cards = getCards(argv[1], &size);
email = lookup(cards, argv[2], size);
// Display the output message ("sorry!" or "name -> email").
if (email == NULL) {
printf("Sorry, that name was not in the list of cards.\n");
} else {
printf("%s -> %s\n", argv[2], email);
}
// Free the memory used by the structures.
k = 0;
printf("Test Point#1");
for (k = 0; k < size; k++) {
free(cards[k].name);
free(cards[k].email);
}
printf("Test Point#2");
free(cards);
return 0;
}
// Header
#ifndef LAB9UTILS_H
#define LAB9UTILS_H
struct Card {
char * name;
char * email;
};
struct Card * getCards(char * filename, int * size);
char * lookup(struct Card * cards, char * name, int size);
#endif
// Functions
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lab9utils.h"
struct Card * getCards(char * filename, int * size_return) {
int i,size;
char cTempName[51]={0};
char cTempEmail[51]={0};
size = 0;
// I/O Setup
FILE *fp;
fp = fopen(filename,"r");
// error checking
if(fp == NULL)
{
perror("Error in opening file");
return(NULL);
}
// Input Loop
while(!feof(fp))
{
fscanf(fp,"%s%s",cTempName,cTempEmail);
size++;
}
size=size-1;
fclose(fp);
struct Card * card = (struct Card *)malloc(*size_return * sizeof(struct Card));
fp = fopen( filename ,"r");
// error checking
if(fp == NULL)
{
perror("Error in opening file");
return(NULL);
}
for(i=0;i<size;i++)
{
fscanf(fp,"%s%s",cTempName,cTempEmail);
card[i].name=(char *)malloc((strlen(cTempName)+1));
card[i].email=(char *)malloc((strlen(cTempEmail)+1));
strcpy(card[i].name,cTempName);
strcpy(card[i].email,cTempEmail);
}
fclose(fp);
// loop to confirm data was read
for(i=0;i<size;i++)
{
printf("[ %d ] Name:%s email:%s Total size:%d\n",i,card[i].name,card[i].email,size);
}
*size_return = size;
return card;
}
char * lookup(struct Card * cards, char * name, int size) {
int i;
for(i=0;i<size;i++)
{
if (strcmp(cards[i].name,name)==0)
{
return cards[i].email;
}
}
return NULL;
}
The value of *size_return is garbage, because you are setting it to size only at the end of the function.
Change this:
struct Card * card = (struct Card *)malloc(*size_return * sizeof(struct Card));
To this:
struct Card * card = (struct Card *)malloc(size * sizeof(struct Card));

Passing struct to functions

Hey I'm not sure why when I pass a Struct array to a function; When I try to access it's members it prints random number. Below the statement "printf("%d\n", netTopo[0].nodes[1]);" works correct but I'm in the function and try print the same data, it prints a bunch of random number? Not sure what I'm doing wrong.
int main(int argc, char *argv[]) {
if (argc != 3){
printf("Incorrect command line arguments. Required 2 files.\n");
exit(-1);
}
FILE *netFile, *schFile; // put into a loop
netFile = fopen(argv[1], "r");
schFile = fopen(argv[2], "r");
int *sched = getSchedFile(schFile);
struct nodeInfo *netTopo = getTopology(netFile);
printf("%d\n", netTopo[0].nodes[1]);
int nodeSocks[nodeCount];
for (int i=0; i<nodeCount; i++){
nodeSocks[i]=getSocketNo();
}
get_elapsed_time(); // start clock
for (int i=0; i<nodeCount; i++){
if (fork()==0){
nodeExecution(i, nodeSocks, netTopo, sched);
exit(0);
}
}
}
void nodeExecution(int id, int nodes[], struct nodeInfo *netTopo, int *schd){
printf("%d\n", netTopo[0].nodes[1]);
......
so you return a pointer to local var on stack from getTopology()? that's the bug.
netTopo is on stack and when you return from getTopology() there are other function calls which would reuse the memory region where netTopo is stored. That memory is modified and you get different output when calling nodeExecution()
ADD: to fix this you may allocate memory in getTopology():
struct nodeInfo* getTopology(FILE *file){
int id, digit=0, totLinks=0;
fscanf(file, "%d", &nodeCount);
struct nodeInfo * netTopo = malloc(sizeof(struct nodeInfo)*nodeCount);
....

Memory Allocation for a Dynamic List of Strings

I'm writing a program in C that's supposed to take several string of text from a file and put them inside a dynamic list.
For some reason (probably memory allocation) I get this error every time I try to put more than fifteen strings into the structure:
*** glibc detected *** ./driver: realloc(): invalid next size: 0x000000000241e250 ***
The code is as follows:
dlist.h
struct dlist
{
int size;
int maxSize;
char item[1][1024];
};
#define INITSIZE 6
#define INCRSIZE 9
#define DLISTSIZE(n) ((size_t)(sizeof(struct dlist) + (n*1024)))
struct dlist *initDlist(int num);
int insDlist(char data[], struct dlist **p);
void printDlist(struct dlist *p);
void debugDlist(struct dlist *p);
int stringCmp(const void *a, const void *b);
dlist.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dlist.h"
struct dlist *initDlist(int num)
{
struct dlist *p;
p = malloc( DLISTSIZE(num) );
if(p == NULL)
return(NULL);
p->size = 0;
p->maxSize = num;
return(p);
}
int insDlist(char data[], struct dlist **p)
{
struct dlist *q;
//printf(" DEBUG: Checking remaining memory.\n");
if ((*p)->size == (*p)->maxSize)
{
//printf(" DEBUG: Out of memory, reallocating now...\n");
q = realloc(*p, DLISTSIZE((*p)->maxSize + INCRSIZE));
if(q == NULL)
return(-1);
q->maxSize += INCRSIZE;
*p = q;
}
//printf(" DEBUG: Space available.\n");
int i;
(*p)->size++;
//adding data to the list
for(i = 0; i < 1024; i++)
(*p)->item[(*p)->size][i] = data[i];
return(0);
}
void printDlist(struct dlist *p)
{
int i;
for(i = 0; i <= p->size; i++)
printf("%s", p->item[i]);
}
void debugDlist(struct dlist *p)
{
int i;
fprintf(stderr, "\nDynamic List Debug Data\n\n");
fprintf(stderr, " size = %d\n", p->size);
fprintf(stderr, " maxSize = %d\n", p->maxSize);
for(i = 0; i <= p->maxSize; i++)
fprintf(stderr, " %s\n", p->item[i]);
}
int stringCmp(const void* a, const void* b)
{
const char *ia = (const char *)a;
const char *ib = (const char *)b;
return strncmp(ia, ib, 1023);
}
driver.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "dlist.h"
int main(int argc, char *argv[])
{
printf("\n");
FILE *fp;
char text[1024];
//check the command line
if(argc != 2)
{
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return(-1);
}
//open file given on command line
fp = fopen(argv[1], "r");
if(fp == NULL)
{
perror(argv[1]);
return(-1);
}
//initialize the dynamic list
struct dlist *p;
p = initDlist(INITSIZE);
if(p == NULL)
{
perror("Unable to malloc dlist");
return(-1);
}
//read each line then store it in the dynamic list
while(fgets(text, 1024, fp) != NULL)
{
//printf("DEBUG: Preparing to insert data.\n");
if( insDlist(text,&p) == -1)
{
perror("Unable to realloc dlist");
return(-1);
}
//printf("DEBUG: Data inserted successfully.\n\n");
}
//debugDlist(p);
printDlist(p);
//printf("\nNow sorting...\n\n");
//qsort(&(p->item), p->size, 1, stringCmp);
//debugDlist(p);
//printDlist(p);
return(0);
}
Any help is appreciated, thanks in advance.
The issue is almost definitely that you are incrementing the size of the list before copying the data:
(*p)->size++;
//adding data to the list
for(i = 0; i < 1024; i++)
(*p)->item[(*p)->size][i] = data[i];
You should reorder these statements:
//adding data to the list
for(i = 0; i < 1024; i++)
(*p)->item[(*p)->size][i] = data[i];
(*p)->size++;
Also, if you're allowed, the following is equivalent:
// adding data to the list
memcpy( (*p)->item[(*p)->size],
data,
1024 );
(*p)->size++;
To elaborate, the indices are zero-based. As an example, when you allocate 6 arrays, you copy into the indexes [1], [2], [3], [4], [5], and [6].
You want to copy into indexes [0], [1], ... [5].
Additionally, the reason that you see the error only after allocating some specific number has to do with the heap allocator.

request for member ' ' in something not a structure or union error hashTable separate chaining

The following code gives me the following errors :
error: request for member ‘name’ in something not a structure or union
error: request for member ‘name’ in something not a structure or union
error: request for member ‘data’ in something not a structure or union
error: request for member ‘next’ in something not a structure or union
How could I fix it ?
Code is :
#define SIZE 5
typedef struct hashTable{
int data;
char *name;
struct hashTable *next;
} table;
int hash_function(int value)
{
return value % SIZE;
}
int insert(char *inFileName, table ***hashLinked)
{
FILE *inFile;
int val = -1;
char str[30];
int probe;
if ((inFile = fopen(inFileName, "r")) == NULL)
{
fprintf(stderr,"Error opening input file, %s\n", inFileName);
return -1;
}
while(fscanf(inFile,"%s %d",str,&val) == 2)
{
probe = hash_function(val);
if(hashLinked[probe] == NULL)
{
**hashLinked[probe] = malloc(sizeof(table));
**hashLinked[probe]->name = (char *)malloc((strlen(str) + 1) * sizeof(char*));
strcpy(**hashLinked[probe]->name,str);
**hashLinked[probe]->data = val;
**hashLinked[probe]->next = NULL;
}
else
{
table* hashLinkedNode = *hashLinked[probe];
while(hashLinkedNode->next!=NULL)
{
hashLinkedNode = hashLinkedNode->next;
}
hashLinkedNode->next = malloc(sizeof(table));
hashLinkedNode->next->name = (char *)malloc((strlen(str) + 1) * sizeof(char*));
strcpy(hashLinkedNode->next->name,str);
hashLinkedNode->next->data = val;
hashLinkedNode->next->next = NULL;
}
}
fclose(inFile);
return 0;
}
void printList(BookNode *hd)
{
for ( ; hd != NULL; hd = hd->next)
{
printf("[%s,%d]", hd->name, hd->isbn);
if (hd->next)
printf(" -> ");
}
printf("\n");
}
void printHashTable(BookNode **temp)
{
BookNode *tmp = NULL;
int i;
for(i=0;i<SIZE;i++)
{
tmp = temp[i];
while(tmp)
{
printf("%s %d",tmp->name, tmp->isbn);
tmp=tmp->next;
}
}
}
int main(int argc, char *argv[])
{
table **hashLinked[SIZE];
insert(argv[1],&hashLinked);
printHashTable(**hashLinked);
return 0;
}
One problem is that you call insert with something other than the type you declared it with,
table **hashLinked[SIZE];
insert(argv[1],&hashLinked);
hashLinked is an array of pointers to pointers to table, so &hashLinked is a pointer to an array of pointers to pointers to table, but insert is declared to take a pointer to pointer to pointer to table. I'm less than confident that I really figured out what you intended to do, but what seems to be reasonable is that you want fewer levels of indirection. I believe the reason for passing &hashLinked is that you want hashLinked to be modified in insert, but that is already done by passing hashLinked itself, you needn't pass its address. That would make the passed type compatible with the declared type, since as a function argument, hashLinked becomes a pointer to its first element, a table ***.
Then you use inconsistent indirection counts in insert, and get the precedence of * and -> wrong, which causes the "request for member in something that isn't a struct or union" errors. **hashLinked[probe]->name is parsed **(hashLinked[probe]->name), so tries to access the name member of a table * and then dereference that twice. With the parameter type table ***, the correct access would be (*hashLinked[probe])->name, get a table ** per hashLinked[probe], dereference that once to get a table * and access its (pointee)member name. However, you check if (hashLinked[probe] == NULL), and if so
**hashLinked[probe] = malloc(sizeof(table));
which is a guaranteed null pointer dereferencing. By the check and the following code, I believe that you actually want to have a parameter type of table **, the hashLinked parameter being an array of linked lists of tables, which makes the code far easier to follow. Filling in a BookNode type and adapting a few variables and parameters, I arrive at
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define SIZE 5
typedef struct hashTable {
int data;
char *name;
struct hashTable *next;
} table;
typedef struct book {
int isbn;
char *name;
struct book *next;
} BookNode;
int hash_function(int value)
{
return value % SIZE;
}
int insert(char *inFileName, table **hashLinked)
{
FILE *inFile;
int val = -1;
char str[30];
int probe;
if ((inFile = fopen(inFileName, "r")) == NULL)
{
fprintf(stderr,"Error opening input file, %s\n", inFileName);
return -1;
}
while(fscanf(inFile,"%s %d",str,&val) == 2)
{
probe = hash_function(val);
if(hashLinked[probe] == NULL)
{
hashLinked[probe] = malloc(sizeof(table));
hashLinked[probe]->name = (char *)malloc((strlen(str) + 1) * sizeof(char*));
strcpy(hashLinked[probe]->name,str);
hashLinked[probe]->data = val;
hashLinked[probe]->next = NULL;
}
else
{
table* hashLinkedNode = hashLinked[probe];
while(hashLinkedNode->next!=NULL)
{
hashLinkedNode = hashLinkedNode->next;
}
hashLinkedNode->next = malloc(sizeof(table));
hashLinkedNode->next->name = (char *)malloc((strlen(str) + 1) * sizeof(char*));
strcpy(hashLinkedNode->next->name,str);
hashLinkedNode->next->data = val;
hashLinkedNode->next->next = NULL;
}
}
fclose(inFile);
return 0;
}
void printList(BookNode *hd)
{
for ( ; hd != NULL; hd = hd->next)
{
printf("[%s,%d]", hd->name, hd->isbn);
if (hd->next)
printf(" -> ");
}
printf("\n");
}
void printHashTable(table **temp)
{
table *tmp = NULL;
int i;
for(i = 0; i < SIZE; i++)
{
tmp = temp[i];
while(tmp)
{
printf("%s %d",tmp->name, tmp->data);
tmp = tmp->next;
}
}
}
int main(int argc, char *argv[])
{
if (argc < 2)
return -1;
table *hashLinked[SIZE];
insert(argv[1],hashLinked);
printHashTable(hashLinked);
return 0;
}
which compiles warning-free and looks like it might do what you intended.

Resources