I am filling in code for a Cache simulator in C. How it work is you are given an input file with commands, you are to trace the results of that input simulating cache functions so that we can keep track of cache hits and misses. I have written the following code but seem to be having trouble with my ReplayTrace method. The line "accessData(addr)" throws a "segmentation fault (core dump)." I am aware that means I am trying to access something that I do not have permission to access or is no longer existing or is out of range. I have no idea how else to call this function. I am posting my whole code because I don't want to make assumptions about where the problem may lie. Can anyone tell where I am making a mistake?
/* TODO - COMPLETE THIS FUNCTION
* accessData - Access data at memory address addr.
* If it is already in cache, increase hit_count
* If it is not in cache, bring it in cache, increase miss count.
* Also increase eviction_count if a line is evicted.
*
* You will manipulate data structures allocated in initCache() here
* Implement Least-Recently-Used (LRU) cache replacement policy
*/
void accessData(mem_addr_t addr)
{
int i;
//pulling out the set and tag bits of address
mem_addr_t set = (addr >> b) & set_bits;
mem_addr_t tag = addr >> (s + b);
cache_set_t cache_set = cache[set];
/* judge if hit */
for (i = 0; i < E; ++i)
{
/* hit */
if (cache_set[i].valid && cache_set[i].tag == tag)
{
if (verbosity)
printf("hit ");
++hit_count;
/* update entry whose lru is less than the current lru (newer) */
for (int j = 0; j < E; ++j)
if (cache_set[j].valid && cache_set[j].lru < cache_set[i].lru)
++cache_set[j].lru;
cache_set[i].lru = 0;
return;
}
}
/* missed */
if (verbosity)
printf("miss ");
++miss_count;
/* find the biggest lru or the first invlaid line */
int j, maxIndex = 0;
unsigned long long maxLru = 0;
for (j = 0; j < E && cache_set[j].valid; ++j)
{
if (cache_set[j].lru >= maxLru)
{
maxLru = cache_set[j].lru;
maxIndex = j;
}
}
if (j != E)
{
/* found an invalid entry */
/* update other entries */
for (int k = 0; k < E; ++k)
if (cache_set[k].valid)
++cache_set[k].lru;
/* insert line */
cache_set[j].lru = 0;
cache_set[j].valid = 1;
cache_set[j].tag = tag;
}
else
{
/* all entry is valid, replace the oldest one*/
if (verbosity)
printf("eviction ");
++eviction_count;
for (int k = 0; k < E; ++k)
++cache_set[k].lru;
cache_set[maxIndex].lru = 0;
cache_set[maxIndex].tag = tag;
}
}
/* TODO - FILL IN THE MISSING CODE
* replayTrace - replays the given trace file against the cache
* reads the input trace file line by line
* extracts the type of each memory access : L/S/M
* YOU MUST TRANSLATE one "L" as a load i.e. 1 memory access
* YOU MUST TRANSLATE one "S" as a store i.e. 1 memory access
* YOU MUST TRANSLATE one "M" as a load followed by a store i.e. 2 memory accesses
* Ignore instruction fetch "I"
*/
void replayTrace(char* trace_fn)
{
char buf[1000];
mem_addr_t addr=0;
unsigned int len=0;
FILE* trace_fp = fopen(trace_fn, "r");
int count = 0;
if(!trace_fp){
fprintf(stderr, "%s: %s\n", trace_fn, strerror(errno));
exit(1);
}
while( fgets(buf, 1000, trace_fp) != NULL) {
if(buf[1]=='S' || buf[1]=='L' || buf[1]=='M') {
sscanf(buf+3, "%llx,%u", &addr, &len);
if(verbosity)
printf("%c %llx,%u ", buf[1], addr, len);
// TODO - MISSING CODE
// now you have:
// 1. address accessed in variable - addr
// 2. type of acccess(S/L/M) in variable - buf[1]
// call accessData function here depending on type of access
switch (buf[1])
{
case 'L':
case 'S':
accessData(addr);
++count;
break;
case 'M':
accessData(addr);
accessData(addr);
++count;
break;
default:
break;
}
if (verbosity)
printf("\n");
}
}
fclose(trace_fp);
}
--edit---
Valgrind output:
Command: ./csim -t traces/dave.trace -s 8 -E 4 -b 12
==4155737==
==4155737== Invalid read of size 8
==4155737== at 0x1095B2: accessData (csim.c:144)
==4155737== by 0x109AE3: replayTrace (csim.c:259)
==4155737== by 0x109DC6: main (csim.c:342)
==4155737== Address 0x4b9c040 is 0 bytes after a block of size 0 alloc'd
==4155737== at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4155737== by 0x10938A: initCache (csim.c:99)
==4155737== by 0x109DB7: main (csim.c:336)
==4155737==
==4155737== Invalid read of size 1
==4155737== at 0x1095E2: accessData (csim.c:150)
==4155737== by 0x109AE3: replayTrace (csim.c:259)
==4155737== by 0x109DC6: main (csim.c:342)
==4155737== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==4155737==
==4155737==
==4155737== Process terminating with default action of signal 11 (SIGSEGV)
==4155737== Access not within mapped region at address 0x0
==4155737== at 0x1095E2: accessData (csim.c:150)
==4155737== by 0x109AE3: replayTrace (csim.c:259)
==4155737== by 0x109DC6: main (csim.c:342)
==4155737== If you believe this happened as a result of a stack
==4155737== overflow in your program's main thread (unlikely but
==4155737== possible), you can try to increase the size of the
==4155737== main thread stack using the --main-stacksize= flag.
==4155737== The main thread stack size used in this run was 8388608.
==4155737==
==4155737== HEAP SUMMARY:
==4155737== in use at exit: 472 bytes in 2 blocks
==4155737== total heap usage: 3 allocs, 1 frees, 4,568 bytes allocated
==4155737==
==4155737== LEAK SUMMARY:
==4155737== definitely lost: 0 bytes in 0 blocks
==4155737== indirectly lost: 0 bytes in 0 blocks
==4155737== possibly lost: 0 bytes in 0 blocks
==4155737== still reachable: 472 bytes in 2 blocks
==4155737== suppressed: 0 bytes in 0 blocks
==4155737== Rerun with --leak-check=full to see details of leaked memory
==4155737==
==4155737== For lists of detected and suppressed errors, rerun with: -s
==4155737== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)```
Related
I am working on a function which allocates memory into an array, and then I free it later. Oddly enough, valgrind is giving me this error:
==93== HEAP SUMMARY:
==93== in use at exit: 11,160 bytes in 2,232 blocks
==93== total heap usage: 44,310 allocs, 42,078 frees, 1,632,230 bytes allocated
==93==
==93== 11,160 bytes in 2,232 blocks are definitely lost in loss record 1 of 1
==93== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==93== by 0x10976F: FillHashMap (in /mnt/c/Users/Jordan/Documents/GitHub/flwg/flwp)
==93== by 0x1092F1: main (in /mnt/c/Users/Jordan/Documents/GitHub/flwg/flwp)
==93==
==93== LEAK SUMMARY:
==93== definitely lost: 11,160 bytes in 2,232 blocks
==93== indirectly lost: 0 bytes in 0 blocks
==93== possibly lost: 0 bytes in 0 blocks
==93== still reachable: 0 bytes in 0 blocks
==93== suppressed: 0 bytes in 0 blocks
==93==
==93== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Dr. Memory is giving me a similar error:
Error #1: UNADDRESSABLE ACCESS: reading 0x0000000000000000-0x0000000000000008 8 byte(s)
# 0 testing [C:/Users/Jordan/Documents/GitHub/flwg/FLWP-2.c:120]
# 1 main [C:/Users/Jordan/Documents/GitHub/flwg/FLWP-2.c:105]
Note: #0:00:01.195 in thread 14704
Note: instruction: mov (%rax) -> %rax
The strcmp line of code is what causes it to break with Dr. Memory, although valgrind says I have issues even if I don't call this particular method.
void testing(struct wordConnections *header){
header = header->nextRow;
while(strcmp(header->word, "berk") != 0){
header = header->nextRow;
if(header == NULL){
printf("Failed");
return;
}
}
}
The code that runs is (the value and significance of numLetters + 1 is it is the length of the char* stored in the wordStorage, the value of numLetters is 4):
char** FillHashMap(struct wordConnections **(*HashMap)){
int h = 0;
/* The Amount of words in each file, File 1, 2, 3 */
int totalWordQuantity[3] = {132, 7420, 19829};
/*the word that we test, we add by two because first 4: word, 5th: \n, 6th: \0*/
char word[numLetters + 1];
/*how many times we've changed the character*/
int letterSpot = 0;
/*the character that goes through the file*/
char c;
FILE *flwd = OpenFile();
/* is it the first word of the line */
int wordCount = 0;
int isFirst = 1;
char p = fgetc(flwd);
c = p;
/* So, this is a temporary word, who will store the row, so all of its category folks will be contained within it */
char* rowWord = malloc(sizeof(char) * (numLetters + 1));
/*This stores all of the words*/
char** wordStorage = (char**)calloc(totalWordQuantity[numLetters - 2], sizeof(char*) * (numLetters + 1));
int i = 0;
/* First, take the character */
while((c = p) != EOF){
p = fgetc(flwd);
/* Add the character to the word */
word[letterSpot] = c;
/* Allows the letter spot to find the next place into the word */
letterSpot++;
/* Determines if the character is the placement immediately after the word */
if((c == ' ' && p != '\n') || c == '\n'){
letterSpot = 0;
/* Throws in the \0, converting into a string */
word[numLetters] = '\0';
wordStorage[wordCount] = malloc(sizeof(char) * (numLetters + 1));
h++;
strcpy(wordStorage[wordCount], word);
/* Determine if it's the first word */
if(isFirst == 1){
strcpy(rowWord, word);
/* Throw it in as a row */
AddRow2DLL(wordStorage[wordCount],
HashMap[FirstHashFunction(word[0])/*First Letter*/]
[SecondHashFunction(word)]/*First Vowel*/);
}
/* If it's not the first word */
else {
AddColumn2DLL(wordStorage[wordCount],
HashMap[FirstHashFunction(rowWord[0])/*First Letter*/]
[SecondHashFunction(rowWord)]/*First Vowel*/);
}
if(c == ' '){
isFirst = 0;
}
if(c == '\n'){
isFirst = 1;
}
wordCount++;
}
c = p;
}
free(rowWord);
fclose(flwd);
return wordStorage;
}
The hash map works fine, this is the method that causes the issues, without it, there are no memory leaks.
Later in the code, I free the wordStorage array with this method:
void FreeWordStorage(char** wordStorage){
int f = 0;
/* The Amount of words in each file, File 1, 2, 3 */
int totalWordQuantity[3] = {132, 7420, 19829};
int i;
for(i = 0; i < totalWordQuantity[numLetters - 2]; i++){
free(wordStorage[i]);
f++;
}
free(wordStorage);
}
I've tried all sorts of things to fix it. Oddly enough, when I check it with integers, I'm allocating and freeing the same amount of data.
Any help would be greatly appreciated. Thank you!
Valgrind's analysis indicates that the leaked memory was allocated by a bunch of malloc() calls by function FillHashMap(), and the only plausible candidate for those is this:
wordStorage[wordCount] = malloc(sizeof(char) * (numLetters + 1));
Function FreeWordStorage() appears to be correct for freeing the data allocated by FillHashMap(), so if some allocations are going unfreed then there are two main possibilities:
The pointer value returned by FillHashMap() is not later passed to FreeWordStorage(). The latter function might not be called at all on the code path that is being exercised, or perhaps a modified or outright wrong pointer is being passed to it.
Or,
Some or all of the pointers recorded in the allocated block returned by FillHashMap() are modified after being recorded, so that when it is called, FreeWordStorage() is ineffective at freeing the allocated memory.
Either one of those could be consistent with Dr. Memory's diagnostic, but whichever scenario applies, it does not appear to play out in the code presented in the question. I am reasonably confident that your pointers are being mangled somewhere else in the program.
I have written a small implementation of a simple stack in C using a linked list. The application works after a bit of fussing with gdb and valgrind. However, I have noticed that valgrind reports a number of "still reachable" leaks at termination of the program.
After some googling, I have found that these type of leaks are not an issue and that I generally shouldn't worry about them. Well that's great news! The only thing is, I would REALLY like to understand why valgrind sees these leaks and where they appear. I went to great pains through my first pass at this application to diligently release any allocated memory. What did I miss? Where are these allocations that valgrind sees but I cannot?
I have been staring at this for awhile now, and despite fiddling with the code this way and that, have come up empty handed. Hopefully you all can help me in this endeavor.
I have stripped the app down to a minimal example that will present the leak I am observing. It just initializes the stack and then immediately destroys it and exits.
// simple stack implementation
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
/*--- data structure in a stack item ---*/
struct data {
char * message;
};
/*--- stack item structure ---*/
struct item {
struct data * my_data;
struct item * next;
};
/*--- stack data structure ---*/
struct stack {
int initialized;
int empty;
struct item * head;
};
struct stack * my_stack;
/*--- create a new stack data structure with provided initial data ---*/
int
create_stack(struct data ** initial_items, int num_items) {
//allocate memory for the stack structure itself
my_stack = (struct stack *) malloc(sizeof(struct stack));
if(!my_stack) return -1;
my_stack->empty = 1;
my_stack ->initialized = 0;
if(num_items) {
//allocate memory for the head of the list first
my_stack->head = (struct item *) malloc(sizeof(struct item));
if(!my_stack->head) return -1;
my_stack->head->my_data = initial_items[0];
my_stack->head->next = NULL;
struct item * tracker = my_stack->head;
//fill the stack with elements containing the provided data
int i = 1;
for(; i < (num_items); i++) {
tracker->next = (struct item *) malloc(sizeof(struct item));
tracker = tracker->next;
if(!tracker) return -1;
tracker->my_data = initial_items[i];
tracker->next = NULL;
}
//no longer empty
my_stack->empty = 0;
}
//set initialized flag & return
my_stack->initialized = 1;
return 0;
}
/*--- destroy the stack by recursively freeing nodes ---*/
int
destroy_stack(struct item * recurse) {
//if the starting node is valid, begin
if(recurse) {
//if the current node links to another
if(recurse->next)
//recurse on the next node
destroy_stack(recurse->next);
else
//otherwise we hit the end, free the node
free(recurse);
}
//the starting node is invalid, just free the stack itself
else {
free(my_stack);
}
return 0;
}
/*--- test wrapper ---*/
int
main(int argc, char **argv) {
//initialize 10 element list of data structures to fill the stack items with
int i = 0;
int length = 10;
struct data ** initial_values = (struct data **) malloc(length*sizeof(struct data *));
//set each data element's value to i
for(; i < length; i++) {
char temp[16];
sprintf(temp, "%d", i);
initial_values[i] = (struct data *) malloc(sizeof(struct data));
initial_values[i]->message = strdup(temp);
}
//simple test case
//create a stack with the generated initial data, then destroy it
assert( !create_stack(initial_values, length) );
assert( !destroy_stack(my_stack->head) );
//free the string data our stack nodes were pointing to
i = 0;
while(i < length) {
free(initial_values[i]->message);
free(initial_values[i]);
i += 1;
}
free(initial_values);
return 0;
}
Running this through valgrind produces the following identified, unreleased blocks:
(trusty)kin3tix#localhost:~/C Practice/Data Structures$ valgrind --leak-check=full --show-leak-kinds=all ./stack_leak_test
==19340== Memcheck, a memory error detector
==19340== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==19340== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==19340== Command: ./stack_leak_test
==19340==
==19340==
==19340== HEAP SUMMARY:
==19340== in use at exit: 168 bytes in 10 blocks
==19340== total heap usage: 32 allocs, 22 frees, 364 bytes allocated
==19340==
==19340== 16 bytes in 1 blocks are still reachable in loss record 1 of 3
==19340== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==19340== by 0x400739: create_stack (stack_leak_test.c:40)
==19340== by 0x40093B: main (stack_leak_test.c:95)
==19340==
==19340== 24 bytes in 1 blocks are still reachable in loss record 2 of 3
==19340== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==19340== by 0x4006E6: create_stack (stack_leak_test.c:33)
==19340== by 0x40093B: main (stack_leak_test.c:95)
==19340==
==19340== 128 bytes in 8 blocks are still reachable in loss record 3 of 3
==19340== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==19340== by 0x4007A1: create_stack (stack_leak_test.c:48)
==19340== by 0x40093B: main (stack_leak_test.c:95)
==19340==
==19340== LEAK SUMMARY:
==19340== definitely lost: 0 bytes in 0 blocks
==19340== indirectly lost: 0 bytes in 0 blocks
==19340== possibly lost: 0 bytes in 0 blocks
==19340== still reachable: 168 bytes in 10 blocks
==19340== suppressed: 0 bytes in 0 blocks
==19340==
==19340== For counts of detected and suppressed errors, rerun with: -v
==19340== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
They all seem to stem from "create_stack" but as far as I can tell my destroy function should be catching everything I allocate. What am I missing here?
Your destruction logic is trying to recursively combine two tasks (deleting the stack object and its items) in a single function. Worse, the else state shouldn't be there at all. You already determined you're sitting on a dynamic node (recurse). It needs to be deleted. Whether it has a next or not is not for the current depth to decide; that will be taken care of in the next depth of recursion.
Honestly, this is much simpler if you create a helper to wipe out the linked list, and as separate wrapper to do said-same to the stack itself:
/*--- destroy linked list nodes recursively ---*/
static void destroy_stack_items(struct item *item)
{
if (item)
{
destroy_stack_items(item->next);
free(item);
}
}
/*--- destroy the stack by recursively freeing nodes ---*/
int destroy_stack(struct stack *s)
{
if (s)
{
destroy_stack_items(s->head);
free(s);
}
return 0
}
and simply invoked as:
destroy_stack(my_stack);
Personally I would do it iteratively (thus remove the helper in the process), but I'm sure you have your reasons for otherwise. For example:
/*--- destroy the stack by iteratively freeing nodes ---*/
int destroy_stack(struct stack *s)
{
if (s)
{
while (s->head)
{
struct item *tmp = s->head;
s->head = tmp->next;
free(tmp);
}
free(s);
}
return 0
}
Best of luck.
I have made a minimal-working example of how to add elements to an array with realloc. This will be expanded in a future program that has many more elements.
#include <stdio.h>//printf
#include <stdlib.h>//malloc, realloc
int main() {
//BEGIN REALLOCATE-ABLE ARRAY
unsigned int *array, loop_variable;
const unsigned int ORIGINAL_ARRAY_SIZE = 4, REALLOC_INDICES = 99;
array = malloc(ORIGINAL_ARRAY_SIZE*sizeof(unsigned int));
for (loop_variable = 0; loop_variable < ORIGINAL_ARRAY_SIZE; loop_variable++) {
array[loop_variable] = loop_variable;
}
//BEGIN REALLOCATION
for (loop_variable = 1; loop_variable < REALLOC_INDICES; loop_variable++) {
array = realloc(array,sizeof(unsigned int)*(ORIGINAL_ARRAY_SIZE+loop_variable));
array[ORIGINAL_ARRAY_SIZE+loop_variable-1] = 2*(ORIGINAL_ARRAY_SIZE+loop_variable-1);
printf("reallocate array[%d] = %d\n",ORIGINAL_ARRAY_SIZE+loop_variable-1,array[ORIGINAL_ARRAY_SIZE+loop_variable-1]);
}
//BEGIN PRINTING ARRAY VALUES
for (loop_variable = 0; loop_variable < ORIGINAL_ARRAY_SIZE+REALLOC_INDICES-1; loop_variable++) {
printf("array[%d] = %d\n",loop_variable,array[loop_variable]);
}
//BEGIN FREE ARRAY
free(array); array = NULL;
return 0;
}
This should compile on any computer with gcc or clang. I then run this program on valgrind to ensure there are no memory leaks, and I get this:
==10791== HEAP SUMMARY:
==10791== in use at exit: 0 bytes in 0 blocks
==10791== total heap usage: 99 allocs, 99 frees, 20,988 bytes allocated
==10791==
==10791== All heap blocks were freed -- no leaks are possible
==10791==
==10791== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==10791== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
However, what troubles me is that I'm using 20,988 bytes for a 101-element array. The memory use grows exponentially as the array gets bigger, instead of linearly by 4 bytes/element.
If I'm understanding Valgrind's output correctly, this array should have 4*101 elements = 404 bytes memory size, but appears to use about 50 times as much memory as it should. This is a trivial problem for such a small program, but more meaningful programs will run out of memory on this computer.
My question: is this array really using 20,988 bytes, or is Valgrind double-counting the memory?
Is there a more memory-efficient way to do this? I can't understand other examples of realloc, though I have tried to follow them as closely as I can and make this question relevant to as many users as possible.
==10791== in use at exit: 0 bytes in 0 blocks
==10791== total heap usage: 99 allocs, 99 frees, 20,988 bytes allocated
is this array really using 20,988 bytes
No, it's using 0 bytes.
“allocated” obviously means “ever allocated”, including bytes that have been freed, since the amount of memory “still allocated” is zero (and another line tells you that).
The answer, thanks to user Pascal Cuoq, is that Valgrind will sum the memory allocations for every allocation. This is why I was confused, and thought that realloc was using too much memory.
I thought that if you want to find the size of the array, you can comment out the line that says
free(array); array = NULL;
to intentionally introduce a memory bug, and Valgrind will output
==11699== LEAK SUMMARY:
==11699== definitely lost: 408 bytes in 1 blocks
==11699== indirectly lost: 0 bytes in 0 blocks
==11699== possibly lost: 0 bytes in 0 blocks
==11699== still reachable: 0 bytes in 0 blocks
==11699== suppressed: 0 bytes in 0 blocks
==11699==
==11699== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
==11699== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
which gives you the true size of the array at its last iteration. There is probably a better way to do this, but my point is made.
I added improvements suggested by other users here. I had a very difficult time finding good, minimal working examples of realloc on search engines, and for future use of anyone finding this on a search engine, this is very basic minimal working example of a good, but probably not best, how to use realloc in C:
#include <stdio.h>//include printf function
#include <stdlib.h>//include malloc, realloc functions
int main() {
/*BEGIN REALLOCATE-ABLE ARRAY*/
unsigned int *array, loop_variable;
const unsigned int ORIGINAL_ARRAY_SIZE = 4, REALLOC_INDICES = 99999;
array = malloc(ORIGINAL_ARRAY_SIZE*sizeof(unsigned int));
for (loop_variable = 0; loop_variable < ORIGINAL_ARRAY_SIZE; loop_variable++) {
array[loop_variable] = loop_variable;
}
/*BEGIN REALLOCATION*/
for (loop_variable = 1; loop_variable < REALLOC_INDICES; loop_variable++) {
array = realloc(array,sizeof(unsigned int)*(ORIGINAL_ARRAY_SIZE+loop_variable));
if (array == NULL) {
printf("Array variable %d failed to reallocate :,-(\n",loop_variable);
exit(EXIT_FAILURE);
}
array[ORIGINAL_ARRAY_SIZE+loop_variable-1] = 2*(ORIGINAL_ARRAY_SIZE+loop_variable-1);
printf("reallocate array[%d] = %d\n",ORIGINAL_ARRAY_SIZE+loop_variable-1,array[ORIGINAL_ARRAY_SIZE+loop_variable-1]);
}
/*BEGIN PRINTING ARRAY VALUES*/
for (loop_variable = 0; loop_variable < ORIGINAL_ARRAY_SIZE+REALLOC_INDICES-1; loop_variable++) {
printf("array[%d] = %d\n",loop_variable,array[loop_variable]);
}
/*BEGIN FREE ARRAY*/
free(array); array = NULL;
return 0;
}
I'm trying to write a program that uses some basic threading for an assignment. Below are the relevant snippets that I think are causing the problem.
The program runs fine with 25 or less threads but usually results in a segfault when 26 or more are used. This led me to think that my malloc statement were incorrect. Can anyone nudge me in the right direction? If you need more code to be posted, I'd be happy to provide it.
Also, these problems only come up when I run the program on my school's student machines. It appears to work fine my local machine. Might anyone know why?
Thanks for your time!
...
struct thread_args {
struct bitmap *bm;
double xmin;
double xmax;
double ymin;
double ymax;
int max;
int start;
int end;
};
...
int num_threads; //Given by user input
struct bitmap *bm = bitmap_create(500, 500); //All threads share the same bitmap
int i;
pthread_t *thread_id = malloc(num_threads * sizeof(*thread_id));
struct thread_args *args = malloc(num_threads * sizeof(*args));
for (i = 0; i < num_threads; i++) {
args[i].bm = bm;
args[i].xmin = xcenter-scale;
args[i].xmax = xcenter+scale;
args[i].ymin = ycenter-scale;
args[i].ymax = ycenter+scale;
args[i].max = max;
args[i].start = bitmap_height(bm) * i / num_threads;
args[i].end = bitmap_height(bm) * (i + 1) / num_threads;
pthread_create(&thread_id[i], NULL, compute_image, &args[i]);
}
for (i = 0; i < num_threads; i++) {
pthread_join(thread_id[i], NULL);
}
...
void* compute_image(void *arg)
{
struct thread_args* args = (struct thread_args*) arg;
int i,j;
int width = bitmap_width(args->bm);
int height = bitmap_height(args->bm);
// For every pixel in the image...
for(j=args->start;j<args->end;j++) {
for(i=0;i<width;i++) {
// Determine the point in x,y space for that pixel.
double x = args->xmin + i*(args->xmax-args->xmin)/width;
double y = args->ymin + j*(args->ymax-args->ymin)/height;
// Compute the iterations at that point.
int iters = iterations_at_point(x,y,args->max);
// Set the pixel in the bitmap.
bitmap_set(args->bm,i,j,iters);
}
}
return 0;
}
...
valgrind log
==24919==
==24919== HEAP SUMMARY:
==24919== in use at exit: 1,000,000 bytes in 1 blocks
==24919== total heap usage: 56 allocs, 55 frees, 1,018,884 bytes allocated
==24919==
==24919== Searching for pointers to 1 not-freed blocks
==24919== Checked 87,112 bytes
==24919==
==24919== 1,000,000 bytes in 1 blocks are definitely lost in loss record 1 of 1
==24919== at 0x4A069EE: malloc (vg_replace_malloc.c:270)
==24919== by 0x401256: bitmap_create (bitmap.c:21)
==24919== by 0x400CEC: main (mandel.c:103)
==24919==
==24919== LEAK SUMMARY:
==24919== definitely lost: 1,000,000 bytes in 1 blocks
==24919== indirectly lost: 0 bytes in 0 blocks
==24919== possibly lost: 0 bytes in 0 blocks
==24919== still reachable: 0 bytes in 0 blocks
==24919== suppressed: 0 bytes in 0 blocks
==24919==
==24919== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)
--24919--
--24919-- used_suppression: 4 U1004-ARM-_dl_relocate_object
--24919-- used_suppression: 2 glibc-2.5.x-on-SUSE-10.2-(PPC)-2a
==24919==
==24919== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)
Edit: Added compute_image code and valgrind log although the log is missing the error messages it was showing earlier today. The 1,000,000 bytes lost is something I know about.
Make sure that pthread_create is not returning an error. The machine has a global limit on the number of threads that can be spawned, and is probably fluctuating close to that limit. If you fail to spawn a thread, you will have a garbage pthread_t, which will likely cause pthread_join to blow up.
I have implemented my own version of strcat function.
It works fine but valgrind complains.
main()
{
char *src=NULL;
src=(char *) malloc(sizeof(char)*8);
strcpy(src,"sandeep");
xstrcat(src,"pathak");
printf("******FINAL STR IS : %s ********",src);
free(src);
src=NULL;
}
void xstrcat(char *src,const char *dest)
{
int dlen=strlen(dest);
int slen=strlen(src);
int j=0;
int i=0;
char *temp=(char *) realloc(src,(slen+dlen+1)*sizeof(char));
for(j=slen;i<dlen;i++,j++)
{
temp[j]=dest[i];
}
temp[j]='\0';
printf("%s",temp);
}
VALGRIND ERROR :
==31775== Invalid read of size 4
==31775== Invalid read of size 4
==31775== Invalid read of size 1
==31775== Invalid read of size 1
==31775== 14 bytes in 1 blocks are definitely lost in loss record 1 of 1
==31775== at 0x1B9053EE: realloc (vg_replace_malloc.c:197)
==31775== by 0x8048606: xstrcat (in /user/gur27268/Computer_Systems/Socket/DevTest/UTI
==31775== by 0x804850F: main (in /user/gur27268/Computer_Systems/Socket/DevTest/UTIL/a
==31775==
==31775== LEAK SUMMARY:
==31775== definitely lost: 14 bytes in 1 blocks.
==31775== possibly lost: 0 bytes in 0 blocks.
==31775== still reachable: 0 bytes in 0 blocks.
==31775== suppressed: 0 bytes in 0 blocks.
==31775== Reachable blocks (those to which a pointer was found) are not shown.**
==31775== To see them, rerun with: --show-reachable=yes
I have freed src, but using realloc tends to this problem...
Any help would be appreciated..
void xstrcat(char *src,const char *dest) {
You're passing src by value, and xstrcat is working on and modifying its local copy. Any changes you make to src will not be reflected in the calling function.
void xstrcat(char **src,const char *dest) {
// Work with *src
}
...
xstrcat(&src, ...)
This approach lets xstrcat modify main's src variable.
To quote a frequently mentioned sample:
void foo (int x) {
x = 2;
}
void bar (int * x) {
*x = 2;
}
int main() {
foo(9); // foo cannot modify the literal 9
int i = 1;
foo(i); // foo cannot modify the variable i
bar(&9); // This isn't legal - it can't be
bar(&i); // bar modifies i
}