C - g_snprintf works in one scenario but not in another - c

Pretty simple situation.
I have a response pointer to struct and i want to populate its values.
In one palce it's working:
janus_audiobridge_sync_endpoint_response *response = g_malloc0(sizeof(janus_audiobridge_sync_endpoint_response));
response->error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
g_snprintf(response->error_cause, 512, "%s - %s", "Failed to find about page with locale - ", locale_text);
return response;
However when i do basicly the same thing another method, the response->error_cause turns out to be null:
janus_audiobridge_sync_endpoint_response *response = g_malloc0(sizeof(janus_audiobridge_sync_endpoint_response));
response->error_code = 0;
response->error_code = JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED;
g_snprintf(response->error_cause, 512, "You need to pass a valid user_secret, before you continue.");
goto plugin_response;
My question: Why does it work in one context and not another? What is the best Practive in C, to do this kind of stuff?
Thanks!
EDIT: And even weirder is that when i do:
response->error_cause = "You need to pass a valid user_secret, before you continue.";
It works on the second example, why is that?
EDIT:
As requested:
typedef struct janus_audiobridge_sync_endpoint_response {
gint error_code;
gchar *error_cause;
json_t *message;
} janus_audiobridge_sync_endpoint_response;

It's clear from the declaration that error_cause is just a pointer, not an array.
So it won't point at anything valid when you allocate (and clear) an instance of janus_audiobridge_sync_endpoint_response. Thus you get undefined behavior.
To fix this, you need to allocate room for the string. In glib-land, you can use the nice g_strdup_printf() function for this:
response->error_cause = g_strdup_printf("%s - %s", "Failed to find about page with locale - ", "foo", locale_text);
Note that I added a foo to that call, your original code seems to fail to provide the proper number of arguments considering the format string, which (again!) gives you undefined behavior.
Doing e.g. error_cause = "hello"; is always kind of safe, since that just sets the pointer in the struct to point at a static array somewhere in memory, it doesn't copy any characters. The only risk with that is that since the pointer in the struct is not const, somebody might try to modify the string which again would bring undefined behavior.

Related

I don't understand how pointers work in this code?

I don't understand this part of the code below. I mean alloc_MY_CAR() returns some array and how does & work so that newTab->pFunFree = &free_MY_CAR sees this array which newTab->pDat returns?
I don't understand pointers well. I only know that & store address of variable and * is a pointer or a value of the variable.
Could anyone guide me on how to use it properly and how does it work? I'm a beginner, so don't be so hard on me.
Thanks in advance!
#pragma once
struct MY_CAR {
char *model;
int year;
};
void print_MY_CAR(void* pdata);
void free_MY_CAR(void *pdata);
MY_CAR* alloc_MY_CAR();
switch (typ) {
case 0:
newTab->pDat = alloc_MY_CAR();
newTab->pFunFree = &free_MY_CAR;
newTab->pFunPrint = &print_MY_CAR;
break;
}
MY_CAR* alloc_MY_CAR() {
MY_CAR* tab = (MY_CAR*)calloc(1, sizeof(MY_CAR));
if (!tab) {
exit(0);
}
else {
char model[125];
printf("Podaj model: ");
scanf("%s", model);
tab->model = (char*)calloc(strlen(model) + 1, sizeof(char));
strcpy(tab->model, model);
printf("Podaj rok: ");
scanf_s("%d", &tab->year);
}
return tab;
}
void free_MY_CAR(void *pdata) {
MY_CAR* car = (MY_CAR*)pdata;
if (!car || !car->model) return ;
free(car->model);
free(car);
}
Notice that the function free_MY_CAR has an argument of type void*,
a pointer to a "void" type
(which is a C idiom for a pointer to something without telling the type of the thing pointed to),
and the first thing it does is to reinterpret that pointer as a pointer to a MY_CAR.
So the function is probably intended to be called like this:
newTab->pFunFree(newTab->pDat);
That is, the way the functions "know" what pointer was returned by
alloc_MY_CAR() and stored in newTab->pDat
is that the programmer explicitly tells the functions what pointer
is stored in newTab->pDat.
The advantage of doing such things is that it allows some code to do some operation on a data structure without necessarily having to know what kind of data structure it will actually operate on when the program actually runs.
In the call to pFunFree above, newTab could have been initialized by the case 0 code shown in the question, but there could be another case
that initializes it with alloc_MY_JOB(), &free_MY_JOB, and &print_MY_JOB,
where the MY_JOB functions allocate/free/print a data structure that is quite different from the data structure used by
alloc_MY_CAR(), &free_MY_CAR, and &print_MY_CAR.
Then if you call
newTab->pFunPrint(newTab->pDat);
we might not be able to predict when we write the code whether it will print the contents of a data structure created by
alloc_MY_CAR() or by alloc_MY_JOB();
but we can predict that it will print the detailed information it has
about your car, or your job, or whatever was read from the data file and stored in newTab.
The property that we can make a function call that uses a data structure in a way appropriate to that data structure, without having to know when we write the code what the type of data structure will be, is called
polymorphism.
This is a cumbersome idiom and there are lots of ways to get it wrong.
One of the selling points of C++ is to enable people to write polymorphic objects more easily than this.

