So I'm trying to make a shell implementation and it seems to be working just fine. Except there is one very strange issue. I get these errors after I enter the command "/bin/ls -l /usr/include":
Error 1:
a.out: malloc.c:2379: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed. Aborted (core dumped)
Error 2:
realloc(): invalid pointer Aborted (core dumped)
My code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
char **parse_cmdline( const char *cmdline )
{
int token_count = 1;
for(int i = 0; cmdline[i] != '\0';i )
{
if(cmdline[i] == ' ')
{
token_count ;
}
}
char *token = strtok((char*)cmdline, " ");
char **arr = malloc(token_count 1);
int i;
for(i = 0;token != NULL;i )
{
arr[i] = token;
token = strtok(NULL, " ");
}
arr[i] = NULL; // make last element NULL for execvp() to work properly
return arr;
}
int main(void)
{
int fd = 0; // set read() to read from STDIN_FILENO, because it's number is 0
const size_t read_size = 1; // set chunk size
size_t size = read_size;
char *buff = malloc(size 1);
size_t offset = 0;
size_t res = 0;
write(STDOUT_FILENO, "$ ", strlen("$ "));
while((res = read(fd, buff offset, read_size)) > 0) // read from stdin and save to buff
{
if(res == -1)
{
//read_error();
free(buff);
}
if(buff[offset] == '\n')
{
buff[offset] = '\0';
char **result = parse_cmdline(buff);
if(result[0] != NULL)
{
int exec;
int status;
pid_t pid = fork();
if(pid == -1)
{
//fork_error();
}
else if(pid == 0) // Handle child process
{
if((exec = execvp(result[0], result)) == -1)
{
//file_error(result[0]);
}
}
else
{
waitpid(pid, &status, 0);
}
offset = 0;
free(buff);
buff = malloc(size 1);
size = read_size;
}
free(result);
result = NULL;
write(STDOUT_FILENO, "$ ", strlen("$ "));
}
else
{
offset = res;
buff[offset] = '\0';
if (offset read_size > size)
{
size *= 2;
buff = realloc(buff, size 1);
}
}
}
free(buff);
return 0;
}
Here is how to reproduce Error 1: Start the program and the first input should be: "/bin/ls -l /usr/include". After that press enter, and after that enter any command or just a blank line and the error will appear.
How to reproduce Error 2: Start the program and run any commands. Then run "/bin/ls -l /usr/include" and then run 2 other commands and the error will appear.
Note: Working with Oracle VM VirtualBox, compiling with:
gcc -Wall -pedantic -std=c11 file.c
./a.out
CodePudding user response:
char **arr = malloc(token_count 1);
does not allocate enough space. Because not enough space is allocated, attempting to fill it with token_count 1
pointers overruns the allocated space and corrupts other data in memory.
malloc
allocates a number of bytes, not a number of elements. It does not know the size of the elements you are trying to allocate. So you must always tell it how many total bytes to allocate. You can do this by multiplying the number of things you want to allocate by the size of each thing.
A general pattern that works for malloc
is:
SomeType *p = malloc(NumberOfThings * sizeof *p);
That works because *p
is one of the objects that the memory will contain, and sizeof *p
produces the number of bytes that such an object requires. So in this case you can use:
char **arr = malloc((token_count 1) * sizeof *arr);