sprintf with struct array field - gets segmentation fault - c

This idea is to format text info messages bellowing to a structure within a module.
It works like a charm when trying to define the message with (cf module.c):
/*this works*/
module_text3.info_text[0] = "toto[0]";
module_text3.info_text[1] = "toto[1]";
But when using sprintf, I got segmentation fault (cf module.c):
/*this gives segmentation fault*/
for(cpt=0; cpt < 2; cpt++)
{
sprintf(module_text3.info_text[cpt], "info[%u]", cpt);
}
3 different files: main.c, module.h and module.c
/*main.c*/
/*gcc -o test main.c module.c*/
#include <stdio.h>
#include "module.h"
int main(int argc, char **argv)
{
int i;
struct message3 *ptext3 = moduleFcn3();
for (i= 0; i < ptext3->info_nb; i++)
{
printf("ptext3->info_text[%u]: %s\n", i, ptext3->info_text[i]);
}
printf("ptext3->error_text: %s\n", ptext3->error_text);
printf("ptext3->id: %u\n", ptext3->id);
printf("ptext3->info_nb: %u\n", ptext3->info_nb);
printf("ptext3->info_nb_max: %u\n", ptext3->info_nb_max);
return 0;
}
/*------------------------------------------------------*/
/*module.h*/
#define NB_LINE_MAX 10
struct message3
{
char *info_text[NB_LINE_MAX]; /*a few info lines.*/
char *error_text; /*only one line for error.*/
int id;
int info_nb_max;
int info_nb;
};
extern struct message3* moduleFcn3(void);
/*------------------------------------------------------*/
/*module.c*/
#include <stdio.h>
#include "module.h"
/*static is in "Stack".*/
static struct message3 module_text3;
struct message3* moduleFcn3(void)
{
int cpt = 0;
struct message3 *ptext;
/*this gives segmentation fault*/
for(cpt=0; cpt < 2; cpt++)
{
sprintf(module_text3.info_text[cpt], "info[%u]", cpt);
}
/*this works*/
// module_text3.info_text[0] = "toto[0]";
// module_text3.info_text[1] = "toto[1]";
// cpt = 2;
module_text3.error_text = "This is error";
module_text3.id = 4;
module_text3.info_nb_max = NB_LINE_MAX;
module_text3.info_nb = cpt;
ptext = &module_text3;
return ptext;
}
I would appreciate any advises on how to format my information messages (with our without using sprintf).
Thank you,

You have not allocated space for the strings in the info_text field. The simplest thing to do would be to change the struct:
/*module.h*/
#define NB_LINE_MAX 10
#define INFO_MAX 25
struct message3
{
char info_text[NB_LINE_MAX][INFO_MAX]; /*a few info lines.*/
char *error_text; /*only one line for error.*/
int id;
int info_nb_max;
int info_nb;
};
extern struct message3* moduleFcn3(void);

You did not allocate any memory for the info_text strings. You either have to use malloc() first, or if your C library supports it (the GNU one does), use asprintf() instead of sprintf() to have it allocate enough memory to hold the whole output string for you:
for(cpt = 0; cpt < 2; cpt++)
asprintf(&module_text3.info[cpt], "info[%u]", cpt);
Don't forget that you also have to free the memory again at some point.
The reason that the following line works:
module_text3.info_text[0] = "toto[0]";
Is that the compiler ensures the string "toto[0]" is stored in memory somewhere, and you just make the pointer module_text3.info_text[0] point to that string.

Related

Automatic generation of struct printing function in C

I have many programs where structs are defined. And each time, I have to create a function to print the members. For example,
typedef struct {
char name[128];
char address[1024];
int zip;
} myStruct;
void printMyStruct(myStruct myPeople) {
printf("%s\n",myPeople.name);
printf("%s\n",myPeople.address);
printf("%d\n",myPeople.zip);
}
int main()
{
myStruct myPeople={"myName" , "10 myStreet", 11111};
printMyStruct(myPeople);
}
I know that reflection is not supported in C. And so, I write these printing functions for each struct I defined.
But, I wonder if it exists any tricks to generate automatically these printing functions. I would understand that I have to modify a little bit these functions. But, if a part of the job is done automatically, it would be great.
(This example is simple, sometimes struct are nested or I have array of structs or some fields are pointers, ...)
You can of-course print structs, but expect a lot of non-readable output:
#include <stdio.h>
#include <ctype.h>
struct example {
int x;
int y;
char c;
};
#define NOT_PRINTABLE "Not Printable"
void print_structure(const char *structure, size_t size) {
for (size_t i = 0; i < size; i++) {
printf("%ld)\t%.2X: %.*s\n", i, structure[i],
(isprint(structure[i]) ? 1 : sizeof(NOT_PRINTABLE) - 1),
(isprint(structure[i]) ? &structure[i] : NOT_PRINTABLE));
}
}
int main(int argc, char **argv) {
struct example a;
a.x = 5;
a.y = 6;
a.c = 'A';
print_structure((char *)&a, sizeof(struct example));
return 0;
}
But the issue is that, it will print the structs as it is represented in memory. So 4 byte (32 bit) integer 1 will be represented with 4 bytes, not the char '1'.
And due to the way pointers work, you cannot make out if a member is a pointer or a non-pointer.
Another issue is that structures have padding to help with alignment, and better/efficent use of memory. So you would see a lot of 0x00 in the middle.
Remember that C is a compiled language.
let's consider to use https://copilot.github.com/. it's great.
this is what i have with copilot
typedef struct {
char name[128];
char address[1024];
int zip;
} myStruct;
//print struct myStruct >> auto generate by codepilot after you type a comment `print struct myStruct`
void printStruct(myStruct *s) {
printf("name: %s\n", s->name);
printf("address: %s\n", s->address);
printf("zip: %d\n", s->zip);
}