Valgrind use of unitialised value

I am creating a symbol table for a compiler I am writing and when I try adding to my symbol table I keep getting valgrind errors. When I call my function, I am calling my add function
stAdd (&sSymbolTable, "test", RSRVWRD, 4, 9);
and in my stAdd function it is currently
void stAdd (StPtr psSymbolTable, char *identifier, SymbolTableType type,
int addressField, int arrayDimensions)
{
int hashValue;
hashValue = hash (identifier, psSymbolTable->numBuckets);
if (psSymbolTable->spSymbolTable[hashValue] == NULL)
{
psSymbolTable->spSymbolTable[hashValue] = (StEntryPtr) malloc (sizeof(StEntry));
strcpy (psSymbolTable->spSymbolTable[hashValue]->identifier, identifier);
psSymbolTable->spSymbolTable[hashValue]->entryLevel = psSymbolTable->currentLevel;
psSymbolTable->spSymbolTable[hashValue]->type = type;
psSymbolTable->spSymbolTable[hashValue]->addressField = addressField;
psSymbolTable->spSymbolTable[hashValue]->arrayDimensions = arrayDimensions;
psSymbolTable->spSymbolTable[hashValue]->psNext = NULL;
}
}
But every time I set a value within my StEntry struckt, I get an error
Use of unitialised value of size 8
every time I set something within the if statement. Does any see where I am going wrong?
My StEntry is
typedef struct StEntry
{
char identifier[32];
SymbolTableLevel entryLevel;
SymbolTableType type;
int addressField;
int arrayDimensions;
StEntryPtr psNext;
} StEntry;
This would be a lot easier if I could see the definition of struct StEntry or even the precise valgrind error. But I'll take a wild guess anyway, because I'm feeling overconfident.
Here, you malloc a new StEntry which you will proceed to fill in:
psSymbolTable->spSymbolTable[hashValue] = (StEntryPtr) malloc (sizeof(StEntry));
This is C, by the way. You don't need to cast the result of the malloc, and it is generally a good idea not to do so. Personally, I'd prefer:
StEntry* new_entry = malloc(sizeof *new_entry);
// Fill in the fields in new_entry
psSymbolTable->spSymbolTable[hashvale] = new_entry;
And actually, I'd ditch the hungarian prefixes, too, but that's an entirely other discussion, which is primarily opinion-based. But I digress.
The next thing you do is:
strcpy (psSymbolTable->spSymbolTable[hashValue]->identifier, identifier);
Now, psSymbolTable->spSymbolTable[hashValue]->identifier might well be a char *, which will point to the character string of the identifier corresponding to this symbol table entry. So it's a pointer. But what is its value? Answer: it doesn't have one. It's sitting in a block of malloc'd and uninitialized memory.
So when strcpy tries to use it as the address of a character string... well, watching out for the flying lizards. (If that's the problem, you could fix it in a flash by using strdup instead of strcpy.)
Now, I could well be wrong. Maybe the identifier member is not char*, but rather char[8]. Then there is no problem with what it points to, but there's also nothing stopping the strcpy from writing beyond its end. So either way, there's something ungainly about that line, which needs to be fixed.

C function returning incorrect data

I'm making a game using C and I have a function the reads a file and returns a pointer that holds the data for the level.
File: levelbuilder.c
bunker *read_rooms(char *rooms_file){
FILE *bunker_file = fopen(rooms_file, "r");
char room_name[MAX_ROOM_NAME_LEN];
fscanf(bunker_file, "%s", room_name);
bunker *result = create_bunker(room_name);
fclose(bunker_file);
return result;
}
Obviously right it doesn't do the whole level as I'm still testing things as I go. I'll list create_bunker below.
File: room.c
bunker *create_bunker(char *room_name){
bunker *result = malloc(sizeof(bunker));
result->room_name = room_name;
for (int i = 0; i < MAX_ITEMS; i++) {
result->items[i] = NULL;
}
result->connected_to = NULL;
result->next = NULL;
return result;
}
This function works just fine.
When I check the variables in read_rooms using the debugger they all have the correct room name from file. However, in main the pointer to the level isn't NULL but it's room_name is. Where am I going wrong? Any help would be much appreciated :)
Variable room_name is a local array in function read_rooms.
As such, it is pointing to a piece of memory on the stack.
The contents of that memory are valid only as long as you're "inside" the function.
Once you're "out", you can no longer rely on this piece of memory to contain valid data.
It might contain the data you'd expect, but it might not.
And even if it does, it may be overridden at a later point in the execution of the program.
So instead of setting result->room_name = room_name, you should copy the actual contents:
result->room_name = malloc(strlen(room_name)+1);
strcpy(result->room_name,room_name);
And of course, don't forget to free(result->room_name) before you free(result)...
Change this line:
result->room_name = room_name;
For
strcpy (result->room_name, room_name);
To copy the contents of room_name in result->room_name. As you have it right now, you are making a char * pointer assigment and this is what will drive the program crazy.
You allocate room_name on stack, than you pass ponter to it, and save to result->room_name. You can't rely on value that is saved on stack (created without malloc or something), it gets overwritten very soon when function execution is finished. Just use strcpy as Hernan Velasquez suggested
For a start this line is wrong
result->room_name = room_name;
As it will go out of scope and hence to the wolves. Perhaps make a copy.
I am sure there are other problems

