How to modify an existing YAML node in C? - c

I am not C programmer but have recently taking interest in it. I am trying to modify a node of a YAML file using the C libyaml library. When I try to modify the node from an event scalar data the compiler doesn't complain but I get segmentation fault errors.
while (!done)
{
/* Get the next token. */
if (!yaml_parser_parse(&parser, &event))
goto parser_error;
//yaml_parser_scan(&parser, &token);
/* Check if this is the stream end. */
if(beginServerNodes && event.type == 8) {
beginServerNodes = 0;
}
if (event.type == YAML_SCALAR_EVENT) {
if(beginServerNodes == 1) {
//I WANT TO MODIFY THIS VALUE
printf("%s\n", event.data.scalar.value);
}
if(strcmp("servers",event.data.scalar.value) == 0) {
beginServerNodes = 1;
}
}
if (event.type == YAML_STREAM_END_EVENT) {
done = 1;
}
/* Emit the token. */
if (!yaml_emitter_emit(&emitter, &event))
goto emitter_error;
}
So while in that loop when I attempt to modify the following value
event.data.scalar.value
It must be of type yaml_char_t
yaml_char_t *newHost = "10.132.16.48:6379:1 redis-001";
event.data.scalar.value = newHost;
event.data.scalar.length = sizeof(newHost);
The compiler doesn't complain and the code run by dies with segementation fault. If have seen the examples in the libyaml test directories but nothing is intuitive as far as simply editing a node, at least not to a C newb like myself.

Libyaml expect that the values of each scalar can be removed via free(). So you need to initialize this value with malloc()ed memory:
const char* newHost = "10.132.16.48:6379:1 redis-001";
event.data.scalar.value = (yaml_char_t*)strdup(newHost);
event.data.scalar.length = strlen(newHost);

Related

`execvp()` seems to not be completing the path search

TL;DR -- what sorts of things might cause an execvp call to not fully function/ search the path properly?
I'm on the tail end of building a rudimentary shell with some quality of life features that I've added over time e.g. history, alias's, and completions. I built those features on top of a functional shell that had a working $PATH search for execution e.g. typing in "ls -la" produced the desired behavior. As you might imagine, I accomplished this just using execvp. (This is written in C if it's not already clear)
I have not changed any of my tokenizing logic and have ensured that the file name is correct; in particular, execvp was producing the desired behavior before I had added these features to my REPL. echo "hello" still produces a tokenized char **xyz and the first token is indeed echo, null-terminated, and so on. That is, my call still looks like, with variables filled-in, ... execvp("echo", argv); after which I call perror, which should only trigger when something has gone awry. Each time I just run the above command, though, since I've added in these features, it returns a failure with the no such file or directory --- before I added these features in though, the behavior was as desired. I'll note, though, that running /bin/echo "hello" runs as expected. Examples are WLOG.
I'm not sure where I should even start looking for errors, and my Google-fu has been mostly fruitless: any suggestions?
I'm initially going to omit code because it totals to several hundred lines and a MWE would not be particularly minimal in addition to my desires to keep this general rather than very particular to my code, though I'm not sure what's causing this. My repository is public and up-to-date, and I'm happy to post any code here.
EDIT:
I knew I wasn't explicitly editing the PATH variable, etc., but this block of code was the problem:
// Grab $PATH from env
char *pathvar = getenv("PATH");
if (pathvar) {
char *path;
int i;
// tokenize on colon to get paths
// then use that immediately to
// scandir, and add everything in
// there to the completions system
path = strtok(pathvar, ":");
while (path) {
struct dirent **fListTemp;
int num_files = scandir(path, &fListTemp, NULL, alphasort);
// only adding the names that are completely composed of
// lower case letters; completions are done using a naive
// Trie Node structure that only supports lowercase letters
// for now... e.g. g++ does not work, and the '+' leads to
// a seg-fault. Same holds for . and ..
for (i = 0; i < num_files; i++) {
char *curr = fListTemp[i]->d_name;
if (strcmp(curr, ".")==0 || strcmp(curr, "..")==0){
continue;
} else if (notalpha(curr)) {
continue;
} else {
str_tolower(curr);
tn_insert(completions, curr);
}
}
for (i = 0; i < num_files; i++) {
free(fListTemp[i]);
}
free (fListTemp);
path = strtok(NULL, ":");
}
} else {
fprintf(stderr, "{wsh # init} -- $PATH variable could not be found?");
}
Note that
The getenv() function returns a pointer to the value in the
environment, or NULL if there is no match.
so my original code was indeed tampering with the PATH variable. The solution I came up with quickly was just to create a copy of that string and use that to parse through the PATH instead:
// Grab $PATH from env
char *pathvar = getenv("PATH");
char *pathvar_cpy = strcpy(pathvar_cpy, pathvar);
if (pathvar_cpy) {
char *path;
int i;
path = strtok(pathvar_cpy, ":");
while (path) {
// Scan directory
struct dirent **fListTemp;
int num_files = scandir(path, &fListTemp, NULL, alphasort);
for (i = 0; i < num_files; i++) {
char *curr = fListTemp[i]->d_name;
if (strcmp(curr, ".")==0 || strcmp(curr, "..")==0){
continue;
} else if (notalpha(curr)) {
continue;
} else {
str_tolower(curr);
tn_insert(completions, curr);
}
}
for (i = 0; i < num_files; i++) {
free(fListTemp[i]);
}
free (fListTemp);
path = strtok(NULL, ":");
}
} else {
fprintf(stderr, "{wsh # init} -- $PATH variable could not be found?");
}

