I encountered a segmentation fault when I tried to print the value of a variable, len, which is a local variable that has been initialized at the start of the function.
Except for the misuse of fprintf, what really bothers me is that the line right after the second fprintf would cause segmentation fault also.
Specifically, it is the line where I assign '\n' to tokens[len][0]: "tokens[len][0] = '\n';"
Here is what GDB shows me:
250 tokens[len][0] = '\n';
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x08049f49 in make_command_stream (get_next_byte=0x80495eb <get_next_byte>,
get_next_byte_argument=0x8059b58) at read-command.c:250
250 tokens[len][0] = '\n';
command_stream_t
make_command_stream (int (*get_next_byte) (void *),
void *get_next_byte_argument)
{
int c = (*get_next_byte)(get_next_byte_argument);
char** tokens = (char**) checked_malloc(CMD_SIZE * sizeof(char*));
tokens[0] = (char*) checked_malloc(WORD_SIZE);
int len = 0;
int word_length = 0;
int len_mult = 1;
int word_count = 1;
bool prev = true;
bool comment = false;
bool prevOp = false;
char prevOpe = '\0';
//reading input into the buffer
while (c != EOF)
{
if (c == '#') comment = true;
if (!comment)
{
bool cur = (c != ' ') && (c != '\t');
bool curOp = isOperator(c);
if (cur)
{
if (!(curOp || isValidWordChar(c)))
error_report1(210);
if (!prev)
{
tokens[len][word_length] = '\0';
len++;
if (len > CMD_SIZE * len_mult)
{
len_mult++;
tokens = checked_realloc(tokens, sizeof(char*) * len_mult * CMD_SIZE);
}
tokens[len] = (char*) checked_malloc(WORD_SIZE);
tokens[len][0] = c;
word_length = 1;
word_count = 1;
}
else {
if (prevOpe != '\0' && (curOp != prevOp || (curOp && c != prevOpe)))
{
tokens[len][word_length] = '\0';
len++;
if (len > CMD_SIZE * len_mult)
{
len_mult++;
tokens = checked_realloc(tokens, sizeof(char*) * len_mult * CMD_SIZE);
}
tokens[len] = (char*) checked_malloc(WORD_SIZE);
word_length = 0;
word_count = 1;
}
tokens[len][word_length] = c;
word_length++;
if (word_length > WORD_SIZE * word_count)
{
word_count++;
tokens[len] = checked_realloc(tokens[len], word_count * word_length);
}
}
}
prev = cur;
prevOp = curOp;
prevOpe = c;
}
else if (c == '\n')
comment = false;
c = (*get_next_byte)(get_next_byte_argument);
}
tokens[len][word_length] = '\0';
len++;
fprintf("the value of len is %d\n", len);
if (tokens[len-1][0] != '\n')
{
if (len > len_mult * CMD_SIZE)
tokens = checked_realloc(tokens, (len_mult + 1) * CMD_SIZE);
fprintf("the value of len is %d\n", len);
tokens[len][0] = '\n';
tokens[len][1] = '\0';
len++;
}
For two fprintf I used in this function, complaints from the compiler are:
read-command.c: In function ‘make_command_stream’:
read-command.c:244: warning: passing argument 1 of ‘fprintf’ from incompatible pointer type
/usr/include/stdio.h:333: note: expected ‘struct FILE * __restrict__’ but argument is of type ‘ char *’
read-command.c:244: warning: passing argument 2 of ‘fprintf’ makes pointer from integer without a cast
/usr/include/stdio.h:333: note: expected ‘const char * __restrict__’ but argument is of type ‘int’
read-command.c:244: warning: format not a string literal and no format arguments
read-command.c:249: warning: passing argument 1 of ‘fprintf’ from incompatible pointer type
/usr/include/stdio.h:333: note: expected ‘struct FILE * __restrict__’ but argument is of type ‘char *’
read-command.c:249: warning: passing argument 2 of ‘fprintf’ makes pointer from integer without a cast
/usr/include/stdio.h:333: note: expected ‘const char * __restrict__’ but argument is of type ‘int’
read-command.c:249: warning: format not a string literal and no format arguments
This appears to me a bizarre warning, as there is no pointer type used in fprintf. I wonder what is the possible source of this warning.
So when I run till the line with fprintf, here is what gdb shows me:
244 fprintf("the value of len is %d\n", len);
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x001a1389 in vfprintf () from /lib/tls/i686/cmov/libc.so.6
Another related file is main.c (I guess), as I am using GNU readline function to write something into a input stream, and write that input stream into a temporary file. This writing might cause some problem in memory.
In main.c:
#include <errno.h>
#include <error.h>
#include <getopt.h>
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
#include "command.h"
static char const *program_name;
static char const *script_name;
static void
usage (void)
{
error (1, 0, "usage: %s [-pti] SCRIPT-FILE", program_name);
}
static int
get_next_byte (void *stream)
{
return getc (stream);
}
int
main (int argc, char **argv)
{
int command_number = 1;
bool print_tree = false;
bool time_travel = false;
bool interactive_mode = false;
program_name = argv[0];
int c;
while (((c = getopt (argc, argv, "pti"))!=-1))
switch (c)
{
case 'p': print_tree = true; break;
case 't': time_travel = true; break;
case 'i': interactive_mode = true; break;
default: usage (); break;
case -1: goto options_exhausted;
}
options_exhausted:;
// Limitation of having only one file is removed
/* if (optind != argc - 1)
usage ();*/
command_t last_command = NULL;
command_t command;
if (time_travel || print_tree)
{
//only one file allowed
if (optind != argc - 1)
usage ();
script_name = argv[optind];
FILE *script_stream = fopen (script_name, "r");
if (! script_stream)
error (1, errno, "%s: cannot open", script_name);
command_stream_t command_stream =
make_command_stream (get_next_byte, script_stream);
if (time_travel)
last_command = execute_timetravel(command_stream);
else {
while ((command = read_command_stream (command_stream)))
{
if (print_tree)
{
printf ("# %d\n", command_number++);
print_command (command);
}
else
{
last_command = command;
execute_command (command);
}
}
}
}
if (interactive_mode)
{
printf("You are now in the interactive mode. Type whatever command you want to run:). \n");
char* temp;
char* input_stream = readline("You can enter command right now.\n");
//write input stream into a temporary file
FILE* script_stream = fopen (temp, "w+");
int c = 0;
while (input_stream[c] != '\0')
{
putc(input_stream[c], script_stream);
c++;
}
command_stream_t command_stream = make_command_stream (get_next_byte, script_stream);
if (time_travel)
last_command = execute_timetravel(command_stream);
else {
while ((command = read_command_stream (command_stream)))
{
if (print_tree)
{
printf ("# %d\n", command_number++);
print_command (command);
}
else
{
last_command = command;
execute_command (command);
}
}
}
}
/* printf("This is what you entered: ");
int c = 0;
while (script_scream[c] != '\0')
{
printf("%c", script_scream[c]);
c++;
}
printf("\n");
}*/
return print_tree || !last_command ? 0 : command_status (last_command);
}
fprintfbefore asking here?