Initializing a struct results in Segmentation Fault - c

I have a simple struct as follows:
typedef struct {
char *raw_headers;
char headers[128][512][512];
} HTTPrequest;
Now in the same file I have a function as follows:
void init_request(char *raw_headers) {
HTTPrequest request;
request.raw_headers = raw_headers;
}
This results in a Segmentation Fault when running the output binary.
I compile the file, as
$ gcc Server.c -o Builds/debug
And, I run the executable as,
$ ./Builds/debug
This is my original file as requested:
Parser.h
typedef struct {
char *raw_headers;
char headers[128][512][512];
} HTTPrequest;
void parser_init(char *raw_headers) {
char *token, *key_value = NULL;
token = strtok(raw_headers, "\r\n");
int line_counter = 1
HTTPrequest request;
request.raw_headers = raw_headers;
while (token) {
char *line = token;
if(line_counter != 1) {
}
token = strtok(NULL, "\r\n");
line_counter++;
}
}
Server.h
int socket_create() {
return socket(AF_INET, SOCK_STREAM, 0);
}
void infinite_loop(int socketFD) {
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
printf("Starting infinite loop, don't worry, everything would be okay!\n");
do {
int connectionFD = accept(socketFD, (struct sockaddr*) NULL, NULL);
/*Accept is a blocking call! The following code wont execute until, accept() returns.*/
strcpy(buffer, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\nHello!");
write(connectionFD, buffer, sizeof(buffer));
char request[2048];
memset(&request, 0, sizeof(request));
read(connectionFD, &request, sizeof(request));
printf("Request received!\n");
// Init the parser.
parser_init(request);
close(connectionFD);
} while (true);
}
Server.c
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <stdbool.h>
#include "Parser.h"
#include "Server.h"
void main() {
struct sockaddr_in listeningAddr;
int socketFD = socket_create();
memset(&listeningAddr, 0, sizeof(listeningAddr));
listeningAddr.sin_family = AF_INET;
listeningAddr.sin_addr.s_addr = htonl(INADDR_ANY);
listeningAddr.sin_port = htons(8070);
bind(socketFD, (struct sockaddr*) &listeningAddr, sizeof(listeningAddr));
if(listen(socketFD, 5) == -1) {
printf("Woah there! I couldn't startup the server!");
}
infinite_loop(socketFD);
}
Also, the error message: Segmentation fault (core dumped)

The headers member (32MiB) makes your struct too big to fit on most default system-provided stacks (8MiB on Linux).
Make it smaller, and trivial MCVEs such as:
typedef struct {
char *raw_headers;
char headers/*[128]*/[512][512]; }
HTTPrequest;
void init_request(char *raw_headers) {
HTTPrequest request;
request.raw_headers = raw_headers;
}
int main()
{
init_request("hello, world");
}
will work, although, initializing an on-stack struct only to have it discarded by the function return is not very meaningful
(Initializer functions will usually take a pointer to the struct they're initializing and initialize the object through that pointer.)

Although your HTTPrequest is simple, it is over 32MB in size. You most probably encounter a stack overflow...

That's a typical case of Stack overflow!
The reason is that your struct HTTPrequest is too big, more than 32 MB. The 3D array has a size of 128 * 512 * 512 = 33554432 bytes, since it's of type char.
In any case, 3D arrays are barely used, and only in special cases. Reconsider your design and try to make that array a 2D instead of a 3D.

Related

Why do I get segmentation fault using fopen?

I'm writing a client-server model in C which works using fifos. I send a file name plus a name for a unique fifo for the client to recieve the data from the client and the server opens the file and writes the first line of it on the fifo. The thing is that even if the file exists i get a segmentation fault when opening it. Seems like the fopen() function works but I still get the error. If the file doesn't exist it just sends an empty string.
Here is client.c :
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#define BUFSIZE 512
struct sent {
char name[BUFSIZE];
char fifo[BUFSIZE];
};
int main()
{
char name[BUFSIZE];
char recieved[BUFSIZE];
int client_server_fifo;
char cs_fifo[BUFSIZE] = "cs_fifo";
int server_client_fifo;
char sc_fifo[BUFSIZE];
sprintf(sc_fifo, "sc_fifo_%d", getpid());
struct sent *sent;
mkfifo(sc_fifo, 0777);
while(1) {
printf("Write the name of the file: ");
scanf("%s", name);
printf("1111\n");
client_server_fifo = open(cs_fifo, O_WRONLY);
printf("2222\n");
printf("%s", name);
printf("%s", cs_fifo);
sent->name = name;
sent->fifo = cs_fifo;
printf("%s", name);
printf("%s", cs_fifo);
write(client_server_fifo, sent, sizeof(*sent));
server_client_fifo = open(sc_fifo, O_RDONLY);
if (read(server_client_fifo, recieved, sizeof(recieved)) == -1) {
printf("An error ocurred.\n");
} else {
printf("First line of the file: \n%s\n", recieved);
close(client_server_fifo);
close(server_client_fifo);
}
memset(recieved, 0, sizeof(recieved));
}
return 0;
}
And here's server.c :
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#define BUFSIZE 512
struct sent {
char name[BUFSIZE];
char fifo[BUFSIZE];
};
int main()
{
int client_server_fifo;
char cs_fifo[BUFSIZE] = "cs_fifo";
int server_client_fifo;
char sc_fifo[BUFSIZE];
struct sent *sent;
char name[BUFSIZE];
char line[BUFSIZE];
FILE *file;
printf("Server running...\n");
mkfifo(cs_fifo, 0777);
while (1)
{
client_server_fifo = open(cs_fifo, O_RDONLY);
read(client_server_fifo, sent, sizeof(*sent));
strcpy(name, sent->name);
strcpy(sc_fifo, sent->fifo);
if((file = fopen(name, "r")) != NULL) {
printf("%s\n", name);
fgets(line, BUFSIZE, file);
printf("%s\n", name);
}
server_client_fifo = open(sc_fifo, O_WRONLY);
write(server_client_fifo, line, strlen(line));
memset(name, 0, sizeof(name));
memset(line, 0, sizeof(line));
close(client_server_fifo);
}
return 0;
}
Why does this happen?
The program has undefined behavior because in gthis statement
sprintf(sc_fifo, "sc_fifo_%d", getpid());
you are trying to change a string literal pointed to by the pointer sc_fifo.
char *cs_fifo = "cs_fifo";
When you declare a pointer to a string literal always declare them with the qualifier const. In this case you will get ban error at compilation time if you will tray to change a string literal.
Also you are using uninitialized pointer sent
struct sent *sent;
in this statement
read(client_server_fifo, sent, sizeof(*sent));
There are other errors. For example arrays do not have the assignment operator. So these statements in client.c
sent->name = name;
sent->fifo = cs_fifo;
are incorrect.

send and Receive a struct in Posix Message Queue

I am getting the exception: file1.c: mq_send: Message too long
The error seems self explanatory but I can not figure it out.
I have the struct and files:
typedef struct {
char path[5011];
char sharedMemSegmentNameBuf[30];
} messageQueueStruct;
file1.c
#include <sys/mman.h>
#define MAX_CACHE_REQUEST_LEN 5041
messageQueueStruct mqStruct;
int maxPathLength = MAX_CACHE_REQUEST_LEN - sizeof(mqStruct.sharedMemSegmentNameBuf);
strncpy(mqStruct.path, path, maxPathLength);
strncpy(mqStruct.sharedMemSegmentNameBuf, sharedMemSegmentNameBuf, sizeof(mqStruct.sharedMemSegmentNameBuf));
if (mq_send(qdCache, (const char *) &mqStruct, sizeof(mqStruct), 0) == -1)
{
perror("handle_with_cache: mq_send");
exit(1);
}
file2.c
#include <sys/mman.h>
#define MAX_CACHE_REQUEST_LEN 5041
struct mq_attr attributes;
attributes.mq_maxmsg = MAX_MESSAGES;
attributes.mq_msgsize = MAX_CACHE_REQUEST_LEN;
messageQueueStruct receiveStruct;
int maxPathLength = MAX_CACHE_REQUEST_LEN - sizeof(receiveStruct.sharedMemSegmentNameBuf);
messageQueueStruct receiveStruct;
if (mq_receive(qdCache, (char *) &receiveStruct, MAX_CACHE_REQUEST_LEN, NULL) == -1)
{
perror("process request: mq_receive");
exit(1);
}
It looks to me that the sizes line up on the receive/ send sides. I also tested with just a char[] buffer and it worked.
Some references I have looked at:
send struct in mq_send
https://w3.cs.jmu.edu/kirkpams/OpenCSF/Books/cs361/html/MessPassMQ.html

Getting segmentation fault in C on Ubuntu when trying to run function from .so library

I am using libwireshark.so, libwsutil.so and libwiretap.so in order to make program which decodes packets like Wireshark in C on Ubuntu Linux.
I am try to run function named epan_init() from libwireshark.so but I get the following run-time error:
Enter file name: 1.pcap
Enter print type(0-XML, 1-TEXT): 1
Init function start
Segmentaion fault (core dumped)
Process returned 139 (0x8B) execution time : 2.882 s
Press ENTER to continue.
SOURCE CODE:
#define HAVE_STDARG_H 1
#define WS_MSVC_NORETURN
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <wireshark/epan/epan.h>
#include <wireshark/epan/print.h>
#include <wireshark/epan/timestamp.h>
#include <wireshark/epan/prefs.h>
#include <wireshark/epan/column.h>
#include <wireshark/epan/epan-int.h>
#include <wireshark/wsutil/privileges.h>
#include <wireshark/epan/epan_dissect.h>
#include <wireshark/epan/proto.h>
#include <wireshark/epan/ftypes/ftypes.h>
#include <wireshark/epan/asm_utils.h>
///Prototypes
void getString(char *msg, char **input);
int init(char *filename);
///Print type of packets
typedef enum {PRINT_XML, PRINT_TEXT} print_type_t;
capture_file cfile;
int main()
{
///Variables
int err;
char *filename = NULL;
print_type_t print_type = PRINT_XML;
getString("Enter file name: ", &filename);
printf("Enter print type(0-XML, 1-TEXT): ");
scanf("%d",&print_type);
err = init(filename);
if(err)
{
printf("Main function(): Error init");
return 1;
}
printf("\n\n\n%s\n\n\n",cfile.filename);
//printf("Hello World");
return 0;
}
///Get input from user
void getString(char *msg, char **input)
{
char buffer[100];
printf("%s", msg);
fgets(buffer, sizeof(buffer), stdin);
*input = calloc(sizeof(char), strlen(buffer) + 1);
strncpy(*input, buffer, strlen(buffer));
}
///
int init(char *filename)
{
printf("Init function start\n");
int err = 0;
gchar *err_info = NULL;
e_prefs *prefs_p;
/// Called when the program starts, to enable security features and save whatever credential information we’ll need later.
init_process_policies();
printf("Init proccesss politices done");
/// Init the whole epan module. Must be called only once in a program. Returns TRUE on success, FALSE on failure.
epan_init(register_all_protocols, register_all_protocol_handoffs, NULL, NULL);
//printf("epan init done");
cap_file_init(&cfile);
cfile.filename = filename;
return 0;
}
void cap_file_init(capture_file *cf)
{
/* Initialize the capture file struct */
memset(cf, 0, sizeof(capture_file));
cf->snap = WTAP_MAX_PACKET_SIZE;
}

Stack smashing detected after calling msgrcv function

I have written two programs one to send message using msgsnd and other to receive with msgrcv. I have been using these functions for quite a while, but I can't figure out "stack smashing detected" error in receiving file. In that file I try to copy one part of file to one char array and second part into second array. I get stack smashing detected after receiving program completion if msgrcv is ever called in a file. At the end of a file I call printf function to print two arrays. From my point arr1 and arr2 should contain complete message, while only arr1 contains message and arr2 is empty. But the biggest problem is stack smashing detected error. I place code for two files below:
Sending file:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/msg.h>
#include <stdint.h>
typedef struct message {
long type;
char text[128];
} message;
int main (int argc, char **argv) {
if (argc == 3 && strcmp (argv [1], "-m") == 0) {
key_t key = (key_t) atoi (argv[2]);
message msg;
int message_queue_id = msgget (key, IPC_CREAT | 0666);
int semaphore_set_id = semget (key, 1, IPC_CREAT | 0666);
struct semid_ds buf;
struct sembuf sb;
long long buf_address = (long long)&buf;
long long sb_address = (long long)&sb;
// sending message
msg.type = 6;
memset (msg.text, 0, 128);
printf ("%p %p\n", (void*)&buf, (void*)&sb);
sprintf (msg.text, "%lld %lld", buf_address, sb_address);
printf ("msg: %s\n", msg.text);
void* ptr = (void*)buf_address;
printf ("ptr = %p\n", ptr);
msgsnd(message_queue_id, (struct msgbuf*)&msg, sizeof (msg) - 4, 0);
sleep (1000);
}
}
Receiving file (without headers):
typedef struct message {
long type;
char text[128];
} message;
int main (int argc, char **argv) {
if (argc == 3 && strcmp (argv [1], "-m") == 0) {
key_t key = (key_t) atoi (argv[2]);
int message_queue_id = msgget (key, IPC_CREAT | 0666);;
int semaphore_set_id = semget (key, 1, IPC_CREAT | 0666);
message msg;
struct semid_ds buf;
struct sembuf sb;
msgrcv (message_queue_id, (struct msgbuf*)&msg, sizeof(msg) - 4, 6, IPC_NOWAIT);
printf ("msg = %s\n", msg.text);
char arr1[32] = "\0", arr2[32] = "\0";
int i = 0;
while (msg.text[i] != ' ') {
arr1[i] = msg.text[i];
i++;
}
i++;
while (msg.text[i]) {
arr2[i] = msg.text[i];
i++;
}
printf ("arr1 = %s, arr2 = %s\n", arr1, arr2);
printf ("sizeof(long) = %d\n", (int)sizeof(long));
}
}
msgrcv (message_queue_id, (struct msgbuf*)&msg, sizeof(msg) - 4, 6, IPC_NOWAIT);
The third parameter to msgrcv should be the size of the buffer stored in the message structure. When doing the calculation sizeof(msg) - 4, you seem to be assuming that the size of long is always 4, which is incorrect. Instead, you should simply use sizeof(msg.text).
You also have the same error in the sender. Because the size of long in 64-bit linux is 8 bytes and not 4, your code will write past the end of the msg variable, causing a buffer overflow.

String concatenation maintaining destination length

I have a basic server-client program that I'm writing in C and I am stuck with an issue regarding strings and concatenation.
Basically I have some strings (in the example below just 2) that I have to put into a buffer which size is determined by:
total # of registered people * 33
Both the strings in the example have a length which is much less than the length of the buffer. I want to obtain something like this after the concatenation:
[0] [32]
people_list=Mark Amy\0;
where Mark(which is inserted secondly) is right at the start of the buffer (people_list) and Amy is 32 characters away from the start of Mark (I hope I've made myself clear).
This is because the client code was given to me and I cannot modify it. The client code takes the buffer and reads the first element, then jumps of 32 chars and reads again.
The output I get from the printf of the client is this:
connected to server
Registered people:
Mark
while I'd like this:
connected to server
Registered people:
Mark
Amy
The communication is implemented through sockets, which I have already checked, but if you wish to suggest some changes I would appreciate that.
Server code:
#include <stdio.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#define LENGTH 32
struct person {
char name[LENGTH+1];
struct person *next;
struct person *prev;
};
struct person *p_head = NULL;
void addPerson(char* name_p){
struct person *new = (struct person*) malloc(sizeof(struct person));
strcpy(new->name, name_p);
new->name[LENGTH]='\0';
new->next=p_head;
new->prev=NULL;
p_head=new;
}
int main(){
int fd_ser;
int fd_c;
int N=100;
char buf[N];
int times=0;
char* path="tmp/sock";
struct sockaddr_un sa;
unlink(path);
sa.sun_family=AF_UNIX;
strncpy(sa.sun_path,(char*) path, sizeof(sa.sun_path));
if((fd_ser=socket(AF_UNIX,SOCK_STREAM,0))<0){ //socket
perror((const char*) (size_t) errno);
exit(EXIT_FAILURE);
}
if ( bind(fd_ser,(struct sockaddr *)&sa, sizeof(sa))<0){
perror("bind\n");
}
listen(fd_ser,10); //listen
struct sockaddr_un addr;
int addr_size= sizeof(struct sockaddr_un);
fd_c=0;
while( (fd_c=accept(fd_ser,(struct sockaddr*) &addr, (socklen_t*)&addr_size))<0){
printf("waiting for connections...\n");
sleep(2);
}
//initialize list of people
char* Amy="Amy";
char* Mark="Mark";
addPerson(Amy);
addPerson(Mark);
//now concat the name strings in a buffer to be sent to the client
char* people_list;
unsigned int list_len;
int value;
struct person* ptr=(struct person*) malloc(sizeof(struct person));
ptr=p_head;
int offset=0;
int i=0;
while(ptr!=NULL){
i++;
people_list=realloc(people_list,i*LENGTH); //every single name has to be LENGTH characters
strcpy(&people_list[offset],ptr->name);
ptr=ptr->next;
offset=offset+LENGTH;
}
people_list[i*LENGTH]='\0';
list_len=(i*LENGTH)+1;
value=write(fd_c, &(list_len), sizeof(unsigned int));
if(value==-1){
perror("write length");
return -1;
}
int toWrite=list_len;
char *toRead=people_list;
while(toWrite>0){
value=write(fd_c, toRead, toWrite);
if(value==-1){
perror("write data");
return -1;
}
toWrite=toWrite-value;
toRead=toRead+value;
if(toRead<=people_list + list_len) break;
}
close(fd_c);
close(fd_ser);
return 0;
}
Client code:
#include <stdio.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <assert.h>
#include <errno.h>
#define MAX_LENGTH 2048
#define LENGTH 32
int main(){
int fd_cli;
char* path="tmp/sock";
struct sockaddr_un sa;
sa.sun_family=AF_UNIX;
strncpy(sa.sun_path,(char*) path, sizeof(sa.sun_path));
if( (fd_cli = socket(AF_UNIX, SOCK_STREAM, 0))==-1){
perror((const char*) (size_t) errno);
return -1;
}
while( (connect(fd_cli,(struct sockaddr*)&sa, sizeof(struct sockaddr_un))) == -1 ) {
if ( errno == ENOENT ) { sleep(1); }
else perror("connect:");
errno=0;
sleep(1);
}
printf("connected to server\n");
int value;
unsigned int len_data;
value=read(fd_cli,&(len_data),sizeof(unsigned int));
if(value==-1){
perror("read length");
return -1;
}
char* buffer=malloc(len_data*sizeof(char));
int toRead=len_data;
char *toWrite=buffer;
while(toRead>0){
value=read(fd_cli, toWrite, toRead);
if(value==-1){
perror("read buffer");
return -1;
}
toRead=toRead-value;
toWrite=toWrite+value;
if(toWrite<=buffer + len_data) break;
}
int people_n = len_data / (LENGTH+1);
assert(people_n > 0); //proceeds only if there is at least one person registered
printf("Registered people:\n");
for(int i=0,p=0;i<people_n; ++i, p+=(LENGTH+1)) {
printf(" %s\n", &buffer[p]);
}
close(fd_cli);
return 0;
}
I really hope I've explained the problem clearly! Thank you for your help!
It's printing only the first user (Mark) because of this line:
int people_n = len_data / (LENGTH+1);
In this example, len_data = 65, LENGTH = 32. So when you are adding 1 to LENGTH, it will return 1 (65/33 = 1.96 => you get 1). Then it only prints the first user.
Consider using Valgrind. It will help you checking the use of the memory.

Resources