I'm trying to make a program to crack passwords by searching through a file of md5 hashes and using bsearch to find them in a rockyou database. My problem is that I'm running into a segmentation fault that is either caused by my qsort or my printf (I've run Valgrind and it says printf, but manipulating qsort changes the error output). I can't seem to find the solution online, though I've tried flushing stdout and different ways to size the array in the qsort function.
char **dict = read_dict( argv[2] );
read_dict, which I haven't placed here because it's a hefty chunk of code, takes in the dictionary file, splits it into an array of strings, formats it into hash:password, and mallocs the space for it. It then returns the pointer of the array of pointers that contains each string.
int qcompare( const void *a, const void *b)
{
return strncmp( *((char **)a), *((char **)b), HASH_LEN);
}
qsort(dict, (sizeof(dict) / sizeof(dict[0])), sizeof(char *), qcompare);
for (int i = 0; dict[i] != NULL; i++)
{
printf("%s\n", dict[i]);
}
The printf shown here isn't the actual one I'm using, it's just a simpler one I was trying to use to debug my code. It's my first time posting so hopefully I haven't done anything atrociously wrong with formatting this question. Thank you in advance for any help I get.
read_dict as requested
char **read_dict(char *filename)
{
FILE *f = fopen(filename, "r");
if (!f)
{
printf("read_dict: file error message\n");
exit(1);
}
int arrlen = 0;
int i = 0;
char **dict = NULL;
char buf[PASS_LEN];
while (fgets(buf, PASS_LEN, f) != NULL)
{
if (i == arrlen)
{
arrlen += STEPSIZE;
char **newdict = realloc(dict, arrlen * sizeof(char*));
if (!newdict)
{
printf("read_dict: newdict error message\n");
exit(1);
}
dict = newdict;
}// end of if
buf[strlen(buf) - 1] = '\0';
int slen = strlen(buf);
char *pass = malloc( (slen + 1) * sizeof(char));
strcpy(pass, buf);
char output[(HASH_LEN + PASS_LEN + 1)];
sprintf(output, "%s:%s", md5(pass, strlen(pass)), pass );
dict[i] = output;
i++;
}// end of while
if (i == arrlen)
{
char **newarr = realloc(dict, (arrlen + 1) * sizeof(char*));
if (!newarr)
{
printf("read_dict: newarr error message\n");
exit(1);
}
dict = newarr;
}
dict[i] = NULL;
return dict;
}// end of read_dict
Related
So I have been searching through stack overflow for a little over an hour and I don't understand why this function is giving me a segmentation error. I want to create a string array, scan strings in through scanf, dynamically change the size of each string and return the string array. Can anyone help? Thank you.
char** readScores(int* count) {
int c = 0;
char** arr =(char**)malloc(100 * sizeof(char*));
char* in;
while(scanf("%s", in) != EOF) {
arr[c] = (char*)malloc(strlen(in)+1);
strcpy(arr[c], in);
}
*count = c;
return arr;
}
char* in;
while(scanf("%s", in) != EOF) {
This tells the computer to read from standard input into the char buffer that in points to.
Which does not exist, because in is not initialised to anything (let alone a valid buffer).
I would not use scanf only fgets.
You need to allocate memory dor the arr and for every line referenced by elements of arr
char** readScores(size_t *count) {
size_t lines = 0;
char** arr = NULL, **tmp;
char* in = malloc(MAXLINE), *result;
size_t len;
if(in)
{
do{
result = fgets(in, MAXLINE, stdin);
if(result)
{
len = strlen(in);
tmp = realloc(arr, sizeof(*tmp) * (lines + 1));
if(tmp)
{
arr = tmp;
len = strlen(in);
arr[lines] = malloc(len + (len == 0));
if(arr[lines])
{
if(len) memcpy(arr[lines], in, len - 1);
arr[lines++][len] = 0;
}
else
{
// error handling
}
}
else
{
// error handling
}
}
}while(result);
free(in);
}
*count = lines;
return arr;
}
I have a Problem when I try to load a file into memory as an array.
I am trying to load a file into an array and print it out again but I would like to allow the memory to grow as the file length can be arbitrary.
When I run my Program locally on my Mac it seems to Work fine but when I try it on my Ubuntu VM, I get the following error
realloc(): invalid next size
Aborted (core dumped)
My Code is as follows
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **loadfile(char *filename, int *len);
int main(int argc, char *argv[])
{
if (argc == 1)
{
printf("Usage add file\n");
return 1;
}
int length = 0;
char **words = loadfile(argv[1],&length);
printf("%d\n", length);
for (int i = 0; i < length; i++) {
printf("%s\n",words[i]);
}
printf("Done\n");
return 0;
}
char **loadfile(char *filename, int *len)
{
const int STEPSIZE = 10;
FILE *f = fopen(filename,"r");
if (!f) {
fprintf(stderr, "Can't open file\n");
return NULL;
}
int arrlen = STEPSIZE;
char **lines = (char **)malloc(STEPSIZE);
char buf[100];
int i = 0;
int counter = 2;
while (fgets(buf,100,f))
{
if (i == arrlen)
{
counter++;
arrlen += STEPSIZE;
char **newlines = (char **)realloc(lines,counter * STEPSIZE);
if(!newlines)
{
printf("Out of memory\n");
//return 2;
}
lines = newlines;
}
buf[strlen(buf)-1] = '\0';
int slen = strlen(buf);
char *str = (char *)malloc(slen + 1 *sizeof(char ));
strcpy(str, buf);
lines[i] = str;
i++;
}
*len =i;
return lines;
}
and for the life of me I cannot find the problem.
I can only assume the problem is somewhere in this section but I may be wrong:
if (i == arrlen)
{
counter++;
arrlen += STEPSIZE;
char **newlines = (char **)realloc(lines,counter * STEPSIZE);
if(!newlines)
{
printf("Out of memory\n");
//return 2;
}
lines = newlines;
}
Your Help is greatly appreciated
const int STEPSIZE = 10;
char **lines = (char **)malloc(STEPSIZE);
char **newlines = (char **)realloc(lines,counter * STEPSIZE);
You don't want to allocate 10 bytes, but memory for 10 char * elements. Thus some subsequent access to lines[i] = str; is invalid.
What you meant to do is:
char **lines = malloc(sizeof(*lines) * STEPSIZE);
char **newlines = realloc(lines, sizeof(*newlines) * counter * STEPSIZE);
Alternatively you can use sizeof(char*).
Also:
char *str = (char *)malloc(slen + 1 *sizeof(char ));
although it is correct and will work, because sizeof(char) is 1, but it's more clearly the intention was:
char *str = malloc((slen + 1) * sizeof(char));
Also, it's good to think if you should cast the result of malloc.
You forgot that malloc and realloc take an amount of bytes, not an amount of 'cells' in your array.
The program works as expected if you replace your malloc(STEPSIZE) by malloc(STEPSIZE * sizeof(char*)) and realloc(lines, counter * STEPSIZE) by realloc(lines, (counter * STEPSIZE) * sizeof(char*))
I have some code where I'm trying to read lines in from a file and store some information from each line in a struct. Since I don't know how long the file will be, I'm dynamically adjusting the array of structs using realloc.
My issue is that my code seems to work fine for the first 3 (technically 6) lines, and then I receive SIGSEGV (address boundary error). gdb says that this happens when trying to index the array (array[i]->string = (char*) _tmp).
typedef struct {
char* string;
int len;
} buffer;
int read_into_array(char *filename, buffer** array) {
int n;
size_t size;
char* buf = NULL;
FILE *file = fopen(filename, "r");
int i = 0;
while (1) {
buffer *tmp = (buffer*)realloc(*array, sizeof(buffer) * (i + 1));
if (!tmp)
printf("Failed realloc\n");
*array = tmp;
// First line is ignored, second line is taken as data.
getline(&buf, &size, file);
n = getline(&buf, &size, file);
if (n > 0) {
void* _tmp = malloc(sizeof(char) * n);
if (!_tmp)
printf("Failed malloc\n");
array[i]->string = (char*) _tmp;
array[i]->len = n-1;
strncpy(array[i]->string, buf, n-1);
}
i++;
if (feof(file)) {
printf("saw end of file, leaving.\n");
break;
}
}
return i;
}
int main(int argc, char* argv[]) {
char *filename = argv[1];
buffer *array = (buffer*) calloc(1, sizeof(buffer));
int num = read_into_array(filename, &array);
}
Apologies for the somewhat poor formatting, I've been trying to figure this out for a while.
Since it seems to work for the first few lines, my assumption is that I'm going wrong somewhere in the realloc calculation. My other guess is that I'm somehow using/reading the file incorrectly.
Thanks for any help. For posterity, the file looks something like this https://hastebin.com/vinidiyita.sm (the real file is thousands of lines long).
when you do *array=tmp you're allocating memory for array[0]
then you're using array[i] that should be a pointer to a buffer, but points to garbage or 0
You're confusing two ways to use data.
The first is by using arrays - there's the non-dynamic:
buffer array[x] = {0};
int num = read_into_array(filename, &array);
then you can use array[i]
and there's the dynamic type:
buffer **array = calloc(initial_len*sizeof(buffer *));
int num = read_into_array(filename, array, initial_len);
read_into_array(char *filename, buffer **&array, int initial_len)
{
int len = initial_len;
...
while()
{
...
if(i>len)
{
array = realloc(array, sizeof(buffer*) * (i + 1));
len = i;
}
array[i] = calloc(sizeof(buffer));
}
}
I'm working on a little C program for a class that reads the lines in from a file and then sorts them using qsort. Long story short, I am dynamically allocating memory for every line of a file, stored as a char*, in an array of char*. The reading in and storing ostensibly works fine based upon the output (see below), but when I print out the lines, they are all duplicates of the last line in the file. Can anyone point out my (most likely painfully obvious) error?
Here is the relevant code to the problem I'm currently running into:
char* trim_white_space(char* str);
char* get_line(FILE* infile, char temp[]);
int main(int argc, char* argv[]) {
FILE* infile;
char* input_file = argv[1];
int cnt = 0;
char temp[MAX_LINE_LENGTH]; //to hold each line as it gets read in
char* tempPointer = temp;
if (argc < 2) {
printf("No input file provided");
return EXIT_FAILURE;
}
//determine the number of lines in the file
infile = fopen(input_file, "r");
int num_lines_in_file = num_lines(infile);
fclose(infile);
//allocate pointers for each line
char** lines = (char**) malloc(num_lines_in_file * sizeof(char*));
//temporarily store each line, and then dynamically allocate exact memory for them
infile = fopen(input_file, "r");
for (cnt = 0; cnt != num_lines_in_file; cnt++) {
tempPointer = get_line(infile, temp);
lines[cnt] = (char*) malloc(strlen(tempPointer) + 1);
lines[cnt] = trim_white_space(tempPointer);
printf("%d: %s\n", cnt, lines[cnt]);
}
fclose(infile);
//print the unsorted lines (for debugging purposes)
printf("Unsorted list:\n");
for (cnt = 0; cnt != num_lines_in_file; cnt++) {
printf("%s\n", lines[cnt]);
}
char* get_line(FILE* infile, char temp[]) {
fgets(temp, MAX_LINE_LENGTH-1, infile);
char* pntr = temp;
return pntr;
}
char *trimwhitespace(char *str)
{
char *end;
// Trim leading space
while(isspace(*str)) str++;
if(*str == 0) // All spaces?
return str;
// Trim trailing space
end = str + strlen(str) - 1;
while(end > str && isspace(*end)) end--;
// Write new null terminator
*(end+1) = 0;
return str;
}
I have this sample input file 5-1input.dat:
Hi guys
x2 My name is
Slim Shady
For real
And here's the output I'm getting:
user#user-VirtualBox ~/Desktop/Low-level/HW5 $ ./homework5-1 5-1input.dat
0: Hi guys
1: x2 My name is
2: Slim Shady
3: For real
Unsorted list:
For real
For real
For real
For real
As in the comments, you should change your loop to:
for (cnt = 0; cnt != num_lines_in_file; cnt++) {
tempPointer = get_line(infile, temp);
lines[cnt] = (char*) malloc(strlen(tempPointer) + 1);
strncpy(lines[cnt], trim_white_space(tempPointer), strlen(tempPointer)+1);
printf("%d: %s\n", cnt, lines[cnt]);
}
The size in strncpy is based on the size of malloc you've used.
Of course you can optimize this code, e.g. to count strlen only once, etc.
I have to dynamically allocate array of words. Words are stored in a file separated by variable count of white-space characters. I don't know how many words is in the file a they can have variable length.
I have this code:
void readWord(FILE* stream, char *word, char first_c) {
word[0] = first_c;
char val;
int wlen = 1;
// isWhitespac is my function - tests if char is blank or '\n'
while ((val = fgetc(stream)) != EOF && isWhitespace(val) == 0) {
wlen++;
word = realloc(word, (wlen+1) * sizeof (char));
word[wlen-1] = val;
}
word[wlen] = '\0';
}
int readList(const char *file) {
FILE* f;
char **arr;
char val;
int wcount = 0;
arr = malloc(sizeof (char*));
f = fopen(file, "r");
while (fscanf(f, " %c", &val) == 1) {
wcount++;
arr = realloc(arr, wcount * sizeof (char *));
arr[wcount - 1] = malloc(sizeof (char));
readWord(f, arr[wcount-1], val);
printf("%s\n", arr[wcount-1]);
}
for (int i = 0; i < wcount; ++i) {
free(arr[i]);
}
free(arr);
fclose(f);
return 0;
}
It appears to work fine, it reads a prints all the words. But when I run the program with Valgrind the are too many errors, which I can't find. Could anyone help me? (I know I have to test if malloc and others went fine, it is just a test func.)
The Valgrind log is quite long, should I post it too?
One of the issues is that you do realloc inside readWord. If realloc allocates a new buffer and doesn't just extend the current one then your code will crash (you will double free the pointer) and this is what Valgrind picks up. To fix this I would rewrite the code so it returns a pointer instead of void.
char * readWord(FILE* stream, char *word, char first_c) {
word[0] = first_c;
char val;
int wlen = 1;
// isWhitespac is my function - tests if char is blank or '\n'
while ((val = fgetc(stream)) != EOF && isWhitespace(val) == 0) {
wlen++;
word = realloc(word, (wlen+1) * sizeof (char));
word[wlen-1] = val;
}
word[wlen] = '\0';
return word;
}
And then change the loop in readList to this:
while (fscanf(f, " %c", &val) == 1) {
wcount++;
arr = realloc(arr, wcount * sizeof (char *));
arr[wcount-1]=malloc(sizeof(char));
arr[wcount - 1] = readWord(f, arr[wcount-1], val);
printf("%s\n", arr[wcount-1]);
}