Weird behavior in C


I’m doing this project in C. Every time I push my work, it fails with a couple of characters at the end of output. This always happens when testing puts some output into a file with echo command and uses cat command to print the output. On local, it almost never happens. When it does, it is so rare that it is almost impossible to debug.
I am following a pretty standard approach of redirecting standard output to a specified file name and use execvp to execute external binary. I debugged and checked that my string is right, null-terminating character is in right place, pointers are pointing to the correct location, my implementation of echo is correct, etc. Nothing works.

Has anybody come across this issue?

Here is the link to my repo regarding this issue: codecrafters-shell-c/src/execute_bin.c at main · MaxJuneKim/codecrafters-shell-c · GitHub

I built it but noticed your main file was set to src/another_main, I switched it back to src/main.c which I presume is the correct one. You are have some kind of bug with parsing. After the first command you get garbage in your args. Just after parsing I added this:

 int argi = 0;
  for (char **arg = args->arguments; *arg != NULL; argi++, arg++) {
    printf("TOKEN[%d] = |%s|\n", argi, *arg);
  }

Then I ran the shell and after the first command I got unexpected. At least on my machine I can easily replicate. (Also echo without any args segfaults!).

$ echo A
TOKEN[0] = |echo|
TOKEN[1] = |A|
A
$ echo A
TOKEN[0] = |echo|
TOKEN[1] = |AA`�Sq|
AA`�Sq
$ echo A
TOKEN[0] = |echo|
TOKEN[1] = |AA`�Sq|
AA`�Sq
$ echo A
TOKEN[0] = |echo|
TOKEN[1] = |AA`�Sq|
AA`�Sq
$ echo AB
TOKEN[0] = |echo|
TOKEN[1] = |AB`�Sq|
AB`�Sq
$ echo ABC
TOKEN[0] = |echo|
TOKEN[1] = |ABC�Sq|
ABC�Sq
$ echo A
TOKEN[0] = |echo|
TOKEN[1] = |AA`�Sq|
AA`�Sq

In parse_arg.c, replacing calls to malloc(n) with calloc(n, 1) eliminates at least this issue. It seems to me you are somehow relying on malloc to always return zeroed blocks, which it doesn’t. Perhaps you are missing setting some '\0'/0 terminators?

A plausible explanation for why it works first time, is perhaps the first calls to malloc acquires fresh page from the OS that has been zeroed. But when same memory is reused by malloc it is no longer zero.

When the line ends and you exit your parsing loop you don’t terminate (with '\0') the last token argument. You need something like:

result->arguments[arg_count][cur_arg_index] = '\0';

Just after your while loop ends.