initialize struct from function call

Feel like im taking crazy pills just trying to do literally the simplest stuff I can imagine in C. Any help would be extremely appreciated. why does this work?
#include <stdio.h>
#include <stdlib.h>
#define Q_LIMT 100
typedef struct servers
{
int id;
int num_in_Q;
int server_status;
}SERVER;
void initialize(SERVER *s);
void initialize(SERVER *s)
{
int i=0,j=0;
for(i=0; i<2; i++) { //i=0; i=1
s[i].id = i; // 0, 1
s[i].num_in_Q = i*i + 1; // 1, 2
s[i].server_status = i+i + 2; // 2, 4
} // the bracket was missing
}
int main()
{
int i;
SERVER serv[2];
initialize(serv);
for(i=0; i<2; i++) {
printf("server[%d].id = %d\n", i, serv[i].id);
printf("server[%d].num_in_Q = %d\n", i, serv[i].num_in_Q);
but this throws away the initialized struct?
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
'''
int POINTERS_PER_INODE = 5;
struct Inode {
int valid;/* 0 == invalid, 1 == valid*/
int size;
int Blocks [5];
};
int InodeToString(char * InodeString, struct Inode iNode){
char * blockBuffer;
sprintf(InodeString, "%d", iNode.valid);
int i;
for (i = 0; i < POINTERS_PER_INODE; i++){
blockBuffer = malloc(8);
sprintf(blockBuffer, "%d", iNode.Blocks[i]); //no valid pointers yet
strcat(InodeString,blockBuffer);
free(blockBuffer);
}
return 0;
}
int initializeInode(struct Inode iNode){
int i;
for (i = 0; i < POINTERS_PER_INODE; i++){
iNode.Blocks[i] = -1; //no valid pointers yet
}
iNode.valid = 0; //initialized as invalid inode
return 0;
}
int main() {
struct Inode iNode1;
initializeInode(iNode1);
char * InodeString;
InodeString = malloc(20);
InodeToString(InodeString, iNode1);
printf("%s", InodeString);
free(InodeString);
iNode1.valid = 1;
InodeString = malloc(20);
InodeToString(InodeString, iNode1);
printf("%s", InodeString);
return 0;
}
This is test code btw, so the includes probably dont make sense. stack overflow says I dont have enough details so I guess I have to keep typing sentences. Let me know if theres any details that would make this more clear. its for a basic super simplified file system simulation project. it seemed in a previous version when I initialized the inode outside of the function, I was able to pass the string into the string function, assign it values, not use it as the return value and still end up on the other side of the function with an updated string.
As is normal in C, arguments to a function are passed by value. The object called iNode in initializeInode is local to that function, and changes to it have no effect on any other object in the program. If you want a function to modify an object that's local to the caller, you have to pass a pointer to it, and dereference that pointer to get at the caller's object.
So what you probably want is:
int initializeInode(struct Inode *iNode){
int i;
for (i = 0; i < POINTERS_PER_INODE; i++){
iNode->Blocks[i] = -1; //no valid pointers yet
}
iNode->valid = 0; //initialized as invalid inode
return 0;
}
int main() {
struct Inode iNode1;
initializeInode(&iNode1);
// ...
}

C: sha256 hash function outputs in fields of structure array inducing crash when writing structure contents to disk

I am attempting to write a program which will store credential information in an array of structures and then print that information out into a file (this is for learning purposes only, don't worry). To do this, I create an array of structures and then raster through that array to assign the pertinent information to each field. This proceeds without issue. I then attempt to raster through the array again to write each structure's fields to a file whereupon the program crashes after the first write (ie only one structure's worth of content is successfully written to the output file).
I created the following simplified / stripped down variant of my program which reproduces the error. I believe the problem lies within the set_hash_entry function as the error only manifested after that function was re-introduced into my stripped down code in place of a hard coded test value.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "openssl/sha.h"
#include <time.h>
#include <math.h>
struct password_struct {
char password[17];
char hash[65];
float entropy;
};
struct password_struct* allocate_heap_memory(int num_passwords);
void orchestrate_value_setting(int num_passwords, struct password_struct* user_password_structs);
void orchestrate_file_output(int num_passwords, struct password_struct* user_password_structs);
void write_results_to_disk(char file_name[], struct password_struct* user_password_structs);
void set_hash_entry(struct password_struct* user_password_structs);
int main(void) {
int num_passwords = 2;
struct password_struct* user_password_structs = allocate_heap_memory(num_passwords);
struct password_struct* allocated_memory_start_ptr = user_password_structs;
orchestrate_value_setting(num_passwords, user_password_structs);
user_password_structs = allocated_memory_start_ptr; // Resetting pointer to allow cycling back through all structures for appending data to output file
orchestrate_file_output(num_passwords, user_password_structs);
free(allocated_memory_start_ptr);
}
struct password_struct* allocate_heap_memory(int num_passwords) {
struct password_struct* user_password_structs = malloc(num_passwords * sizeof(struct password_struct));
if (!user_password_structs) {
printf("Malloc failed, exiting\n");
exit(0);
}
return user_password_structs;
}
void set_hash_entry(struct password_struct* user_password_structs){
int pass_entry_length = strlen(user_password_structs->password);
SHA256_CTX context;
unsigned char generated_hash[65]; //sha256 standard digest length + 1;
SHA256_Init(&context);
SHA256_Update(&context, (unsigned char *)user_password_structs->password, pass_entry_length);
SHA256_Final(generated_hash, &context);
char* hash_ptr = &user_password_structs->hash[0];
int i;
for (i=0; i < (64); i++) {
snprintf(&hash_ptr[i*2], (64), "%02x", generated_hash[i]); // Need to convert from hex to char representation
}
user_password_structs->hash[64] = '\0';
printf("%s\n", user_password_structs->hash);
}
void orchestrate_value_setting(int num_passwords, struct password_struct* user_password_structs) {
char pw1[10] = "test";
char pw2[10] = "test2";
float entropy1 = 5.0;
float entropy2 = 10.0;
strcpy(user_password_structs->password, pw1);
set_hash_entry(user_password_structs);
user_password_structs->entropy = entropy1;
user_password_structs++;
strcpy(user_password_structs->password, pw2);
set_hash_entry(user_password_structs);
user_password_structs->entropy = entropy2;
user_password_structs++;
}
void orchestrate_file_output(int num_passwords, struct password_struct* user_password_structs) {
printf("Writing data to disk...\n");
char file_name[20] = "name";
int i;
for (i = 0; i < num_passwords; i++) {
write_results_to_disk(file_name, user_password_structs);
user_password_structs++;
}
}
void write_results_to_disk(char file_name[], struct password_struct* user_password_structs) {
FILE *file_pointer = fopen(file_name, "a");
if (file_pointer == NULL) {
printf("Error: Failed to open file\n");
exit(1);
}
fprintf(file_pointer, "%s:%s:%f\n", user_password_structs->password, user_password_structs->hash, user_password_structs->entropy);
fclose(file_pointer);
}
After running this program, the following output is produced:
9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752
Writing data to disk...
*** Error in `./diagnostic': free(): invalid next size (normal): 0x0804b0c0 ***
Aborted (core dumped)
I naively assumed this was an overflow issue related to my
snprintf(&hash_ptr[i*2], (64), "%02x", generated_hash[i]);
operation, but increasing the size of the hash buffer in the struct does not seem to help. Any help would be greatly appreciated!
I compiled as follows: gcc -o diagnostic -g diagnostic.c -lcrypto -lm
char hash[65];
Okay, hash has room for 65 characters.
char* hash_ptr = &user_password_structs->hash[0];
So, hash_ptr points to hash, so it points to room for 65 characters.
for (i=0; i < (64); i++) {
snprintf(&hash_ptr[i*2], (64), "%02x", generated_hash[i]); // Need to convert from hex to char representation
}
When i is 60, i*2 is 120. So you're trying to write to the 120th position of a buffer with room for 65 characters.
Change that (64) to 32 in the loop or change hash[65] to a bigger buffer.
Using valgrind found this immediately. You should learn to use some too that detects buffer overflows, use after free, double frees, and similar problems.

Why I am having a Segmentation fault?

/* This Program generates a file with a pseudo-random number of st_record_t structures. The file is passed by command line arguments. The program must by executed, in UNIX, this way: ./file_gen -path <path> */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "types.h"
#define MSG_INVALID_INPUT "Your input was not valid"
#define CMD_FLAG_PATH_POSITION 1
#define CMD_ARG_PATH_POSITION 2
#define CMD_FLAG_PATH "-path"
#define SDM_MAX 10000.0
status_t validate_arguments (int argc, char * argv []);
int main (int argc, char * argv [])
{
FILE * fi;
size_t i;
st_record_t aux_struct, aux2_struct;
int size;
if ((validate_arguments(argc, argv))!= OK)
{
fprintf(stderr, "%s\n", MSG_INVALID_INPUT);
return EXIT_FAILURE;
}
if((fi = fopen(argv[CMD_ARG_PATH_POSITION], "wb")) == NULL)
return EXIT_FAILURE;
srand(time(NULL));
for (i=0; i<(size=100); i++)
{
aux_struct.SDM = (((float)rand()/(float)(RAND_MAX)) * SDM_MAX); /*pseudo-random real number between 0 and SDM_MAX*/
(aux_struct.ID) = i;
(aux_struct.coordinates)->latitude.deg = rand()%180;
(aux_struct.coordinates)->latitude.min = rand()%60;
(aux_struct.coordinates)->latitude.sec = rand()%60;
(aux_struct.coordinates)->longitude.deg = rand()%180;
(aux_struct.coordinates)->longitude.min = rand()%60;
(aux_struct.coordinates)->longitude.sec = rand()%60;
if((fwrite (&aux_struct, sizeof(st_record_t), 1, fi))!=1)
return ERROR_WRITING_FILE;
}
if(fclose(fi) == EOF)
return EXIT_FAILURE
return EXIT_SUCCESS;
}
The problem is with the (aux_struct.coordinates)->latitude.deg = rand()%180 lines. If instead of using a random number I select one, this won't happen
The st_record_t struct is defined this way:
typedef struct {
unsigned char deg, min, sec;
}angle_t;
typedef struct {
angle_t latitude, longitude;
}st_coord_t;
typedef struct {
float SDM;
size_t ID;
st_coord_t * coordinates;
}st_record_t;
The segmentation fault has nothing to do with random number, it's because you never allocate memory for aux_struct.coordinates.
To fix the problem, use something like:
aux_struct.coordinates = malloc(sizeof(st_coord_t));
Remember to free the memory when it's not used any more.
In addition to the issue of the missing initialization of the "coordinates" member, it should be pointed out that the fwrite() will not do what you want. It will just write the contents of the st_record_t. The value of the pointer "coordinates" has no meaning outside the process that is doing the writing and the data in the st_coord_t structure it points to will not get written at all.
You might want to look at something like hdf5 to write complex binary data structures to file in a portable way.
You have
typedef struct {
float SDM;
size_t ID;
st_coord_t * coordinates;
}st_record_t;
As you can see,coordinates is a pointer of type st_coord_t. You need to allocate memory for it using malloc:
aux_struct.coordinates=malloc(sizeof(st_coord_t));
And you need to free the allocated memory after its use using:
free(aux_struct.coordinates);
Note that you must allocate memory for coordinates in aux2_struct if you want to use it and later free it after its use.

Can't deallocate memory in my C program

I need your help deallocating memory in below program. I tried as you can see in main, but no success. Can not get how to do it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char name[25];
char street[25];
char citystate[25];
char zip[6];
}student;
typedef student *studinfo;
/*function prototypes*/
void getinfo(student *details[], int *);
int main(void)
{
int count = 0;
student *studptr[49];
getinfo(studptr, &count);/*call getinfo function to get student info*/
/*int i = 0;
for (i; i<count; i++) {
free(studptr[i]->name);
free(studptr[i]->street);
free(studptr[i]->citystate);
free(studptr[i]->zip);
} */
return 0;
}
Below is a function to get the info from the file. I will use this info later on in sort function and in display function to display the results. After that I should deallocate the memory.
void getinfo(student *details[], int *count)
{
char s[100];
studinfo info;
/*Get student information*/
while (gets(s) != NULL) {
info = (studinfo)malloc(sizeof(student));
strcpy(info->name, s);
gets(info->street);
gets(info->citystate);
gets(info->zip);
details[(*count)++] = info; /*Increase the pointer to next position*/
} /* End of while loop*/
} /* End of getinfo */
There are three problems with your code:
You are trying to free components of struct student. Since these component arrays were not allocated with malloc, you cannot free them; you need to free only the struct itself.
You are using gets, which can cause buffer overruns. You should use fgets instead, passing buffer size, and stdin for the FILE* parameter.
You copy s[100] into info->name. This can potentially overrun the buffer, because info->name fits only 25 characters.
Once you fix these issues, your program should run correctly.
It should be:
int i;
for (i = 0; i < count; i++) {
free(studptr[i]);
}
Since you allocated each student as a single block, you free them the same way.

Resources