Identifying C syntax

So I was studying some tutorial code for a BLE implementation, and I came across this syntax which I have never seen before.
&p_ble_evt->evt.gatts_evt.params.write;
It is the &foo;bar-&baz part i'm unsure of.
I tried 'googleing' the code part, then tried running it through https://cdecl.org/.
But without getting an understanding for what this code does/is.
/**#brief Function for handling the Write event.
*
* #param[in] p_midi_service LED Button Service structure.
* #param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_write(ble_midi_service_t * p_midi_service, ble_evt_t const * p_ble_evt)
{
ble_gatts_evt_write_t * p_evt_write = (ble_gatts_evt_write_t *) &p_ble_evt->evt.gatts_evt.params.write;
if ((p_evt_write->handle == p_midi_service->data_io_char_handles.value_handle) &&
(p_evt_write->len == 1) &&
(p_midi_service->evt_handler != NULL))
{
// Handle what happens on a write event to the characteristic value
}
// Check if the Custom value CCCD is written to and that the value is the appropriate length, i.e 2 bytes.
if ((p_evt_write->handle == p_midi_service->data_io_char_handles.cccd_handle)
&& (p_evt_write->len == 2)
)
{
// CCCD written, call application event handler
if (p_midi_service->evt_handler != NULL)
{
ble_midi_evt_t evt;
if (ble_srv_is_notification_enabled(p_evt_write->data))
{
evt.evt_type = BLE_DATA_IO_EVT_NOTIFICATION_ENABLED;
}
else
{
evt.evt_type = BLE_DATA_IO_EVT_NOTIFICATION_DISABLED;
}
p_midi_service->evt_handler(p_midi_service, &evt);
}
}
}
So if some kind soul would help enlighten me that would be much appreciated.
Thank you.
Looks like xml/html escape sequences, should read:
&p_ble_evt->evt.gatts_evt.params.write;

Strcmp generate a core dump

So i have a std::unordered_map, i want to acces to strings stored intro this map. I want to search intro intro all words inside the map and compare with a given word. If the strings are same then continue execution of the if statement.
{
public:
bool CheckFoo(const char* word);
protected:
typedef std::unordered_map<std::string, bool> word_map;
word_map words_map;
};
bool CheckFoo(const char* word)
{
if (words_map.empty())
{
return false;
}
auto it = words_map.begin();
while (it != words_map.end())
{
const std::string &r = it->first;
const char* tmp = word;
if (strcmp(tmp, r.c_str() ) == 0)
{
return true;
}
}
return false;
}
if ( CheckFoo("wordFoo") )
{
// bla bla
}
The problem is that those codes generate a .core dump file..
Do you see any mistakes in my codes?
The crash core analyze point me to strcmp line
Can't write comments yet but,
Like Nunchy wrote, tmp is not defined in that context.
I also noticed that your code never increments the map iterator, which would result in a never ending loop.
I'm assuming you did not copy your actual code into your post but instead rewrote it hastily which resulted in some typos, but if not, try making sure you're using temp and not tmp in your call to strcmp, and make sure the loop actually increments the iterator.
Like one of the comments on your post points out as well, make sure you actually have data in the map, and the function parameter.
You are declaring temp then referencing tmp which doesn't exist:
const char* temp = word;
if (strcmp(tmp, r.c_str() ) == 0)
Does this compile? Surely it should be:
const char* temp = word;
if (strcmp(temp, r.c_str() ) == 0)
?

Whether code is read from top to bottom

I am creating a program in c which is based on a linked list, where every node (of struct) holds an integer and a pointer to the next node.
I use dynamic allocation (malloc) and deallocation (free) as new nodes are added and old nodes are deleted.
when a node is deleted a function named delete is called.
I discovered that the program crashes sometimes when this delete-function is called and I KNOW that its something with the pointers in the method but I dont know WHERE in the code (row number) and WHY this happends.
I am used to high-level languages such as Java and I am used to encircle the problem by putting print-syntax at certain places in the method just to reveal WHERE it crashes.
I thought I could do the same with c and with pointer because to my knowledge I beleive the code is read from top to bottom that is 1, 2, 3, 4, and so on. (maybe interrupt handlers behave another way?)
So in this function named delete I have gone so far by putting this printf() at the very beginning of the delete-function - and all the same the program crashes.
So my Question - is it really possible that its some syntax in the delete-function (when I loop pointers for instance) that causes the crash WHEN not even the printf() is printing?
Am I wrong when I believe that the program is executed from to to bottom - that is 1, 2, 3 ....
You can se my printf-function in the very beginning of delete-function
And by the way - how could I solve this problem when I get this cryptic crash message from windows? See the bitmap!!
Greatful for answers!!!
int delete(int data) {
printf("IN THE BEGINNING OF DELETE!!!");
int result = 0;
if (queueref.last != NULL) {
node *curr_ptr;
node *prev_ptr;
node *temp_ptr;
if (queueref.first->data == data) {
temp_ptr = queueref.first;
queueref.first = queueref.first->next;
destroy_node(temp_ptr);
result = 1;
if (queueref.first == NULL) {
queueref.last = NULL;
puts("queue is now empty!!!");
}
} else {
prev_ptr = queueref.first;
curr_ptr = queueref.first->next;
printf("prev_ptr: %d\n", prev_ptr);
printf("curr_ptr: %d\n", curr_ptr);
while(curr_ptr != NULL) {
if (curr_ptr->data == data) {
result = 1;
if (curr_ptr->next != NULL) {
temp_ptr = curr_ptr;
destroy_node(temp_ptr);
prev_ptr->next = curr_ptr->next;
} else {
temp_ptr = curr_ptr;
queueref.last = prev_ptr;
prev_ptr->next = NULL;
destroy_node(temp_ptr);
}
}
curr_ptr = curr_ptr->next;
prev_ptr = prev_ptr->next;
}
}
}
return result;
}
Common mistake, here's the deal. This
printf("IN THE BEGINNING OF DELETE!!!");
needs to be
printf("IN THE BEGINNING OF DELETE!!!\n");
^^ note the newline
The reason is because stdio does not flush stdout until it sees a newline. If you add that newline, you should see the printf when the code enters the function. Without it, the program could crash, the stdout buffer would not have been flushed and would not see the printf.
Your code seems to have lots of implementation flaws. As a general advice I would recommend using some standard well-tested queue support library and static code analyzers (in this case you would even find dynamic analyzer valgrind very helpful, I guess).
For example, if implementation of destroy_node(ptr) is equivalent to free(ptr), then your code suffers from referencing destroyed data (or ,in other words, garbage) in this code snippet:
while(curr_ptr != NULL) {
if (curr_ptr->data == data) {
result = 1;
if (curr_ptr->next != NULL) {
temp_ptr = curr_ptr;
destroy_node(temp_ptr);
prev_ptr->next = curr_ptr->next; //<- curr_ptr is still in stack
//or register, but curr->next
//is garbage
// what if curr_ptr is first node? did you forget to update queueref.first?
} else {
temp_ptr = curr_ptr;
queueref.last = prev_ptr;
prev_ptr->next = NULL;
destroy_node(temp_ptr);
}
// if you you need to destroy only one node - you can leave the loop here with break;
}
curr_ptr = curr_ptr->next; /// assigning garbage again if node is found
prev_ptr = prev_ptr->next;
The reason why using destroyed data can work in * most * (if I can say that, basically this is unpredictable) cases is that the chances that this memory can be reused by other part of program for dynamically allocated data can vary on timings and code flow.
PS
Regarding cryptic messages in the Windows box - when program crashes OS basically generates crashdump and prints registers (and dumps some relevant memory parts). Registers and memory dumps can show the place of crash and immediate register/stack values but you have to now memory map and assembler output to understand it. Crashdump can be loaded to debugger (WinDbg) together with unstripped binary to check stactrace and values of local variables at the moment of crash. All these I described very very briefly, you could find tons of books / guides searching for "windows crash or crashdump analysis"

Why does segmentation fault (core dumped) error apply to my C program?

I keep getting this error and I am not sure how it applies to my program. This is my program.
#include<stdio.h>
#include<stdlib.h>
int nextword(char *str);
void main(void)
{
char *str = "Hello! Today is a beautiful day!!\t\n";
int i = nextword(str);
while(i != -1)
{
printf("%s\n",&(str[i]));
i = nextword(NULL);
}
}
int nextword(char *str)
{
// create two static variables - these stay around across calls
static char *s;
static int nextindex;
int thisindex;
// reset the static variables
if (str != NULL)
{
s = str;
thisindex = 0;
// TODO: advance this index past any leading spaces
while (s[thisindex]=='\n' || s[thisindex]=='\t' || s[thisindex]==' ' )
thisindex++;
}
else
{
// set the return value to be the nextindex
thisindex = nextindex;
}
// if we aren't done with the string...
if (thisindex != -1)
{
nextindex = thisindex;
// TODO: two things
// 1: place a '\0' after the current word
// 2: advance nextindex to the beginning
// of the next word
while (s[nextindex] != ' ' || s[nextindex] != '\n' || s[nextindex] != '\t')
{
if ( s[nextindex] == '\0')
return -1;
else
{
nextindex++;
if (s[nextindex]==' '||s[nextindex]=='\n'||s[nextindex]=='\t')
str[nextindex]='\0';
}
}
}
return thisindex;
}
My program is supposed to have an output to the console of
Hello!
Today
is
a
beautiful
day!!
You are trying to change a String literal. This results in undefined behavior, such as a segfault.
str[nextindex]='\0'
and in Here, str is the parameter of nextWord(), which is:
char *str = "Hello! Today is a beautiful day!!\t\n";
int i = nextword(str);
Since "Hello! Today is a beautiful day!!\t\n" is a string literal - changing it is udnefined behavior, and in your case (luckily) it caused a seg-fault.
You should compile with all warnings and debugging info enabled (if using GCC e.g. on Linux, that means compiling with gcc -Wall -g).
Then you should learn how to use the debugger (i.e. gdb on Linux) and possibly a leak detector like valgrind
a segmentation fault may happen if you dereference some "bad" pointer, e.g. a NULL one or an uninitialized one. It also may happen if you write into a read-only segment (you are probably overwriting a string literal which is put into a read-only -so called .text or .rodata- segment)
Taking account of every warning of the compiler (and enabling them) and using a debugger are essential skills of any C programmer.
Please give nextindex a initial value

Resources