0

I have a struct named task. It's a linked list that contains a struct timing and a command. It's used to store the command I have to execute at a certain time:

// and here is the struct command:
struct argument {
    size_t length; // length of the data string
    char *data;
};
typedef struct argument argument;

struct command {
    int argc; // amount of arguments(words) in argv
    argument *argv; // here I already tried put argument **argv
};
typedef struct command command;

I initialize the task with task *this_task = malloc(sizeof(task)); and initialize the command with command *cmds = malloc(sizeof(command)).

I add the commands with this method:

command *addToCommand(command *cmd, size_t argSize, char *arg) {
    argument *currentArgument = malloc(sizeof(argument) + argSize * sizeof(char));
    if (currentArgument == NULL) {
        cmd = NULL;
        return cmd;
    }
    currentArgument->length = argSize;
    currentArgument->data = arg;

    if (cmd == NULL) {
        cmd = malloc(sizeof(command));
        if (cmd == NULL) return cmd;
        cmd->argv = malloc(sizeof(argument));
        cmd->argv[0] = *currentArgument;
        cmd->argc = 1;
    } else {
        cmd->argc++;
        cmd->argv = realloc(cmd->argv, (cmd->argc) * sizeof(argument));
        cmd->argv[cmd->argc-1] = *currentArgument;
    }
    return cmd;
}

and then set it with this_task->cmd = cmds;

Now the problem: just after I did all this I printed the first argv of my task with printf( "%s\n", this_task->cmd->argv[0].data), and it showed 'test-0' like it should.

But the moment when I send it to an another method, like addTask(this_task), and print it again on the first line of the addTask method it shows weird symbols like "p<a�".

For example for this code :

void addTask(task *task_to_add) {
    printf("arg inside addTask = '%s'\n", task_to_add->cmd->argv[0].data);
   // i'm doing things here but even when everything is commented the bug happen 
}

printf("arg before addTask = '%s'\n", this_task->cmd->argv[0].data);
addTask(this_task);
printf("arg after addTask = '%s'\n", this_task->cmd->argv[0].data);

Shows:

arg before addTask = 'test-0'
arg inside addTask = '`��'
arg after addTask = '`��'

In this project, I'm writing the command to a pipe, and reading it in the code above. While trying to make a minimal reproducible example, I noticed that when I remove the part reading from pipes and directly force the value for "test-0", it works correctly. So does the problem happen because of the way I'm reading the pipes? I also tried the solution of the "possible duplicate," but it didn't work. The issue is probably from how I read from the pipe.

I also noticed that if I don't have any other printf before the one displaying "arg before addTask ...", the arg before show " ", I commented it and wrote "THIS PRINTF" near it

How I compile and run:

gcc src/saturnd.c -o saturnd
gcc src/cassini.c  -o cassini
./saturnd
./cassini (in another terminal)

The code who's reading the pipe:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <endian.h>

struct argument {
    size_t length;
    char *data;
};
typedef struct argument argument;

struct command {
    int argc;
    argument *argv;
};
typedef struct command command;

struct task {
    int id;
    struct timing *timing;
    command *cmd;
    struct task *next;
};
typedef struct task task;


struct timing {
    uint64_t minutes;
    uint32_t hours;
    uint8_t daysofweek;
};


int readHere;
task *tasks = NULL;

command *addToCommand(command *cmd, size_t argSize, char *arg) {
//    printf("adding to cmd %s\n", arg);
    argument *currentArgument = malloc(sizeof(argument) + argSize * sizeof(char));
    if (currentArgument == NULL) {
        cmd = NULL;
        return cmd;
    }
    currentArgument->length = argSize;
    currentArgument->data = arg;

    if (cmd == NULL) {
        cmd = malloc(sizeof(command));
        if (cmd == NULL) return cmd;
        cmd->argv = malloc(sizeof(argument));
        cmd->argv[0] = *currentArgument;
        cmd->argc = 1;
    } else {
        cmd->argc++;
        cmd->argv = realloc(cmd->argv, (cmd->argc) * sizeof(argument));
        cmd->argv[cmd->argc - 1] = *currentArgument;
    }
    return cmd;
}

void addTask(task *task_to_add) {
    printf("arg inside addTask = '%s'\n", task_to_add->cmd->argv[0].data);
}

