Hello I seem to be having an issue with freeing some of my variables after creating them.
Little background on my program. My program is reading MatrixMarket files and building a Matrix Structure from the information read in. I am then using the matrices to do scalar and vector multiplication.
This is my structure for my matrix.
typedef struct {
double *values; // Value of each non-zero element.
unsigned int *col_indices; // Corresponding column coordinate.
unsigned int *row_ptr; // Initial position of each row.
unsigned int nz; // Total non-zero elements.
unsigned int row_count; // Total row_count of matrix.
unsigned int cols_count; // Total columns of matrix.
} CSRMatrix;
My goal here is to be able to manipulate my matrix and be able to multiply a vector to the CSR Matrix. (CSR is Compressed Sparse Row Matrix).
Here is how I am initializing my memory allocation.
/**
* Set the correct values to the struct and create the memory allocation.
*/
csrMatrix.row_count = numberOfRows;
csrMatrix.cols_count = numberOfColumn;
csrMatrix.nz = numberOfNonZeros;
csrMatrix.row_ptr = calloc(numberOfRows, 1);
csrMatrix.values = (double *)malloc(numberOfRows * numberOfRows * 1);
csrMatrix.col_indices = calloc(numberOfRows * numberOfRows, 1);
Here is where I think my issue is, I may be wrong. I'm terrible at troubleshooting memory issues.
Before I go more in-depth here is where the main multiplication and iteration to the matrix happens:
// Initialize vectors for multiplication
int x_size = numberOfRows * numberOfColumn;
int csr_x[x_size];
memset(csr_x, 0, sizeof(csr_x));
for(int h = 0; h < x_size; h++){
csr_x[h] = 1;
}
double* csr_y;
printf("\nCalculating matrix-vector product of the CSR for %u iterations...\n", iterations);
clock_t begin = clock();
for(i=0; i < iterations; i++){
csr_y = (double *)malloc(csrMatrix.row_count * csrMatrix.cols_count * 1);
csrMVP(&csrMatrix, csr_x,csr_y);
free(csr_y);
}
clock_t end = clock();
double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("for loop used %f seconds to complete the execution\n", time_spent);
fclose(file);
free(csr_x);
free(csr_y);
exit(EXIT_SUCCESS);
When I run my program strange things being to happen. The program will run for a few loops (total loops is 1000 iterations) then either exit incomplete with Process finished with exit code 0 or with exit code 11. This is where my troubleshooting started.
Since intellij is not throwing any memory issues or errors I have to go deeper.
I decided to ask a friend of mine who has used Valgrind to do a memcheck on my program. This was the result:
==5607== Memcheck, a memory error detector
==5607== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5607== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5607== Command: ./code
/home/tron/src/workspace/classes/cda5110/matrix/mat/ibm32/ibm32.mtx
==5607==
==5607== Invalid write of size 4
==5607== at 0x109537: loadCSRMatrix (mainCSR.c:173)
==5607== by 0x108F3A: main (mainCSR.c:72)
==5607== Address 0x51f23b0 is 0 bytes after a block of size 128 alloc'd
==5607== at 0x4C2EEF5: calloc (vg_replace_malloc.c:711)
==5607== by 0x108EC5: main (mainCSR.c:64)
==5607==
==5607== Invalid read of size 4
==5607== at 0x109300: csrMVP (mainCSR.c:140)
==5607== by 0x109085: main (mainCSR.c:92)
==5607== Address 0x51f23b0 is 0 bytes after a block of size 128 alloc'd
==5607== at 0x4C2EEF5: calloc (vg_replace_malloc.c:711)
==5607== by 0x108EC5: main (mainCSR.c:64)
==5607==
==5607== Invalid free() / delete / delete[] / realloc()
==5607== at 0x4C2E10B: free (vg_replace_malloc.c:530)
==5607== by 0x10910C: main (mainCSR.c:99)
==5607== Address 0x1ffefff5a0 is on thread 1's stack
==5607== in frame #1, created by main (mainCSR.c:24)
==5607==
==5607== Invalid free() / delete / delete[] / realloc()
==5607== at 0x4C2E10B: free (vg_replace_malloc.c:530)
==5607== by 0x10911B: main (mainCSR.c:100)
==5607== Address 0x59d3bc0 is 0 bytes inside a block of size 8,192 free'd
==5607== at 0x4C2E10B: free (vg_replace_malloc.c:530)
==5607== by 0x109094: main (mainCSR.c:93)
==5607== Block was alloc'd at
==5607== at 0x4C2CEDF: malloc (vg_replace_malloc.c:299)
==5607== by 0x109064: main (mainCSR.c:91)
==5607==
==5607==
==5607== HEAP SUMMARY:
==5607== in use at exit: 12,416 bytes in 3 blocks
==5607== total heap usage: 1,006 allocs, 1,005 frees, 8,213,160 bytes
allocated
==5607==
==5607== LEAK SUMMARY:
==5607== definitely lost: 0 bytes in 0 blocks
==5607== indirectly lost: 0 bytes in 0 blocks
==5607== possibly lost: 0 bytes in 0 blocks
==5607== still reachable: 12,416 bytes in 3 blocks
==5607== suppressed: 0 bytes in 0 blocks
==5607== Rerun with --leak-check=full to see details of leaked memory
==5607==
==5607== For counts of detected and suppressed errors, rerun with: -v
==5607== ERROR SUMMARY: 1003 errors from 4 contexts (suppressed: 0 from 0)
There are few things that popped out at me. There are a few invaild write and read sizes. These are the following lines for each code called out by the errors:
at 0x109537: loadCSRMatrix (mainCSR.c:173): m->row_ptr[row_index + 1] = pairIndex;
by 0x108F3A: main (mainCSR.c:72): loadCSRMatrix(&csrMatrix, file);
by 0x108EC5: main (mainCSR.c:64): csrMatrix.row_ptr = calloc(numberOfRows, 1);
at 0x109300: csrMVP (mainCSR.c:140): y[i] += val[j] * x[col[j]];
by 0x109085: main (mainCSR.c:92): free(csr_y);
by 0x108EC5: main (mainCSR.c:64): csrMatrix.row_ptr = calloc(numberOfRows, 1);
by 0x10910C: main (mainCSR.c:99): free(csr_y);
by 0x10911B: main (mainCSR.c:100): exit(EXIT_SUCCESS);
by 0x109094: main (mainCSR.c:93): }
by 0x109064: main (mainCSR.c:91): csrMVP(&csrMatrix, csr_x,csr_y);
From what I bring it down to is that I am not correctly utilizing malloc and calloc for my memory allocation.
So here's where I ask my question, I am not sure if malloc or calloc are used correctly. If anyone knows where I can start looking to fix this issue.
In case you're wondering what loadCSRMatrix and csrMVP functions are I will attach them below.
csrMVP
/**
* Stores on vector y the product of matrix M and vector x:
* y = Mx
*/
void csrMVP(CSRMatrix *m, int x[], double *y){
printf("\n\n\nValue of Y: \n ");
unsigned int i,j,end;
double *val = m->values;
unsigned int *col = m->col_indices;
unsigned int *ptr = m->row_ptr;
end = 0;
for(i = 0; i < m->row_count; i++){
y[i] = 0.0;
j = end;
end = ptr[i+1];
for( ; j < end; j++){
y[i] += val[j] * x[col[j]];
printf("%.f\t", y[i]);
}
}printf("\n");
}
loadCSRMatrix
/**
* Loads the matrix
*/
void loadCSRMatrix(CSRMatrix *m, FILE *f){
unsigned int pairIndex = 0;
for (int row_index = 0; row_index < m->row_count; row_index++) {
for (unsigned int column_index = 0; column_index < m->row_count; column_index++) {
double value;
if(fscanf(f, "%lg", &value) != EOF){
m->values[pairIndex] = value;
m->col_indices[pairIndex] = column_index+1;
//printf("Column: %d\t", matrixCSR.col_indices[pairIndex]);
printf("%.f\t", m->values[pairIndex]);
pairIndex++;
}
else {
m->values[pairIndex] = 0;
m->col_indices[pairIndex] = column_index+1;
//printf("Column: %d\t", matrixCSR.col_indices[pairIndex]);
printf("%.1f\t", m->values[pairIndex]);
pairIndex++;
}
}
if(pairIndex != 0) {
m->row_ptr[row_index + 1] = pairIndex;
}
//printf("%zu\n", matrixCSR.row_indices[row_index]);
printf("\n");
}
}
Related
I ran valgrind on my program (which works as expected) but valgrind reports 12 bytes of memory leakage and a couple instances of uninitialised values that I just can't find in my code.
The program is a simple quadratic equation solver, the vast majority of the maths stuff takes place in quadSolver.c, whereas the input validation and returning the results to the user in a clean, presentable way is in main.c.
main.c:
#include <stdlib.h>
#include "quadSolver.h"
int main(int argv, char* args[]){
if (argv != 4) {
printf("Invalid arguments.\n");
printf("Input: ./solve x y z\n");
exit(0);
} else if (!isNumber(args[1]) || !isNumber(args[2]) || !isNumber(args[3])) {
printf("Invalid arguments.\n");
printf("Arguments must be integers.\n");
exit(0);
}
int* a = calloc(1, sizeof(int));
int* b = calloc(1, sizeof(int));
int* c = calloc(1, sizeof(int));
*a = strtol(args[1], NULL, 10);
*b = strtol(args[2], NULL, 10);
*c = strtol(args[3], NULL, 10);
double** roots = calloc(3, sizeof(int));
roots = findRoots(*a, *b, *c);
if(*roots[0] == 0) {
printf("Roots are imaginary.\n");
} else if(*roots[0] == 1) {
printf("Roots are real and equal.\n");
printf("Roots = %f\n", *roots[1]);
} else {
printf("Roots are real and unequal.\n");
printf("Root A = %f\n", *roots[1]);
printf("Root B = %f\n", *roots[2]);
}
free(a);
free(b);
free(c);
free(roots);
}
quadSolver.c:
#include "quadSolver.h"
bool isNumber(char* input) {
int i = 0;
if (input[0] == '-') {
i = 1;
}
for (i; input[i] != '\0'; i++) {
if(!isdigit(input[i])) {
return false;
}
}
return true;
}
int determineNumberOfRoots(int a, int b, int c) {
if ((square(b)-4*a*c) > 0) {
return 2;
} else if ((square(b)-4*a*c) == 0) {
return 1;
} else {
return 0;
}
}
int square(int x) {
int answer = x * x;
return answer;
}
double** findRoots(int a, int b, int c) {
if (determineNumberOfRoots(a, b, c) == 0) {
double** result = calloc(1, sizeof(double));
double num = 0;
result[0] = #
return result;
} else if (determineNumberOfRoots(a, b, c) == 1) {
double* root = calloc(1, sizeof(double));
*root = (-b)/(2*a);
double** result = calloc(2, sizeof(double));
double num = 1.0;
result[0] = #
result[1] = root;
return result;
} else {
double* rootPos = calloc(1, sizeof(double));
double* rootNeg = calloc(1, sizeof(double));
*rootPos = (double) ((-b) + sqrt((double)(square(b)-(4*a*c))))/(2*a);
*rootNeg = (double) ((-b) - sqrt((double)(square(b)-(4*a*c))))/(2*a);
double** result = calloc(3, sizeof(double));
double num = 2.0;
result[0] = #
result[1] = rootPos;
result[2] = rootNeg;
return result;
}
}
Valgrind says:
==34332== Conditional jump or move depends on uninitialised value(s)
==34332== at 0x1093E1: main (in /home/lugehr/Documents/Programming Practice/C/QuadraticSolver/solve)
==34332== Uninitialised value was created by a stack allocation
==34332== at 0x1093CA: main (in /home/lugehr/Documents/Programming Practice/C/QuadraticSolver/solve)
==34332==
==34332== Conditional jump or move depends on uninitialised value(s)
==34332== at 0x1093EB: main (in /home/lugehr/Documents/Programming Practice/C/QuadraticSolver/solve)
==34332== Uninitialised value was created by a stack allocation
==34332== at 0x1093CA: main (in /home/lugehr/Documents/Programming Practice/C/QuadraticSolver/solve)
==34332== HEAP SUMMARY:
==34332== in use at exit: 12 bytes in 1 blocks
==34332== total heap usage: 6 allocs, 5 frees, 1,056 bytes allocated
==34332==
==34332== 12 bytes in 1 blocks are definitely lost in loss record 1 of 1
==34332== at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==34332== by 0x1093AA: main (in /home/lugehr/Documents/Programming Practice/C/QuadraticSolver/solve)
==34332==
==34332== LEAK SUMMARY:
==34332== definitely lost: 12 bytes in 1 blocks
==34332== indirectly lost: 0 bytes in 0 blocks
==34332== possibly lost: 0 bytes in 0 blocks
==34332== still reachable: 0 bytes in 0 blocks
==34332== suppressed: 0 bytes in 0 blocks
==34332==
You're leaking the memory in main() at:
double **roots = calloc(3, sizeof(int)));
The call to findRoots() on the next line, allocates memory inside itself, and overwrites the value of roots when it returns, in the end you leak the 3*sizeof(int) (allocated inside main) bytes which is now unreachable due to the overwrite previously mentioned.
Your program however, is riddled with other kinds of bugs, as mentioned in the comments, but the scope of this answer is to address the memory leak.
EDIT: For future reference, when debugging, you should compile your programs with debug information (e.g. gcc/clang -g ...) so that valgrind has more context to work with and it becomes easier to figure out the leaks when you can e.g. get line numbers directly in the output.
I am not sure why I am getting this error, I am running a steganography program which takes in a PPM file and allows a user to encode a message into the PPM file and it I tried to debug in valgrind and the error occurs:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
struct PPM {
char *comments;
char *ppmname;
unsigned int width, height, max;
unsigned int size;
struct Pixel**pixels;
}ppm;
struct Pixel {
int r, g, b;
}Pixel;
static int *decimalToBinary(const char *message, unsigned int msgSize);
struct PPM * getPPM(FILE * f);
struct PPM *encode(struct PPM *im, char *message, unsigned int mSize, unsigned int secret);
void showPPM(struct PPM * im);
int main(int argc, char *argv[]){
FILE * fin = fopen("home-cat.ppm", "r");
if(fin == NULL) {
perror("Cannot open file");
exit(1);
}
struct PPM *p = getPPM(fin);
struct PPM *g = encode(p, "test", 5, 2);
showPPM(g);
free(p->comments);
free(p);
return 0;
}
struct PPM * getPPM(FILE * f) {
ppm.comments = (char *)calloc(70,sizeof(char));
ppm.ppmname = (char *)calloc(3,sizeof(char));
fscanf(f, "%s", ppm.ppmname);
fgetc(f);
fgets(ppm.comments, 70, f);
fscanf(f, "%d %d", &ppm.width, &ppm.height);
fscanf(f, "%d", &ppm.max);
ppm.size = ppm.width * ppm.height;
ppm.pixels = (struct Pixel**)malloc(ppm.width * sizeof(struct Pixel));
for (int i=0; i<ppm.width; i++) {
ppm.pixels[i] = (struct Pixel*)malloc(ppm.height*sizeof(struct Pixel));
}
for (int i=0; i<ppm.width; i++) {
for (int j=0; j<ppm.height; j++) {
fscanf(f, "%d %d %d", &ppm.pixels[i][j].r, &ppm.pixels[i][j].g, &ppm.pixels[i][j].b);
}
}
return &ppm;
}
void showPPM(struct PPM * im) {
printf("%s\n", ppm.ppmname);
printf("%s", ppm.comments);
printf("%d %d\n", ppm.width, ppm.height);
printf("%d\n", ppm.max);
for (int i=0; i<ppm.width; i++) {
for (int j=0; j<ppm.height; j++){
printf("%d %d %d\n", ppm.pixels[i][j].r, ppm.pixels[i][j].g, ppm.pixels[i][j].b);
}
}
}
struct PPM *encode(struct PPM *im, char *message, unsigned int mSize, unsigned int secret) {
int *binaryMessage = decimalToBinary(message, mSize);
int i, j, k;
bool unique;
srand(secret);
int used[40]; memset(used, -1, sizeof(used)); // might have the last two args backwards... I always forget lol
for(i = 0; i < 39; i+=3) {
// determine next pixel based on the user's secret (srand)
// and without ovewrwriting a previous hidden message
do {
unique = true;
j = rand() % 3; // get new number and then check if it's unique
for(k = 0; k < i; k++) if (used[i] == j) {unique = false; break;}
} while(!unique);
im->pixels[j]->r = im->pixels[j]->r & ~1 | binaryMessage[i+0]; // ~1 is 11111110
im->pixels[j]->g = im->pixels[j]->g & ~1 | binaryMessage[i+1]; // anding keeps the first 7 and clears the last
im->pixels[j]->b = im->pixels[j]->b & ~1 | binaryMessage[i+2]; // oring will set it if the binaryMessage is set
}
// should make a function...
do {
unique = true;
j = rand() % 3; // get new number and then check if it's unique
for(int k = 0; k < 39; k++) if (used[i] == j) {unique = false; break;}
} while(!unique);
im->pixels[j]->r = im->pixels[j]->r & ~1 | binaryMessage[39]; // last bit
free(binaryMessage);
return im;
}
static int *decimalToBinary(const char *message, unsigned int length) {
/*
* malloc is used here instead of [] notation to allocate memory,
* because defining the variable with [] will make its scope
* limited to this function only. Since we want to access this
* array later on, we use malloc to assign space in the memory
* for it so we can access it using a pointer later on.
*/
int k = 0, i, j;
unsigned int c;
unsigned int *binary = malloc(8 * length * sizeof(int));
for(i = 0; i < length; i++) {
c = message[i];
for(j = 7; j >= 0; j--,k++) {
/*
* We check here if the jth bit of the number is 1 or 0
* using the bit operator &. If it is 1, it will return
* 1 because 1 & 1 will be true. Otherwise 0.
*/
if((c >> j) & 1)
binary[k] = 1;
else
binary[k] = 0;
}
}
return binary;
}
I was not sure why it occurred so I ran the error inside valgrind because I read online that it is a very useful debugger however I still cannot understand what the trace of the problem is. Here is the error report in valgrind:
==2066== Invalid free() / delete / delete[] / realloc()
==2066== at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2066== by 0x108B14: main (in /home/ziyad/test12)
==2066== Address 0x30a060 is 0 bytes inside data symbol "ppm"
==2066==
==2066==
==2066== HEAP SUMMARY:
==2066== in use at exit: 2,150,955 bytes in 515 blocks
==2066== total heap usage: 519 allocs, 5 frees, 2,156,305 bytes allocated
==2066==
==2066== 3 bytes in 1 blocks are still reachable in loss record 1 of 4
==2066== at 0x4C31B25: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2066== by 0x108B4D: getPPM (in /home/ziyad/test12)
==2066== by 0x108AC8: main (in /home/ziyad/test12)
==2066==
==2066== 552 bytes in 1 blocks are still reachable in loss record 2 of 4
==2066== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2066== by 0x4EBAE49: __fopen_internal (iofopen.c:65)
==2066== by 0x4EBAE49: fopen##GLIBC_2.2.5 (iofopen.c:89)
==2066== by 0x108A9B: main (in /home/ziyad/test12)
==2066==
==2066== 6,144 bytes in 1 blocks are still reachable in loss record 3 of 4
==2066== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2066== by 0x108C0E: getPPM (in /home/ziyad/test12)
==2066== by 0x108AC8: main (in /home/ziyad/test12)
==2066==
==2066== 2,144,256 bytes in 512 blocks are still reachable in loss record 4 of 4
==2066== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2066== by 0x108C53: getPPM (in /home/ziyad/test12)
==2066== by 0x108AC8: main (in /home/ziyad/test12)
==2066==
==2066== LEAK SUMMARY:
==2066== definitely lost: 0 bytes in 0 blocks
==2066== indirectly lost: 0 bytes in 0 blocks
==2066== possibly lost: 0 bytes in 0 blocks
==2066== still reachable: 2,150,955 bytes in 515 blocks
==2066== suppressed: 0 bytes in 0 blocks
==2066==
==2066== For counts of detected and suppressed errors, rerun with: -v
==2066== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
ppm is a stack object, not a heap-allocated one. You should not free it. You must only call free() on pointers previously returned by malloc() or calloc(). This is not the case here, so don't free() it.
I want to free the double pointer, the problem is I was receiving as parameter another double pointer which actually makes a copy of the one I wanna free but that means it doesn't actually free the original, so how can I free the original in another function.
I've tried passing a double pointer as argument and a pointer pointing to this double pointer too but none of this worked.
int main(){
int ** matrix;
int rows = 5;
int cols = 6;
matrix = createMatrix(rows, cols);
printf("%d\n", matrix[2][3]);
freeMatrix(matrix, rows);
printf("%d\n", matrix[2][3]);
}
int** createMatrix(int row, int col){
int **m = (int **)malloc(row * sizeof(int*));
for(int x = 0; x < row; x++){
m[x] = (int *)malloc(col * sizeof(int));
}
return m;
}
void freeMatriz(int **m, int row){
for(int x = 0; x < row; x++){
free(m[x]);
}
free(m);
}
I was trying to print a position, lets say matrix[2][3] before and after the free; but both times its printing the number when after the print it shouldn't because that space in memory its supposed to be freed which apparently is not happening.
other than the typo in the
void freeMatriz(int **m, int row)
^
This is correctly freeing up the memory. The printf after freeing the matrix should actually result in an access violation. Which when testing with a MUCH larger 1024x2048 matrix this is what happens. My theories are as follows...
The memory has not yet been reclaimed and was still within program reach...
Some sort of delay in garbage collection or something.. lol
I'll leave it up to someone who might know why the second printf worked with such a small memory space being allocated to do so.. ;) would love to know the exact reason..
if you step through this with a debugger you will see the memory does get freed properly and if stepped through with a debugger the second printf results in an access violation... so it's gotta have something to do with the kernel.. :)
If you look at the Working Set and the Memory allocation in task manager, and put a system("pause") or getchar() (whatever type of break you want) before the free.. you can allocate a large matrix, check in in task manager... resume the program (with another break after the free). and you will see that the memory is being released. :)
Your two primary problems are:
You fail to validate the return of each allocation so malloc could have failed and you would have no way of knowing; and
After allocating storage for your integer values, you fail to initialize the memory, leaving the memory holding whatever garbage values happened to be present at that memory location (you can, and in the case of your integer allocations, use calloc to allocate and initialize at the same time, or use memset to do the same)
Your attempt to access matrix[2][3] before free() was simply accessing a uninitialized 4-bytes of memory containing whatever bits happened to be there. Your attempt to access matrix[2][3] after free() invokes Undefined Behavior. After free(), you can no longer validly access the memory that has been freed.
If you allocate, you must validate... It's not a matter of if malloc can fail returning NULL, it is a matter of when malloc fails returning NULL. To handle the failure case, you must always check the return of the allocation function (just as you do with every input function) you use. It is simple, if malloc returns NULL the allocation failed. So just check, e.g.
int **creatematrix (int row, int col)
{
int **m = malloc (row * sizeof *m);
if (!m) { /* if you allocate -- you must VALIDATE */
perror ("malloc-m");
return NULL;
}
for (int x = 0; x < row; x++) {
if (!(m[x] = malloc (col * sizeof *m[x]))) { /* ditto */
perror ("malloc-m[x]");
while (x--) /* on error free any allocated memory */
free (m[x]);
free (m); /* before returing NULL */
return NULL;
}
}
return m;
}
(note: before returning NULL you should free() any memory you have allocated up to that point to prevent a memory leak when you return NULL)
In your calling function (main() here), you need to validate the return of your creatematrix function to determine success/failure of the allocate -- before you make use of the memory, e.g.
int main (void) {
int **matrix,
rows = 5,
cols = 6;
if (!(matrix = creatematrix (rows, cols))) /* VALIDATE allocations */
exit (EXIT_FAILURE);
for (int i = 0; i < rows; i++) { /* loop initializing all values */
for (int j = 0; j < cols; j++) {
matrix[i][j] = i * cols + j;
printf (" %3d", matrix[i][j]); /* output all values */
}
putchar ('\n');
}
freematrix (matrix, rows); /* free all allocated memory */
}
Now you can free() all memory (which except for the typo of 'z' instead of 'x' you were doing correctly). Putting it altogether you could do:
#include <stdio.h>
#include <stdlib.h>
int **creatematrix (int row, int col)
{
int **m = malloc (row * sizeof *m);
if (!m) { /* if you allocate -- you must VALIDATE */
perror ("malloc-m");
return NULL;
}
for (int x = 0; x < row; x++) {
if (!(m[x] = malloc (col * sizeof *m[x]))) { /* ditto */
perror ("malloc-m[x]");
while (x--) /* on error free any allocated memory */
free (m[x]);
free (m); /* before returing NULL */
return NULL;
}
}
return m;
}
void freematrix (int **m, int row)
{
for (int x = 0; x < row; x++)
free (m[x]);
free (m);
}
int main (void) {
int **matrix,
rows = 5,
cols = 6;
if (!(matrix = creatematrix (rows, cols))) /* VALIDATE allocations */
exit (EXIT_FAILURE);
for (int i = 0; i < rows; i++) { /* loop initializing all values */
for (int j = 0; j < cols; j++) {
matrix[i][j] = i * cols + j;
printf (" %3d", matrix[i][j]); /* output all values */
}
putchar ('\n');
}
freematrix (matrix, rows); /* free all allocated memory */
}
Example Use/Output
$ ./bin/freematrix
0 1 2 3 4 5
6 7 8 9 10 11
12 13 14 15 16 17
18 19 20 21 22 23
24 25 26 27 28 29
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/freematrix
==17080== Memcheck, a memory error detector
==17080== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==17080== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==17080== Command: ./bin/freematrix
==17080==
0 1 2 3 4 5
6 7 8 9 10 11
12 13 14 15 16 17
18 19 20 21 22 23
24 25 26 27 28 29
==17080==
==17080== HEAP SUMMARY:
==17080== in use at exit: 0 bytes in 0 blocks
==17080== total heap usage: 6 allocs, 6 frees, 160 bytes allocated
==17080==
==17080== All heap blocks were freed -- no leaks are possible
==17080==
==17080== For counts of detected and suppressed errors, rerun with: -v
==17080== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.
I am trying to simulate matrices using 2d arrays. But I am stuck at a run-time error. I am sure it occurs at printing function,but I couldn't find a solution at all.
obtn_matrix is a function that I use to create a matrix array. I didn't share the filler function which is used to get int values for the elements of the matrix array,so printed values will be whats in the memory. However, the problem is, I can't print the values at all. Program crashes after obtn_matrix.
int main()
{
int**matrix,m,n;
obtn_matrix(matrix,m,n);
prnt_matrix(matrix,m,n);
getch();
}
void prnt_matrix(int** matrix,int m,int n)
{
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
printf("%d ",matrix[i][j]);
}
printf("\n");
}
}
void obtn_matrix(int** matrix,int m,int n)
{
printf("Please enter the column number: ");
fflush(stdin);
scanf("%d",&m);
printf("Please enter the row number: ");
fflush(stdin);
scanf("%d",&n);
matrix=create_matrix(m,n);
}
The expected result is something like below:
4542 64 274 4234
765 53 3523 5345
5145 154 545 545
5435 543 545 14
I will handle the formatting (%4d etc). Kindly thanks in advance.
in obtn_matrix the assignment of matrix, m and n are not visible from main , you need to use pointer to them.
For instance, using array of int * because the dimensions are unknown at compile time:
#include <stdio.h>
#include <stdlib.h>
void prnt_matrix(int ** matrix,int m,int n)
{
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
printf("%d ",matrix[i][j]);
}
printf("\n");
}
}
int ** create_matrix(int m, int n)
{
int ** ma = calloc(m, sizeof(int*));
if (ma != NULL) {
int i, j;
for (i = 0; i != m; ++i) {
if ((ma[i] = malloc(n*sizeof(int))) == NULL)
return NULL;
for (j = 0; j != n; ++j) {
ma[i][j] = i*n + j;
}
}
}
return ma;
}
void obtn_matrix(int *** matrix,int * m,int * n)
{
printf("Please enter the row number: ");
fflush(stdin);
scanf("%d",m);
printf("Please enter the column number: ");
fflush(stdin);
scanf("%d",n);
*matrix=create_matrix(*m,*n);
}
void free_matrix(int ** matrix,int m,int n)
{
for(int i=0;i<m;i++)
{
if (matrix[i] == NULL)
/* matrix creation was aborted */
break;
free(matrix[i]);
}
free(matrix);
}
int main()
{
int ** matrix,m,n;
obtn_matrix(&matrix,&m,&n);
if (matrix != NULL) {
prnt_matrix(matrix,m,n);
free_matrix(matrix,m,n);
}
}
Compilation and execution :
pi#raspberrypi:~ $ gcc -pedantic -Wextra m.c
pi#raspberrypi:~ $ ./a.out
Please enter the row number: 3
Please enter the column number: 2
0 1
2 3
4 5
Execution under valgrind
pi#raspberrypi:~ $ valgrind ./a.out
==10436== Memcheck, a memory error detector
==10436== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10436== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10436== Command: ./a.out
==10436==
Please enter the row number: 3
Please enter the column number: 2
0 1
2 3
4 5
==10436==
==10436== HEAP SUMMARY:
==10436== in use at exit: 0 bytes in 0 blocks
==10436== total heap usage: 6 allocs, 6 frees, 2,084 bytes allocated
==10436==
==10436== All heap blocks were freed -- no leaks are possible
==10436==
==10436== For counts of detected and suppressed errors, rerun with: -v
==10436== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
Note it is also possible to just alloc one array of m*n int but in that case rather than to use m[i][j]you need to do m[i*n+j]
If you haven't fully wrapped your head around the basic problem you are having, the problem is this, C passes parameters to functions by value. What this means is that when a parameter is passed, the function receives a copy of the variable which it is free to change -- but any changes are lost when the function returns.
One caveat to this is when an allocated pointer is passed. While it is still passed by value and the pointer will have its very own and very different address from the original, the memory address it holds as its value will still point to the same address as it does in the caller. This is no different that assigning int a = 5; and then passing a as a parameter, the function receives a copy of the variable, but it still contains 5.
However, if you attempt to allocate or reallocate such that the address of the pointer is changed, then any changes made in the function will be lost on return and not visible in the caller.
How Do You Handle This?
You have two options (1) pass the address of the pointer, so any changes to the address can be assigned to the dereferenced pointer (i.e. the original pointer address), or (2) change the return type from void to the type of pointer that needs to be returned and return the newly allocated/reallocated pointer for assignment in the caller.
For example, in your case, you need not pass matrix as a parameter to obtn_matrix() at all. You can simply use option (2) above and change the return type of obtn_matrix() to int ** and return create_matrix (*m, *n); at the end, e.g.
int **create_matrix (int m, int n)
{
int **matrix = malloc (m * sizeof *matrix);
if (matrix == NULL) {
perror ("malloc-matrix");
return NULL;
}
for (int i = 0; i < m; i++)
/* use calloc to initialize values zero */
if ((matrix[i] = calloc (n, sizeof **matrix)) == NULL) {
perror ("malloc-matrix[n]");
return NULL;
}
return matrix;
}
/* use pointers as parameters so the updated values of m, n are
* available back in the caller after the function returns. return
* int** for assignment back in the caller. Avoids becoming a
* 3-Star Programmer (not a compliment). return NULL on failure.
*/
int **obtn_matrix (int *m, int *n)
{
fputs ("enter number of rows: ", stdout);
if (scanf ("%d", m) != 1) { /* validate ALL user-input */
fputs ("error: invalid number of rows.\n", stderr);
return NULL;
}
fputs ("enter number of cols: ", stdout);
if (scanf ("%d", n) != 1) {
fputs ("error: invalid number of cols.\n", stderr);
return NULL;
}
return create_matrix (*m, *n);
}
Now putting it altogether, and making note that #bruno explains why you must pass the address of m, n (e.g. &m, &n) to obtn_matrix (option (1) above) so the updated values of m & n are available back in main() (the caller here), you could do something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int **create_matrix (int m, int n)
{
int **matrix = malloc (m * sizeof *matrix);
if (matrix == NULL) {
perror ("malloc-matrix");
return NULL;
}
for (int i = 0; i < m; i++)
/* use calloc to initialize values zero */
if ((matrix[i] = calloc (n, sizeof **matrix)) == NULL) {
perror ("malloc-matrix[n]");
return NULL;
}
return matrix;
}
/* use pointers as parameters so the updated values of m, n are
* available back in the caller after the function returns. return
* int** for assignment back in the caller. Avoids becoming a
* 3-Star Programmer (not a compliment). return NULL on failure.
*/
int **obtn_matrix (int *m, int *n)
{
fputs ("enter number of rows: ", stdout);
if (scanf ("%d", m) != 1) { /* validate ALL user-input */
fputs ("error: invalid number of rows.\n", stderr);
return NULL;
}
fputs ("enter number of cols: ", stdout);
if (scanf ("%d", n) != 1) {
fputs ("error: invalid number of cols.\n", stderr);
return NULL;
}
return create_matrix (*m, *n);
}
void prnt_matrix (int **matrix, int m, int n)
{
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++)
printf (" %4d", matrix[i][j]);
putchar ('\n');
}
}
void free_matrix (int **matrix, int m)
{
for (int i = 0; i < m; i++)
free (matrix[i]); /* free integers */
free (matrix); /* free pointers */
}
int main (void) {
int **matrix, m = 0, n = 0;
if ((matrix = obtn_matrix (&m, &n)) == NULL)
return 1;
prnt_matrix (matrix, m, n);
free_matrix (matrix, m);
return 0;
}
Since you "didn't share the filler function", the code above simply zeros all integer values by allocating the integers for each row with calloc instead of malloc which is a good idea when working with simulated arrays so that if you inadvertently fail to initialize one of the integers, you don't SegFault when you attempt to traverse all elements to, e.g. prnt_matrix, etc...
Example Use/Output
$ ./bin/matrix_cr_obtn
enter number of rows: 5
enter number of cols: 3
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/matrix_cr_obtn
==10251== Memcheck, a memory error detector
==10251== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==10251== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==10251== Command: ./bin/matrix_cr_obtn
==10251==
enter number of rows: 5
enter number of cols: 3
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
==10251==
==10251== HEAP SUMMARY:
==10251== in use at exit: 0 bytes in 0 blocks
==10251== total heap usage: 6 allocs, 6 frees, 100 bytes allocated
==10251==
==10251== All heap blocks were freed -- no leaks are possible
==10251==
==10251== For counts of detected and suppressed errors, rerun with: -v
==10251== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.
So I've looked over about every issue i could fine both on stack and many other sources. While i was able to fix some issues and add some extra testing it still hasnt resolved my issue. The program is set up with mergesort.c, which calls the functions, mergesortTest.c, which tests my functions. The serial implementation works just fine. I got past the issue with my initial creates. However, now that im trying to join them I'm getting a seg fault. Ive used both valgrind and gdb to test it and its on my join. Though i cant print out an error message since it causes a seg fault and shuts down my program. Ive made sure to try and allocate proper space. However ill post my code and the output of gdb in hopes someone can help me with this.
**mergesort.c**
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define TRUE 1
#define FALSE 0
#define MAX 100000000
#define MAX_CORE 4
// function prototypes
void serial_mergesort(int A[], int p, int r);
void merge(int A[], int p, int q, int r);
void insertion_sort(int A[], int p, int r);
void *pthread_mergesort(void *arg);
struct mergeS
{
int numElements;
int *A;
int level;
int Max_Level;
};
const int INSERTION_SORT_THRESHOLD = 100; //based on trial and error
/*
* insertion_sort(int A[], int p, int r):
*
* description: Sort the section of the array A[p..r].
*/
void insertion_sort(int A[], int p, int r)
{
int j;
for (j=p+1; j<=r; j++) {
int key = A[j];
int i = j-1;
while ((i > p-1) && (A[i] > key)) {
A[i+1] = A[i];
i--;
}
A[i+1] = key;
}
}
/*
* serial_mergesort(int A[], int p, int r):
*
* description: Sort the section of the array A[p..r].
*/
void serial_mergesort(int A[], int p, int r)
{
if (r-p+1 <= INSERTION_SORT_THRESHOLD) {
insertion_sort(A,p,r);
} else {
int q = (p+r)/2;
serial_mergesort(A, p, q);
serial_mergesort(A, q+1, r);
merge(A, p, q, r);
}
}
/*
* pthread_mergesort(void *arg)
*
* description:Sorts based off levels
*
*/
void *pthread_mergesort(void *arg)
{
struct mergeS *threader = (struct mergeS*) arg;
int i = 0;
int flag = 0;
int level = (threader)->level;
printf("level: %d\n",level);
int numElements = threader->numElements;
int Max_Level = threader->Max_Level;
int *A = threader->A;
if(Max_Level == 1)
{
serial_mergesort(A,1,numElements + 1);
return NULL;
}
int low = level * (numElements/Max_Level) + 1;
int high =((level + 1) * ((numElements/Max_Level)));
pthread_t *tids = (pthread_t*) malloc(sizeof(pthread_t) * 2);
struct mergeS *merger = (struct mergeS*) malloc(sizeof(struct mergeS) * 2);
int error = 0;
if(level < Max_Level - 1)
{
for(i = 0;i < 2; i ++)
{
printf("for loop\n");
merger[i].numElements = numElements/(i + 1);
merger[i].level = threader->level + 1;
merger[i].Max_Level = threader->Max_Level;
merger[i].A = threader->A;
if((error = pthread_create(&tids[i],NULL,pthread_mergesort,(void*)&merger[i])) == 0)
{
printf("thread failed\n");
flag = 1;
}
}
printf("error: %d\n",error);
}
serial_mergesort(A,low,high);
int j = 0;
if(flag == 0)
{
for(j = 0;j < 2; j++)
{
printf("for level: %d\n",threader->level);
printf("join = %d\n", j);
if((error = pthread_join(tids[j],NULL)) != 0)
{
printf("error: %d\n",error);
}
}
}
merge(A,low,(high/2) + 1,high);
free(merger);
free (tids);
return NULL;
}
/*
* merge(int A[], int p, int q, int r):
*
* description: Merge two sorted sequences A[p..q] and A[q+1..r]
* and place merged output back in array A. Uses extra
* space proportional to A[p..r].
*/
void merge(int A[], int p, int q, int r)
{
int *B = (int *) malloc(sizeof(int) * (r-p+1));
int i = p;
int j = q+1;
int k = 0;
int l;
// as long as both lists have unexamined elements
// this loop keeps executing.
while ((i <= q) && (j <= r)) {
if (A[i] < A[j]) {
B[k] = A[i];
i++;
} else {
B[k] = A[j];
j++;
}
k++;
}
// now only at most one list has unprocessed elements.
if (i <= q) {
// copy remaining elements from the first list
for (l=i; l<=q; l++) {
B[k] = A[l];
k++;
}
} else {
// copy remaining elements from the second list
for (l=j; l<=r; l++) {
B[k] = A[l];
k++;
}
}
// copy merged output from array B back to array A
k=0;
for (l=p; l<=r; l++) {
A[l] = B[k];
k++;
}
free(B);
}
end of file
**mergesortTest.c**
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_THREAD 4
#define TRUE 1
#define FALSE 0
// function prototypes
int check_if_sorted(int A[], int n);
void generate_random_array(int A[], int n, int seed);
void serial_mergesort(int A[], int p, int r);
void *pthread_mergesort(void *arg);
void merge(int A[], int p, int q, int r);
void insertion_sort(int A[], int p, int r);
double getMilliSeconds();
// Struct
struct mergeS
{
int numElements;
int *A;
int level;
int Max_Level;
};
/*
* generate_random_array(int A[], int n, int seed):
*
* description: Generate random integers in the range [0,RANGE]
* and store in A[1..n]
*/
#define RANGE 1000000
void generate_random_array(int A[], int n, int seed)
{
int i;
srandom(seed);
for (i=1; i<=n; i++){
A[i] = random()%RANGE;
}
}
/*
* check_if_sorted(int A[], int n):
*
* description: returns TRUE if A[1..n] are sorted in nondecreasing order
* otherwise returns FALSE
*/
int check_if_sorted(int A[], int n)
{
int i=0;
for (i=1; i<n; i++) {
if (A[i] > A[i+1]) {
printf("%d > %d\n",A[i],A[i+1]);
printf("i: %d\n",i);
return FALSE;
}
}
return TRUE;
}
int main(int argc, char **argv) {
printf("argc = %d\n",argc);
int n;
int Max_Level = 4;
int flag = 1;
int seed;
if (argc == 1) { // there must be at least one command-line argument
printf("Default: Input Size = 100000000 levels: 4\n");
printf("Usage: executable input size number of levels\n");
n = 100000000;
seed = 4;
flag = 0;
}
if (argc == 2 && flag == 1) {
printf("Default: Threads: 4\n");
printf("Usage: executable input size number of levels\n");
n = atoi(argv[1]);
Max_Level = 4;
seed = 4;
}
if(argc == 3)
{
n = atoi(argv[1]);
Max_Level = atoi(argv[2]);
seed = Max_Level;
}
if(Max_Level > 15)
{
printf("To many levels. Setting to 4\n");
Max_Level = 4;
seed = Max_Level;
}
int *A = (int *) malloc(sizeof(int) * (n+1)); // n+1 since we are using A[1]..A[n]
// generate random input
generate_random_array(A,n,seed);
double start_time;
double sorting_time;
// sort the input (and time it)
start_time = getMilliSeconds();
serial_mergesort(A,1,n);
sorting_time = getMilliSeconds() - start_time;
////////////////////////////////////////////////////////////////////////////////////////////////////// Start of parallel //////////////////////////////////////////////////////////////////////////////////////////////////////
int *B = (int *) malloc(sizeof(int) * (n+1)); // n+1 since we are using A[1]..A[n]
//int i;
double p_start_time;
double p_sorting_time;
struct mergeS *threader = (struct mergeS*) malloc(sizeof(struct mergeS));
generate_random_array(B,n,seed);
// sort the input with threads (and time it)
p_start_time = getMilliSeconds();
threader[0].numElements = n;
threader[0].level = 0;
threader[0].Max_Level = Max_Level;
threader[0].A = B;
pthread_mergesort(threader);
printf("sorted\n");
/*for(i = 0;i < n + 1;i = i + 1)
{
printf("B[%d]: %d\n",i,B[i]);
}
printf("B:[%d] = %d\n",999,B[999]);
*/
p_sorting_time = getMilliSeconds() - p_start_time;
// print results if correctly sorted otherwise cry foul and exit
if (check_if_sorted(A,n)) {
printf("Serial: Sorting %d elements took %4.2lf seconds.\n", n, sorting_time/1000.0);
} else {
printf("%s: sorting failed!!!!\n", argv[0]);
exit(EXIT_FAILURE);
}
if (check_if_sorted(B,n)) {
printf("Threaded: Sorting %d elements took %4.2lf seconds.\n", n, p_sorting_time/1000.0);
} else {
printf("%s: parallel sorting failed!!!!\n", argv[0]);
exit(EXIT_FAILURE);
}
free(threader);
free(A);
free(B);
exit(EXIT_SUCCESS);
}
end of file
**GBD error report and code output**
[rutgerluther#onyxnode72 multi-threaded]$ valgrind --leak-check=yes ./mergesort 1000 2
==5636== Memcheck, a memory error detector
==5636== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5636== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5636== Command: ./mergesort 1000 2
==5636==
argc = 3
level: 0
for loop
thread failed
for loop
thread failed
error: 0
sorted
Serial: Sorting 1000 elements took 0.00 seconds.
993090 > 163007
i: 500
./mergesort: parallel sorting failed!!!!
==5636==
==5636== HEAP SUMMARY:
==5636== in use at exit: 9,152 bytes in 5 blocks
==5636== total heap usage: 30 allocs, 25 frees, 33,216 bytes allocated
==5636==
==5636== 1,120 bytes in 2 blocks are possibly lost in loss record 2 of 4
==5636== at 0x4C2B9B5: calloc (vg_replace_malloc.c:711)
==5636== by 0x40128C4: _dl_allocate_tls (in /usr/lib64/ld-2.17.so)
==5636== by 0x4E3E7FB: pthread_create##GLIBC_2.2.5 (in /usr/lib64/libpthread-2.17.so)
==5636== by 0x400E88: pthread_mergesort (mergesort.c:114)
==5636== by 0x400B00: main (mergesortTest.c:145)
==5636==
==5636== LEAK SUMMARY:
==5636== definitely lost: 0 bytes in 0 blocks
==5636== indirectly lost: 0 bytes in 0 blocks
==5636== possibly lost: 1,120 bytes in 2 blocks
==5636== still reachable: 8,032 bytes in 3 blocks
==5636== suppressed: 0 bytes in 0 blocks
==5636== Reachable blocks (those to which a pointer was found) are not shown.
==5636== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==5636==
==5636== For counts of detected and suppressed errors, rerun with: -v
==5636== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
[rutgerluther#onyxnode72 multi-threaded]$ gdb ./mergesort
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-110.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/RutgerLuther/RutgerLuther#u.boisestate.edu/backpack/CS453-1-f18/p2/multi-threaded/mergesort...done.
(gdb) b 130
Breakpoint 1 at 0x400abd: file mergesortTest.c, line 130.
(gdb) r 1000 2
Starting program: /home/RutgerLuther/RutgerLuther#u.boisestate.edu/backpack/CS453-1-f18/p2/multi-threaded/./mergesort 1000 2
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
argc = 3
Breakpoint 1, main (argc=<optimized out>, argv=0x7fffffffcf98) at mergesortTest.c:135
135 struct mergeS *threader = (struct mergeS*) malloc(sizeof(struct mergeS));
Missing separate debuginfos, use: debuginfo-install glibc-2.17-222.el7.x86_64
(gdb) n
137 generate_random_array(B,n,seed);
(gdb)
140 p_start_time = getMilliSeconds();
(gdb)
141 threader[0].numElements = n;
(gdb)
142 threader[0].level = 0;
(gdb)
143 threader[0].Max_Level = Max_Level;
(gdb)
144 threader[0].A = B;
(gdb)
145 pthread_mergesort(threader);
(gdb)
level: 0
for loop
[New Thread 0x7ffff77f1700 (LWP 5892)]
thread failed
for loop
level: 1
for level: 1
join = 0
[New Thread 0x7ffff6ff0700 (LWP 5893)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff77f1700 (LWP 5892)]
0x00007ffff7bc7f01 in pthread_join () from /lib64/libpthread.so.0
(gdb)
end of file
**Valgrind report**
[rutgerluther#onyxnode72 multi-threaded]$ valgrind --leak-check=yes ./mergesort 1000 2
==5636== Memcheck, a memory error detector
==5636== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5636== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5636== Command: ./mergesort 1000 2
==5636==
argc = 3
level: 0
for loop
thread failed
for loop
thread failed
error: 0
sorted
Serial: Sorting 1000 elements took 0.00 seconds.
993090 > 163007
i: 500
./mergesort: parallel sorting failed!!!!
==5636==
==5636== HEAP SUMMARY:
==5636== in use at exit: 9,152 bytes in 5 blocks
==5636== total heap usage: 30 allocs, 25 frees, 33,216 bytes allocated
==5636==
==5636== 1,120 bytes in 2 blocks are possibly lost in loss record 2 of 4
==5636== at 0x4C2B9B5: calloc (vg_replace_malloc.c:711)
==5636== by 0x40128C4: _dl_allocate_tls (in /usr/lib64/ld-2.17.so)
==5636== by 0x4E3E7FB: pthread_create##GLIBC_2.2.5 (in /usr/lib64/libpthread-2.17.so)
==5636== by 0x400E88: pthread_mergesort (mergesort.c:114)
==5636== by 0x400B00: main (mergesortTest.c:145)
==5636==
==5636== LEAK SUMMARY:
==5636== definitely lost: 0 bytes in 0 blocks
==5636== indirectly lost: 0 bytes in 0 blocks
==5636== possibly lost: 1,120 bytes in 2 blocks
==5636== still reachable: 8,032 bytes in 3 blocks
==5636== suppressed: 0 bytes in 0 blocks
==5636== Reachable blocks (those to which a pointer was found) are not shown.
==5636== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==5636==
==5636== For counts of detected and suppressed errors, rerun with: -v
==5636== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
[rutgerluther#onyxnode72 multi-threaded]$
end of file
Im running this giving it only a 1000 elements and only using 2 threads. Though the issue still happens with any threads more than 1.
Ive read the man pages and looked at other exmaples and previous cases where i used this and class mates did. But i still cant figure it out.
Any help is appreciated.
If changed some things and pthread is creating correctly. This is stepping into the function. I dont know what the value of tids[0] should be. But the elements in the array are random numbers.
**mergesort.c function call on tids**
level: 1
116 if((error = pthread_create(&tids[i],NULL,pthread_mergesort,(void*)&merger[i])) != 0)
(gdb) info tids
Undefined info command: "tids". Try "help info".
(gdb) print tids[0]
$2 = 140737345689344
(gdb) print &tids
Address requested for identifier "tids" which is in register $r14
(gdb) print *tids
$3 = 140737345689344
(gdb) n
thread failed
for level: 1
join = 0
117 {
(gdb) print tids
$4 = (pthread_t *) 0x604f90
(gdb) print tids[0]
$5 = 140737345689344
(gdb)
The tids array contains uninitialized data if the branch if(level < Max_Level - 1) is not taken. You need to call pthread_join only if you called pthread_create successfully.