Reputation: 813
I am trying to push a struct with its respective nodes inside a shared memory where another program will be reading the node content to do some validation(just reading, no modification). Each node of the linked list contains several variables, and a lot of nodes as well
My Struct:
typedef struct DNode {
char *polname;
char *devname;
char *status;
char *srczone;
char *dstzone;
char *srcaddr;
char *dstaddr;
char *srcuser;
char *app;
char *service;
char *urlcategory;
char *action;
char *vulnerability;
int isok;
struct DNode *next;
} Current;
struct DNode *head = NULL;
int list_insert_front(struct DNode* new_node) {
struct DNode *temp;
temp = malloc(sizeof *temp);
if (temp && new_node) {
memcpy(temp, new_node, sizeof(struct DNode));
temp->next = head;
head = temp;
return 1;
}
return 0;
}
This struct is using the function list_insert_front
to get data from an XML file and populate the list. This linked list is now to be stored inside a shared memory for faster processing and easy read-ups for other programs.
However, I am unable to do so (because of pointer mistakes). I am able to send an integer data to my client which is easily readable, but when I try the same with the list, BAM Segmentation fault
occurs.
Main.c
int main(int argc, char **argv)
{
Current aaron;
Current *dlist;
int key = 5555;
int shmid;
xmlDocPtr doc;
xmlNode *root_element = NULL;
dlist = &aaron;
if (argc != 2)
{
printf("\nInvalid argument\n");
return(1);
}
doc = xmlReadFile(argv[1], NULL, XML_PARSE_NOBLANKS | XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NONET);
if (doc == NULL)
{
fprintf(stderr, "Document not parsed successfully.\n");
return 0;
}
root_element = xmlDocGetRootElement(doc);
if (root_element == NULL)
{
fprintf(stderr, "empty document\n");
xmlFreeDoc(doc);
return 0;
}
printf("Root Node is %s\n", root_element->name);
traverse_dom_trees(root_element);
shmid = shmget(key, sizeof(aaron), IPC_CREAT | 0660);
if (shmid < 0) exit (1);
dlist = shmat(shmid, NULL, 0);
if (dlist == (void *) (-1))
exit(1);
printf("dlist alloc\n");
(*dlist).isok = 10;
printf("dlist val: %d\n", (*dlist).isok);
//This integer value is printed and read by the client, but not the linked list
while (Current.next != NULL){
(*dlist).polname = aaron.polname;
(*dlist).devname = aaron.devname;
(*dlist).status = aaron.status;
(*dlist).srczone = aaron.srczone;
(*dlist).dstzone = aaron.dstzone;
(*dlist).srcaddr = aaron.srcaddr;
(*dlist).dstaddr = aaron.dstaddr;
(*dlist).srcuser = aaron.srcuser;
(*dlist).app = aaron.app;
(*dlist).service = aaron.service;
(*dlist).urlcategory = aaron.urlcategory;
(*dlist).action = aaron.action;
(*dlist).vulnerability = aaron.vulnerability;
Current = Current.next;
}
printf("printing list: ");
shmdt(dlist);
xmlFreeDoc(doc);
xmlCleanupParser();
return 0;
}
I realise that I might have made a lot of silly mistakes, like in the while loop maybe, and the way by which I am trying to insert the struct in the shared memory segment, but that is what I ask all of you. To help me build a better logic for the same. All suggestions are welcome.
Upvotes: 1
Views: 980
Reputation: 55564
You cannot use pointers in your shared memory segment because they are only valid within your process. This is likely the reason for segfaults you getting. You could use offsets in the shared memory segment.
Upvotes: 3
Reputation: 753870
What you show is not really an MCVE. You have 13 char *
members in the structure; 3 would be plenty for an MCVE. You are also using XML parsing functions which are basically tangential to the problem; you could simplify things a lot.
You don't show any of the other processes that will be using the list in shared memory; it would be helpful to have one of them (it need only attach to the shared memory and traverse the list, printing the results).
Basic obervation:
You're signally failing to ensure that all the data is in shared memory.
Your assignments like:
(*dlist).polname = aaron.polname;
are bogus on at least four counts. First, aaron.polname
is a pointer in this process's per-process (unshared) memory. So the pointer assignment is giving other processes a bogus address to work with. It points to some random location in that other processes address space — or, if you're lucky, to some location outside their address space so they crash quickly rather than slowly.
Second, you haven't copied the string; you've simply assigned a pointer. That's a problem.
Third, you're making all the pointers in shared memory point to the same locations, so that multiple entries point at the same data.
Fourth, you should use dlist->polname
notation. Yes, what you've got works; it doesn't work well. It is easier to check (write, think of) dlist->next->next
than (*(*dlist).next).next
. (I can't even write that without doing it incrementally. And I'm not claiming that this is a good expression in this context; I'm just pointing out that chained access is a lot easier with the arrow ptr->member
notation than the star-dot (*ptr).member
.)
You have to ensure that the pointers in the shared structure point into shared memory.
You also have to ensure that all the processes load the shared memory segment at the same address. If you can't do that, then you can't reliably use pointers at all; you have to use offsets from the base address (the start address of the shared memory segment). The link pointer also needs to be handled carefully.
You are not creating a big enough chunk of shared memory. You are using:
shmid = shmget(key, sizeof(aaron), IPC_CREAT | 0660);
That creates enough space for a set of pointers, but no space for the pointers to point at. You also seem to want to create a linked list, but you're only allocating enough space for a single element. This has to be reworked. The shared memory must be big enough to contain all the shared data — the structures and the strings that the structures point at.
So, you need to:
dlist->polname
and not (*dlist).polname
unless you wish to be taken to be a neophyte programmer.Upvotes: 3