I tested this program under Visual Studio 2010, 2008 and Codeblock 10.2 (gcc 4.x.x), it worked perfectly. However, when I connect to my school compiler, they use gcc 3.3.4, it crashed, and the result 开发者_开发知识库was Memory fault
(coredump), and I have no idea why? I wonder is gcc 3.3.4 bug? Or something was wrong? Any idea?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const int MEM_SIZE = 65536;
/* Cache definition */
struct _tag_cache {
int tag;
int *block;
};
typedef struct _tag_cache cache;
/* Function Prototype */
void set_params( int* , int* , int* );
void program();
void display_options();
int get_val_with_mess( const char* );
int *init_main_mem_of( int );
cache *init_cache_of( int );
void free_cache( cache** , int );
void write_cache( int* , cache* , int , int , int );
void read_cache( int* , cache* , int , int , int );
void show_content( int* , int );
/* Main Program */
int main() {
program();
printf( "\nGoodbye!\n" );
return 0;
}
/* Function Implementations */
void set_params( int *main_mem_size, int *cache_size, int *block_size ) {
*main_mem_size = get_val_with_mess( "Enter main memory size (words): " );
*cache_size = get_val_with_mess( "Enter cache size (words): " );
*block_size = get_val_with_mess( "Enter block size (words/block): " );
}
void program() {
int user_option = 0;
int main_mem_size = 65536;
int cache_size = 1024;
int block_size = 16;
int tags = main_mem_size / cache_size;
int *main_mem_ptr = NULL;
cache *cache_ptr = NULL;
// initialize memory
main_mem_ptr = init_main_mem_of( main_mem_size );
cache_ptr = init_cache_of( cache_size );
do {
// display menu
display_options();
// get user input
user_option = get_val_with_mess( "\nEnter selection: " );
switch( user_option ) {
case 1:
// if user set new parameters, free old memory
free_cache( &cache_ptr, tags );
free( main_mem_ptr );
// get new sizes
set_params( &main_mem_size, &cache_size, &block_size );
// calculate number of tags
tags = main_mem_size / cache_size;
// initialize new memory
main_mem_ptr = init_main_mem_of( main_mem_size );
cache_ptr = init_cache_of( cache_size );
break;
case 2:
read_cache( main_mem_ptr, cache_ptr, main_mem_size, block_size, cache_size );
break;
case 3:
write_cache( main_mem_ptr, cache_ptr, main_mem_size, block_size, cache_size );
break;
case 4:
break;
default:
printf( "Invalid options. Try again!\n" );
break;
}
}
while( user_option != 4 );
// free cache
if( cache_ptr != NULL ) {
free_cache( &cache_ptr, tags );
}
// free memory
if( main_mem_ptr != NULL ) {
//printf( "\nFreeing main memory.\n" );
free( main_mem_ptr );
}
}
void display_options() {
printf( "\nMain memory to cache memory mapping: \n" );
printf( "------------------------------------ \n" );
printf( "1) Set parameters \n" );
printf( "2) Read cache \n" );
printf( "3) Write to cache \n" );
printf( "4) Exit \n" );
}
int get_val_with_mess( const char *user_message ) {
int var;
printf( user_message );
scanf( "%d", &var );
return var;
}
int* init_main_mem_of( int size ) {
int i = 0;
int* p = ( int* )malloc( size * sizeof( int ) );
for( ; i < size; ++i )
*( p + i ) = size - i;
return p;
}
cache* init_cache_of( int tags ) {
int i = 0;
// one cache has 64 blocks
// one block has 16 words
cache* p = ( cache* )malloc( tags * sizeof( cache ) );
for( ; i < tags; ++i ) {
p[i].tag = -1;
p[i].block = NULL;
}
return p;
}
void free_cache( cache **p, int size ) {
int i = 0;
for( ; i < size; ++i ) {
// if that block is not NULL, free it
if( ( *p )[i].block != NULL ) {
//printf( "\nFreeing block of tag %d.", i );
free( ( *p )[i].block );
}
}
// free cache
//printf( "\nFreeing cache.\n" );
free( *p );
}
void write_cache( int* main_mem_ptr, cache* cache_ptr, int mm_size, int block_size, int cache_size ) {
int addr = 0;
int value = 0;
int tag;
int block;
int word;
int i;
int base_offset;
int already_missed = 0;
addr = get_val_with_mess( "Enter main memory address to write to: " );
value = get_val_with_mess( "Enter value to write: " );
base_offset = ( addr / block_size ) * block_size;
tag = addr / cache_size;
word = addr % block_size;
block = ( addr % cache_size ) / block_size;
// assign new value
main_mem_ptr[addr] = value;
// if tag doesn't match
if( cache_ptr[block].tag != tag ) {
printf( "Write miss!\n" );
already_missed = 1;
cache_ptr[block].tag = tag;
}
// if cache block memory is NULL
if( cache_ptr[block].block == NULL ) {
if( already_missed == 0 )
printf( "Write miss!\n" );
// allocate block
cache_ptr[block].block = ( int* )malloc( block_size * sizeof( int ) );
}
// transfer from main memory to cache
for( i = 0; i < block_size; ++i ) {
cache_ptr[block].block[i] = main_mem_ptr[base_offset + i];
}
printf( "Word %d of block %d with tag %d contains %d\n", word, block, tag, cache_ptr[block].block[word] );
}
void read_cache( int* main_mem_ptr, cache* cache_ptr, int mm_size, int block_size, int cache_size ) {
int addr = 0;
int value = 0;
int tag;
int block;
int word;
int i;
int base_offset;
int already_missed = 0;
addr = get_val_with_mess( "Enter main memory address to read from: " );
base_offset = ( addr / block_size ) * block_size;
tag = addr / cache_size;
word = addr % block_size;
block = ( addr % cache_size ) / block_size;
// if tag doesn't match
if( cache_ptr[block].tag != tag ) {
printf( "Read miss!\n" );
already_missed = 1;
cache_ptr[block].tag = tag;
}
if( cache_ptr[block].block == NULL ) {
if( already_missed == 0 )
printf( "Read miss!\n" );
// allocate block
cache_ptr[block].block = ( int* )malloc( block_size * sizeof( int ) );
}
// read from main memory
for( i = 0; i < block_size; ++i ) {
cache_ptr[block].block[i] = main_mem_ptr[base_offset + i];
}
printf( "Word %d of block %d with tag %d contains %d\n", word, block, tag, cache_ptr[block].block[word] );
}
void show_content( int* p, int size ) {
int i = 0;
for( ; i < size; ++i )
printf( "%d, ", p[i] );
}
Input and output sample
Main memory to Cache memory mapping:
--------------------------------------
1) Set parameters
2) Read cache
3) Write to cache
4) Exit
Enter selection: 1
Enter main memory size (words): 65536
Enter cache size (words): 1024
Enter block size (words/block): 16
Main memory to Cache memory mapping:
--------------------------------------
1) Set parameters
2) Read cache
3) Write to cache
4) Exit
Enter selection: 3
Enter main memory address to write to: 65535
Enter value to write: 14
Write miss!
Word 15 of block 63 with tag 63 contains value 14
Main memory to Cache memory mapping:
--------------------------------------
1) Set parameters
2) Read cache
3) Write to cache
4) Exit
Enter selection: 2
Enter main memory address to read from: 65535
Word 15 of block 63 with tag 63 contains value 14
Main memory to Cache memory mapping:
--------------------------------------
1) Set parameters
2) Read cache
3) Write to cache
4) Exit
Enter selection: 3
Enter main memory address to write to: 65534
Enter value to write: 512
Word 14 of block 63 with tag 63 contains value 512
Main memory to Cache memory mapping:
--------------------------------------
1) Set parameters
2) Read cache
3) Write to cache
4) Exit
Enter selection: 2
Enter main memory address to read from: 1023
Read miss!
Word 15 of block 63 with tag 0 contains value 64513
Main memory to Cache memory mapping:
--------------------------------------
1) Set parameters
2) Read cache
3) Write to cache
4) Exit
Enter selection: 4
%
I haven't gone right through the program, but the first thing I spotted is that when you call malloc()
you don't check for success.
e.g.
int* init_main_mem_of(int size)
{
int i = 0;
int* p = (int *)malloc(size * sizeof(int));
if (!p)
{
puts("Error: Out of memory\n");
exit(1);
}
for( ; i < size; ++i)
p[i] = size - i;
return p;
}
The problem might be the school computer running out of memory, rather than the compiler. Go through the program and make sure that every call to malloc()
succeeds.
aschelper caught the error from the screenshot. You specify a memory size of 65535
then tell it to write at address 65535
(one past the end of the array!).
When run in valgrind, the following output occurs (compiled with gcc-4.5.2):
$ valgrind ./test
==29640== Memcheck, a memory error detector
==29640== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==29640== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==29640== Command: ./test
==29640==
Main memory to cache memory mapping:
------------------------------------
1) Set parameters
2) Read cache
3) Write to cache
4) Exit
Enter selection: 1
Enter main memory size (words): 65535
Enter main memory size (words): 1024
Enter block size (words/block): 16
Main memory to cache memory mapping:
------------------------------------
1) Set parameters
2) Read cache
3) Write to cache
4) Exit
Enter selection: 3
Enter main memory address to write to: 65535
Enter value to write: 14
==29640== Invalid write of size 4
==29640== at 0x400B25: write_cache(int*, _tag_cache*, int, int, int) (test.cc:173)
==29640== by 0x400878: program() (test.cc:80)
==29640== by 0x4006CC: main (test.cc:29)
==29640== Address 0x59ac4bc is 0 bytes after a block of size 262,140 alloc'd
==29640== at 0x4C24660: malloc (vg_replace_malloc.c:195)
==29640== by 0x400968: init_main_mem_of(int) (test.cc:122)
==29640== by 0x400824: program() (test.cc:71)
==29640== by 0x4006CC: main (test.cc:29)
==29640==
==29640== Invalid read of size 4
==29640== at 0x400B34: write_cache(int*, _tag_cache*, int, int, int) (test.cc:175)
==29640== by 0x400878: program() (test.cc:80)
==29640== by 0x4006CC: main (test.cc:29)
==29640== Address 0x59ac8f0 is 0 bytes after a block of size 1,008 alloc'd
==29640== at 0x4C24660: malloc (vg_replace_malloc.c:195)
==29640== by 0x4009C8: init_cache_of(int) (test.cc:132)
==29640== by 0x400832: program() (test.cc:72)
==29640== by 0x4006CC: main (test.cc:29)
==29640==
Write miss!
==29640== Invalid write of size 4
==29640== at 0x400B5C: write_cache(int*, _tag_cache*, int, int, int) (test.cc:178)
==29640== by 0x400878: program() (test.cc:80)
==29640== by 0x4006CC: main (test.cc:29)
==29640== Address 0x59ac8f0 is 0 bytes after a block of size 1,008 alloc'd
==29640== at 0x4C24660: malloc (vg_replace_malloc.c:195)
==29640== by 0x4009C8: init_cache_of(int) (test.cc:132)
==29640== by 0x400832: program() (test.cc:72)
==29640== by 0x4006CC: main (test.cc:29)
==29640==
==29640== Invalid read of size 8
==29640== at 0x400B6B: write_cache(int*, _tag_cache*, int, int, int) (test.cc:181)
==29640== by 0x400878: program() (test.cc:80)
==29640== by 0x4006CC: main (test.cc:29)
==29640== Address 0x59ac8f8 is 8 bytes after a block of size 1,008 alloc'd
==29640== at 0x4C24660: malloc (vg_replace_malloc.c:195)
==29640== by 0x4009C8: init_cache_of(int) (test.cc:132)
==29640== by 0x400832: program() (test.cc:72)
==29640== by 0x4006CC: main (test.cc:29)
==29640==
==29640== Invalid write of size 8
==29640== at 0x400BA5: write_cache(int*, _tag_cache*, int, int, int) (test.cc:185)
==29640== by 0x400878: program() (test.cc:80)
==29640== by 0x4006CC: main (test.cc:29)
==29640== Address 0x59ac8f8 is 8 bytes after a block of size 1,008 alloc'd
==29640== at 0x4C24660: malloc (vg_replace_malloc.c:195)
==29640== by 0x4009C8: init_cache_of(int) (test.cc:132)
==29640== by 0x400832: program() (test.cc:72)
==29640== by 0x4006CC: main (test.cc:29)
==29640==
==29640== Invalid read of size 8
==29640== at 0x400BBF: write_cache(int*, _tag_cache*, int, int, int) (test.cc:189)
==29640== by 0x400878: program() (test.cc:80)
==29640== by 0x4006CC: main (test.cc:29)
==29640== Address 0x59ac8f8 is 8 bytes after a block of size 1,008 alloc'd
==29640== at 0x4C24660: malloc (vg_replace_malloc.c:195)
==29640== by 0x4009C8: init_cache_of(int) (test.cc:132)
==29640== by 0x400832: program() (test.cc:72)
==29640== by 0x4006CC: main (test.cc:29)
==29640==
==29640== Invalid read of size 4
==29640== at 0x400BE4: write_cache(int*, _tag_cache*, int, int, int) (test.cc:189)
==29640== by 0x400878: program() (test.cc:80)
==29640== by 0x4006CC: main (test.cc:29)
==29640== Address 0x59ac4bc is 0 bytes after a block of size 262,140 alloc'd
==29640== at 0x4C24660: malloc (vg_replace_malloc.c:195)
==29640== by 0x400968: init_main_mem_of(int) (test.cc:122)
==29640== by 0x400824: program() (test.cc:71)
==29640== by 0x4006CC: main (test.cc:29)
==29640==
==29640== Invalid read of size 8
==29640== at 0x400C06: write_cache(int*, _tag_cache*, int, int, int) (test.cc:192)
==29640== by 0x400878: program() (test.cc:80)
==29640== by 0x4006CC: main (test.cc:29)
==29640== Address 0x59ac8f8 is 8 bytes after a block of size 1,008 alloc'd
==29640== at 0x4C24660: malloc (vg_replace_malloc.c:195)
==29640== by 0x4009C8: init_cache_of(int) (test.cc:132)
==29640== by 0x400832: program() (test.cc:72)
==29640== by 0x4006CC: main (test.cc:29)
==29640==
Word 15 of block 63 with tag 63 contains 14
Main memory to cache memory mapping:
------------------------------------
1) Set parameters
2) Read cache
3) Write to cache
4) Exit
Enter selection: ^C==29640==
==29640== HEAP SUMMARY:
==29640== in use at exit: 263,212 bytes in 3 blocks
==29640== total heap usage: 5 allocs, 2 frees, 526,380 bytes allocated
==29640==
==29640== LEAK SUMMARY:
==29640== definitely lost: 64 bytes in 1 blocks
==29640== indirectly lost: 0 bytes in 0 blocks
==29640== possibly lost: 0 bytes in 0 blocks
==29640== still reachable: 263,148 bytes in 2 blocks
==29640== suppressed: 0 bytes in 0 blocks
==29640== Rerun with --leak-check=full to see details of leaked memory
==29640==
==29640== For counts of detected and suppressed errors, rerun with: -v
==29640== ERROR SUMMARY: 23 errors from 8 contexts (suppressed: 4 from 4)
You were simply lucky that it didn't crash with other compilers, but you did indeed have an error (you don't check that user input is sane!)
At the very least, perhaps you should put something like this before main_mem_ptr[addr] = value;
:
assert(addr < main_mem_size);
You always can get information about crash, if you run your program under source level debugger - gdb.
Compile your sources with -g option and run it under gdb.
$gdb ./your_prog_name_here
In gdb type "run" to start program.
When program crashed gdb will stop. Type "bt" to get backtrace of your executable to get an idea which statement cause crash.
Hope this help.
精彩评论