int main() {
    char *readHere_path = "saturndReadPipe";
    mkfifo(readHere_path, S_IRWXU | S_IRWXG | S_IRWXO);
    readHere = open(readHere_path, O_RDONLY);

    task *this_task = malloc(sizeof(task));
    this_task->id = 0;

    struct timing *reply_time = malloc(sizeof(struct timing));
    reply_time->minutes = 5; // test vars
    reply_time->hours = 5; // test vars
    reply_time->daysofweek = 5; // test vars

    uint32_t reply_argc;
    read(readHere, &reply_argc, sizeof(reply_argc));
    reply_argc = be32toh(reply_argc);

    // reply_argc should be 2, because we wrote only 2 words "echo" and "test-0"

    command *cmds = NULL;
    for (int j = 0; j < (int) reply_argc; j++) {
        uint32_t argSize_uint;
        read(readHere, &argSize_uint, sizeof(argSize_uint));
        int argSize = be32toh(argSize_uint);
        int newSize = argSize + 1;
        char arg[newSize];
        int data_read = (int) read(readHere, &arg, argSize);
        arg[data_read] = '\0';

        //printf("read '%s' from pipe\n", arg); // THIS PRINTF

        cmds = addToCommand(cmds, newSize, arg);
    }
    this_task->cmd = cmds;
    this_task->next = NULL;

    printf("arg before addTask = '%s'\n", this_task->cmd->argv[0].data);
    addTask(this_task);
    printf("arg after addTask = '%s'\n", this_task->cmd->argv[0].data);

    exit(0);
}

The code which is writing in the pipe:

#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <endian.h>

int main() {

    char *writeHere_path = "saturndReadPipe";

    int writeHere = open(writeHere_path, O_WRONLY | O_TRUNC);

    uint32_t cmd_argc = htobe32(2);
    write(writeHere, &cmd_argc, sizeof(cmd_argc));

    // sending "echo"
    uint32_t length = htobe32(4);
    write(writeHere, &length, sizeof(length));
    char *cmd_data = "echo";
    uint8_t d[4];
    int j = 0;
    for (; j < 4; ++j)
        d[j] = cmd_data[j];
    write(writeHere, &d, sizeof(d));

    // sending "test-0"
    length = htobe32(4);
    write(writeHere, &length, sizeof(length));
    cmd_data = "test-0";
    uint8_t dd[4];
    j = 0;
    for (; j < 4; ++j)
        dd[j] = cmd_data[j];
    write(writeHere, &dd, sizeof(dd));

    exit(0);
}
Secretary
  • 17
  • 3
arbi12321
  • 23
  • 4
  • 5
    I don't see any definition for a `struct task`. Don't tell us what you did, show us the code of a [mre]. – Cheatah Dec 26 '21 at 20:36
  • 2
    Can you put together a [mcve]? Showing how all the parts fit together is always better than just explaining it. – Retired Ninja Dec 26 '21 at 20:36
  • `currentArgument->data = arg;` is a copy of the pointer. I expect you want a copy of the _string_ pointers to by `arg`. – chux - Reinstate Monica Dec 26 '21 at 20:51
  • Does this answer your question? [Copying a string to a struct member](https://stackoverflow.com/questions/53152341/copying-a-string-to-a-struct-member) – kirjosieppo Dec 26 '21 at 20:59

1 Answers1

1

You do not copy string only assign the pointer to it. I would do it a bit different way.

typedef struct argument {
    size_t length; // length of the data string
    char data[];
}argument;

typedef struct command {
    int argc; // amount of arguments(words) in argv
    argument *argv[];
}command;

command *addToCommand(command *cmd, const size_t argSize, const char *restrict arg) 
{
    int newargc = cmd ? cmd -> argc + 1 : 1;
    argument *currentArgument = malloc(sizeof(*currentArgument) + 
             (argSize + 1) * sizeof(currentArgument -> data[0]));  //if argsize includes null terminating character remove "+1"  
    if (currentArgument) 
    {
        currentArgument->length = argSize;
        strcpy(currentArgument->data, arg);

        cmd = realloc(cmd, sizeof(*cmd) + newargc * sizeof(cmd -> argv[0]));

        if(cmd)
        {
            cmd -> argc = newargc;
            cmd -> argv[newargc -1] = currentArgument;
        }
    }

    return cmd;
}
0___________
  • 60,014
  • 4
  • 34
  • 74