Changing a structs string

I'm using lex to implement a scanner. I want to build a symbol table while parsing. I have two structs, SymbolEntry and SymbolTable (below). Most of the time, when I call my function for inserting a symbol (registerID, also below) I have all the information for the entry. However, when I have a constant I also want to get it's value, but that is not immediately available when I first create the entry. When I try to change the entries value later in the code, I'm invalidating the whole memory block used by that entry and the name and value are printing garbage.
Here are the two structs:
typedef struct{
char* type;
char* name;
char* value;
} SymbolEntry;
typedef struct{
SymbolEntry *entries;
size_t size;
size_t capacity;
} SymbolTable;
This is the registerID function, called when an {id} is matched. yytext contains the ID.
int registerID(char* type){
//create a new symbol entry with the specified type and name and a default value
SymbolEntry e;
e.type = type;
e.name = (char *)calloc(yyleng+1, sizeof(char));
strcpy(e.name, yytext);
e.value = "";
prevSym = insertSymbol(&table, e);
return prevSym;
}
This is the relevant code for insertSymbol(SymbolTable* st, SymbolEntry entry). pos is always the last element in the array when inserting (otherwise the entry isn't unique and pos is just returned).
st->entries[pos].name = (char *)calloc(strlen(entry.name)+1, sizeof(char));
st->entries[pos].type = (char *)calloc(strlen(entry.type)+1, sizeof(char));
st->entries[pos].value = (char *)calloc(strlen(entry.value)+1, sizeof(char));
strcpy(st->entries[pos].name, entry.name);
strcpy(st->entries[pos].type, entry.type);
strcpy(st->entries[pos].value, entry.value);
Later, after the lex framework has matched the value immediately following a CONSTANTs name, this code is performed (directly in the rule for <CONSTANT_VAL>{number})
table.entries[prevSym].value = (char *)calloc(yyleng+1, sizeof(char));
strcpy(table.entries[prevSym].value, yytext);
Why does this invalidate the the SymbolEntry at this position in the array, and how can I safely change the contents of value?
EDIT:
It doesn't only happen with constants. The first two SymbolEntrys are always garbage. I'm assuming that probably means they ALL are, but the others just haven't been overwritten.
Also, it seems like subsequent calls to registerID is causing the data to get corrupted. With just 9 symbols, only the first two are garbage, with 34, it's the first 7. Adding more text to parse without variables did not cause any issues.
SOLVED
Well it turns out that I just accidentally deleted a line somewhere along the way and that's what introduced the bug. I accidentally erased my call to initSymbolTable. Thanks to chux for asking me how I initialized the table. Sorry about that.
2 potential problems.
1 - Compare
// Fields set with non-malloc'ed memory
e.type = type;
e.value = "";
// Fields set with malloc'ed memory
st->entries[pos].type = (char *)calloc(strlen(entry.type)+1, sizeof(char));
st->entries[pos].value = (char *)calloc(strlen(entry.value)+1, sizeof(char));
strcpy(st->entries[pos].type, entry.type);
strcpy(st->entries[pos].value, entry.value);
Both of these set the fields to valid memory and in the second case, dynamically fill the memory. The concern is subsequent use. How does OP know to free() or realloc() the second kind and not the first. Further concern: With registerID(char* type), how do we know the value passed to type is still valid way later when that pointer is used via field type. Suggest:
e.type = strdup(type); // or the usual strlen()+1, malloc() and copy
e.value = strdup("");
2 - The type and setting of yyleng are not shown. Maybe it is not big enough as compared to strlen(e.name), etc.?
[Edit] after review, I real think e.type = type; is the problem. e.type needs its own copy of type.
Minor: Consider
// st->entries[pos].type = (char *)calloc(strlen(entry.type)+1, sizeof(char));
// strcpy(st->entries[pos].type, entry.type);
size_t Length = strlen(entry.type) + 1;
st->entries[pos].type = malloc(Length);
memcpy(st->entries[pos].type, entry.type, Length);

Char* array not retaining value C

For my networking class, we're building a bittorrent client based off the UDP protocol, which is pretty cool but I'm having a ton of trouble with C strings for some reasons.
The first time I receive a packet, I do:
if(server_data == NULL){
server_data = malloc(one_block.total_blocks*sizeof(char*));
int i;
for(i = 0; i < one_block.total_blocks; i++){
server_data[i] = malloc(sizeof(char*));
server_data[i] = "";
}
}
Here, server_data is a char** and one_block is struct that holds packet information and the payload.
Next I do:
server_data[one_block.which_block] = one_block.payload;
blocks_rcv++;
if(blocks_rcv == one_block.total_blocks-1)
done = TRUE; //macro
if(done){
int i;
for(i = 0; i < one_block.total_blocks; i++){
printf("%s", server_data[i];
}
}
All seems well and dandy but for whatever insane reason when I print the contents of server_data before all the packets are received, I see different data from each packet. Afterwards I set done = TRUE and go into that for loop, every spot in the array contains the same string value.
I have no idea why this is happening and I really want to understand how from the beginning of the post to the end, the contents of the array change, even though I verify them through every iteration of the loop that reads in one packet at a time.
This line is the problem:
server_data[i] = "";
It overwrites the allocated pointer, with a pointer to the string literal. And as string literals can't be modified, if you later copy into this pointer, you experience undefined behavior.
If you want to make sure the string is empty, either use calloc, set the first character to '\0', or use strcpy to copy in the new string.
There are a couple of issues going on here:
1) First, server_data, if it's declared as a char**, may or may not be null off the bat, unless you declare it so. I'm not sure if you initialized it to NULL or not. It's a good idea to explicitly initialize it to NULL.
2) I'm not sure from what's going on if you intend for each item of the array server_data to hold a char* (in other words, a reference to a string), or for the array to be a string itself. Is one_block.payload a string, or a set of pointers to strings?
I ran your code with some test values and I'm personally not getting any problems with unexpected values...I think the issue may be in how the struct that holds your payload data is set up. Could you show us your one_block struct? What type of variable/array is one_block.payload?

Resources