I'm currently writing a method that reads from an allocated block of memory and prints out its contents from a certain offset and up to a specified size, both of which are passed as parameters. I'm using char pointers to accomplish this, but keep getting a malloc error around line
char *content = (char *)malloc(size+1);
Code for the method:
int file_read(char *name, int offset, int size)
{
//First find file and its inode, if existing
int nodeNum = search_cur_dir(name);
if(nodeNum < 0) {
printf("File read error: file does not exist\n");
return -1;
}
//Size check, to avoid overflows/overreads
if(offset > inode[nodeNum].size || size > inode[nodeNum].size || (offset+size) > inode[nodeNum].size) {
printf("File read error: offset and/or size is too large\n");
return -1;
}
int i, read_size, track_size = size, content_offset = 0;
int target_block = offset / BLOCK_SIZE; //Defined as constant 512
int target_index = offset % BLOCK_SIZE;
char *raw_content = (char *)malloc(inode[nodeNum].size+1);
printf("check1\n"); //Debug statment
for(i = target_block; i < (inode[nodeNum].blockCount-(size/BLOCK_SIZE)); i++) {
disk_read(inode[nodeNum].directBlock[i], raw_content+content_offset);
content_offset += BLOCK_SIZE;
}
printf("check2\n"); //Debug statment
char *content = (char *)malloc(size+1);
memcpy(content, raw_content+target_index, size);
printf("%s\n", content);
free(raw_content);
free(content);
return 0;
}
and code for disk_read:
char disk[MAX_BLOCK][BLOCK_SIZE]; //Defined as 4096 and 512, respectively
int disk_read(int block, char *buf)
{
if(block < 0 || block >= MAX_BLOCK) {
printf("disk_read error\n");
return -1;
}
memcpy(buf, disk[block], BLOCK_SIZE);
return 0;
}
structure for node
typedef struct {
TYPE type;
int owner;
int group;
struct timeval lastAccess;
struct timeval created;
int size;
int blockCount;
int directBlock[10];
int indirectBlock;
char padding[24];
} Inode; // 128 byte
The error I get when using this method is one of memory corruption
*** glibc detected *** ./fs_sim: malloc(): memory corruption (fast): 0x00000000009f1030 ***
Now the strange part is, firstly this only occurs after I have used the method a few times - for the first two or three attempts it will work and then the error occurs. For instance, here is an example test run:
% read new 0 5
z12qY
% read new 0 4
z12q
% read new 0 3
*** glibc detected *** ./fs_sim: malloc(): memory corruption (fast): 0x00000000009f1030 ***
Even stranger still, this error disappears completely when I comment out
free(raw_content);
free(content);
Even through this would tie up the memory. I've read through previous posts regarding malloc memory corruption and understand this usually results from overwriting memory bounds or under allocating space, but I can't see where I could be doing this. I've attempted other sizes for malloc as well and these produced the best results when I commented out the lines freeing both pointers. Does anyone see what I could be missing? And why does this occur so inconsistently?
Code allocates space for characters and a null character, but does not insure the array is terminated with a null character before printing as a string.
char *content = (char *)malloc(size+1);
memcpy(content, raw_content+target_index, size);
// add
content[size] = '\0';
printf("%s\n", content);
Likely other issues too.
[Edit]
OP code is prone to mis-coding and dependent on inode[] to have coherent values (.blockCount . size). Clarify and simplify by determining the loop count and allocating per that count.
int loop_count = (inode[nodeNum].blockCount-(size/BLOCK_SIZE)) - target_block;
char *raw_content = malloc(sizeof *raw_content * loop_count * BLOCK_SIZE);
assert(raw_count);
for (loop = 0; loop < loop_count; loop++) {
i = target_block + loop;
disk_read(inode[nodeNum].directBlock[i], raw_content + content_offset);
content_offset += BLOCK_SIZE;
}
Also recommend checking the success of disk_read()
Related
As part of a personal project, I'm trying to create a dynamic array of 2-tuples that show a) the line in a program and b) the number of bytecode tokens associated with that line. I've implemented this as a struct of arrays:
typedef struct{
int count; // Number of elements
int capacity; // total capacity of arraylist
int* lines;
int* lineCount;
}
this is based on the example from the codebase, as such:
int count;
int capacity;
uint8_t* bytes;
My problem comes from re-allocation - I have several helper functions/macros for growing and re-allocating the array lists memory - here particularly the macro GROW_ARRAY and reallocate(), as described below. When I try and re-allocate lines, it works fine, but I get a segmentation fault and realloc(): invalid old size several times when I attempt to reallocate lineCount after it
I'm using the code base from Bob Nystrom's Crafting Interpreters, especially this first part here https://craftinginterpreters.com/chunks-of-bytecode.html#challenges. Most of the code comes from there, albeit tinkered with some of having added
Mostly, I've added a lot of checks and been running this with all the debug features in gcc I can find. Notably, realloc(): invalid old size has stop appearing as I've tinkered with the code some.
EDIT: Added main function that should reproduce behavior
int main() {
LineArray lines;
// Initialize to 0 / NULL
initLineArray(&lines);
updateLineArray(&lines, 0, 1);
}
// the structure I'm using
typedef struct {
int capacity;
int count;
int* lines;
int* lineCount;
} LineArray;
/* Note LineArray has already been initialized earlier with
capacity=0;
count=0;
lines=NULL;
lineCount=NULL;
*/
void updateLineArray(LineArray* array, int line, int count) {
// IF line in `lines` -- update it
int index = containsLine(array, line);
if (index != -1) { // IF Index is not Error Code
// I think I fixed a bug here?
array->lineCount[index] += count;
return;
}
//ELSE -- add line to end (naturally appends); then increment
else {
//Check to see if array would be overgrown
if (array->capacity < array->count + 1) {
//IF yes, regrow array
int old_capacity = array->capacity;
array->capacity = GROW_CAPACITY(old_capacity);
// Reallocate arrays.
array->lines = GROW_ARRAY(array->lines, int, old_capacity,
array->capacity);
array->lineCount = GROW_ARRAY(array->lineCount, int, old_capacity,
array->capacity);
}
// Properly update the lines
array->lines[array->count] = line;
array->lineCount[array->count] = count;
array->count++;
return;
}
}
//The memory management functions/macros I'm using here
#define GROW_CAPACITY(capacity) \
((capacity) < 8 ? 8 : (capacity) * 2)
#define GROW_ARRAY(previous, type, oldCount, count) \
(type*) reallocate(previous, sizeof(type) * (oldCount), \
sizeof(type) * (count))
void* reallocate(void* previous, size_t oldSize, size_t newSize) {
// If size is null, erase it and get null_pointer
if (newSize == 0) {
free(previous);
return NULL;
}
// reallocate the data into a new size
// is Oldsize is zero :: malloc(data, newSize)
return realloc(previous, newSize);
}
I'm trying to make a file system in C. I have trouble with this portion of my code when I'm printing my values in the code below:
for (int i = 0; i<NUM_POINTERS; i++) {
printf("before SB->root[%d]=%d\n", i, SB->root->pointers[i]);
}
write_blocks(0, 1, SB);
for (int i = 0; i<NUM_POINTERS; i++) {
printf("after SB->root[%d]=%d\n", i, SB->root->pointers[i]);
}
my write_blocks method:
int write_blocks(int start_address, int nblocks, void *buffer)
{
int i, e, s;
e = 0;
s = 0;
void* blockWrite = (void*) malloc(BLOCK_SIZE);
/*Checks that the data requested is within the range of addresses of the disk*/
if (start_address + nblocks > MAX_BLOCK)
{
printf("out of bound error\n");
return -1;
}
/*Goto where the data is to be written on the disk*/
fseek(fp, start_address * BLOCK_SIZE, SEEK_SET);
/*For every block requested*/
for (i = 0; i < nblocks; ++i)
{
/*Pause until the latency duration is elapsed*/
usleep(L);
memcpy(blockWrite, buffer+(i*BLOCK_SIZE), BLOCK_SIZE);
fwrite(blockWrite, BLOCK_SIZE, 1, fp);
fflush(fp);
s++;
}
free(blockWrite);
/*If no failure return the number of blocks written, else return the negative number of failures*/
if (e == 0)
return s;
else
return e;
}
And here's what gets printed:
before SB->root[0]=1
before SB->root[1]=2
before SB->root[2]=3
before SB->root[3]=4
before SB->root[4]=5
before SB->root[5]=6
before SB->root[6]=7
before SB->root[7]=8
before SB->root[8]=9
before SB->root[9]=10
before SB->root[10]=11
before SB->root[11]=12
before SB->root[12]=13
before SB->root[13]=14
after SB->root[0]=1234344888
after SB->root[1]=32688
after SB->root[2]=3
after SB->root[3]=4
after SB->root[4]=5
after SB->root[5]=6
after SB->root[6]=7
after SB->root[7]=8
after SB->root[8]=9
after SB->root[9]=10
after SB->root[10]=11
after SB->root[11]=12
after SB->root[12]=13
after SB->root[13]=14
I don't understand why my first and second pointer value change?
Some additional information: SB is a superBlock here's my structures:
typedef struct iNode
{
int id;
int size;
int pointers[NUM_POINTERS];
} iNode;
typedef struct superBlock
{
int magic_number;
int block_size;
int num_blocks;
int num_inodes;
iNode *root;
iNode jNodes[20];
} superBlock;
Is this single threaded?
Does the modified SB->root[0,1] contain the data you are trying to write?
What is your BLOCK_SIZE?
I suspect the problem is outside of write_blocks(). My best guess would be that you accidentally freed SB somewhere and malloc gave you the same address. After the malloc check (print or debugger) both buffer and blockWrite and make sure they are different and valid.
Unrelated Issues:
printf has more % than params
You should check the return of malloc
e is never set
s and i are equal. AKA redundant.
Out of bounds error causes a memory leak (since it is after the malloc)
usleep is strange perhaps you want fsync?
While working on a program which requires frequent memory allocation I came across behaviour I cannot explain. I've implemented a work around but I am curious to why my previous implementation didn't work. Here's the situation:
Memory reallocation of a pointer works
This may not be best practice (and if so please let me knwow) but I recall that realloc can allocate new memory if the pointer passed in is NULL. Below is an example where I read file data into a temporary buffer, then allocate appropriate size for *data and memcopy content
I have a file structure like so
typedef struct _my_file {
int size;
char *data;
}
And the mem reallocation and copy code like so:
// cycle through decompressed file until end is reached
while ((read_size = gzread(fh, buf, sizeof(buf))) != 0 && read_size != -1) {
// allocate/reallocate memory to fit newly read buffer
if ((tmp_data = realloc(file->data, sizeof(char *)*(file->size+read_size))) == (char *)NULL) {
printf("Memory reallocation error for requested size %d.\n", file->size+read_size);
// if memory was previous allocated but realloc failed this time, free memory!
if (file->size > 0)
free(file->data);
return FH_REALLOC_ERROR;
}
// update pointer to potentially new address (man realloc)
file->data = tmp_data;
// copy data from temporary buffer
memcpy(file->data + file->size, buf, read_size);
// update total read file size
file->size += read_size;
}
Memory reallocation of pointer to pointer fails
However, here is where I'm confused. Using the same thought that reallocation of a NULL pointer will allocate new memory, I parse a string of arguments and for each argument I allocate a pointer to a pointer, then allocate a pointer that is pointed by that pointer to a pointer. Maybe code is easier to explain:
This is the structure:
typedef struct _arguments {
unsigned short int options; // options bitmap
char **regexes; // array of regexes
unsigned int nregexes; // number of regexes
char *logmatch; // log file match pattern
unsigned int limit; // log match limit
char *argv0; // executable name
} arguments;
And the memory allocation code:
int i = 0;
int len;
char **tmp;
while (strcmp(argv[i+regindex], "-logs") != 0) {
len = strlen(argv[i+regindex]);
if((tmp = realloc(args->regexes, sizeof(char **)*(i+1))) == (char **)NULL) {
printf("Cannot allocate memory for regex patterns array.\n");
return -1;
}
args->regexes = tmp;
tmp = NULL;
if((args->regexes[i] = (char *)malloc(sizeof(char *)*(len+1))) == (char *)NULL) {
printf("Cannot allocate memory for regex pattern.\n");
return -1;
}
strcpy(args->regexes[i], argv[i+regindex]);
i++;
}
When I compile and run this I get a run time error "realloc: invalid pointer "
I must be missing something obvious but after not accomplishing much trying to debug and searching for solutions online for 5 hours now, I just ran two loops, one counts the numbers of arguments and mallocs enough space for it, and the second loop allocates space for the arguments and strcpys it.
Any explanation to this behaviour is much appreciated! I really am curious to know why.
First fragment:
// cycle through decompressed file until end is reached
while (1) {
char **tmp_data;
read_size = gzread(fh, buf, sizeof buf);
if (read_size <= 0) break;
// allocate/reallocate memory to fit newly read buffer
tmp_data = realloc(file->data, (file->size+read_size) * sizeof *tmp_data );
if ( !tmp_data ) {
printf("Memory reallocation error for requested size %d.\n"
, file->size+read_size);
if (file->data) {
free(file->data)
file->data = NULL;
file->size = 0;
}
return FH_REALLOC_ERROR;
}
file->data = tmp_data;
// copy data from temporary buffer
memcpy(file->data + file->size, buf, read_size);
// update total read file size
file->size += read_size;
}
Second fragment:
unsigned i; // BTW this variable is already present as args->nregexes;
for(i =0; strcmp(argv[i+regindex], "-logs"); i++) {
char **tmp;
tmp = realloc(args->regexes, (i+1) * sizeof *tmp );
if (!tmp) {
printf("Cannot allocate memory for regex patterns array.\n");
return -1;
}
args->regexes = tmp;
args->regexes[i] = strdup( argv[i+regindex] );
if ( !args->regexes[i] ) {
printf("Cannot allocate memory for regex pattern.\n");
return -1;
}
...
return 0;
}
A few notes:
the syntax ptr = malloc ( CNT * sizeof *ptr); is more robust than the sizeof(type) variant.
strdup() does exactly the same as your malloc+strcpy()
the for(;;) loop is less error prone than a while() loop with a loose i++; at the end of the loop body. (it also makes clear that the loopcondition is never checked)
to me if ( !ptr ) {} is easyer to read than if (ptr != NULL) {}
the casts are not needed and sometimes unwanted.
I am having trouble with a struct array. I need to read in a text file line by line, and compare the values side by side. For example "Mama" would return 2 ma , 1 am because you have ma- am- ma. I have a struct:
typedef struct{
char first, second;
int count;
} pair;
I need to create an array of structs for the entire string, and then compare those structs. We also were introduced to memory allocation so we have to do it for any size file. That is where my trouble is really coming in. How do I reallocate the memory properly for an array of structs? This is my main as of now (doesn't compile, has errors obviously having trouble with this).
int main(int argc, char *argv[]){
//allocate memory for struct
pair *p = (pair*) malloc(sizeof(pair));
//if memory allocated
if(p != NULL){
//Attempt to open io files
for(int i = 1; i<= argc; i++){
FILE * fileIn = fopen(argv[i],"r");
if(fileIn != NULL){
//Read in file to string
char lineString[137];
while(fgets(lineString,137,fileIn) != NULL){
//Need to reallocate here, sizeof returning error on following line
//having trouble seeing how much memory I need
pair *realloc(pair *p, sizeof(pair)+strlen(linestring));
int structPos = 0;
for(i = 0; i<strlen(lineString)-1; i++){
for(int j = 1; j<strlen(lineSTring);j++){
p[structPos]->first = lineString[i];
p[structPos]->last = lineString[j];
structPos++;
}
}
}
}
}
}
else{
printf("pair pointer length is null\n");
}
}
I am happy to change things around obviously if there is a better method for this. I HAVE to use the above struct, have to have an array of structs, and have to work with memory allocation. Those are the only restrictions.
Allocating memory for an array of struct is as simple as allocating for one struct:
pair *array = malloc(sizeof(pair) * count);
Then you can access each item by subscribing "array":
array[0] => first item
array[1] => second item
etc
Regarding the realloc part, instead of:
pair *realloc(pair *p, sizeof(pair)+strlen(linestring));
(which is not syntactically valid, looks like a mix of realloc function prototype and its invocation at the same time), you should use:
p=realloc(p,[new size]);
In fact, you should use a different variable to store the result of realloc, since in case of memory allocation failure, it would return NULL while still leaving the already allocated memory (and then you would have lost its position in memory). But on most Unix systems, when doing casual processing (not some heavy duty task), reaching the point where malloc/realloc returns NULL is somehow a rare case (you must have exhausted all virtual free memory). Still it's better to write:
pair*newp=realloc(p,[new size]);
if(newp != NULL) p=newp;
else { ... last resort error handling, screaming for help ... }
So if I get this right you're counting how many times pairs of characters occur? Why all the mucking about with nested loops and using that pair struct when you can just keep a frequency table in a 64KB array, which is much simpler and orders of magnitude faster.
Here's roughly what I would do (SPOILER ALERT: especially if this is homework, please don't just copy/paste):
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
void count_frequencies(size_t* freq_tbl, FILE* pFile)
{
int first, second;
first = fgetc(pFile);
while( (second = fgetc(pFile)) != EOF)
{
/* Only consider printable characters */
if(isprint(first) && isprint(second))
++freq_tbl[(first << 8) | second];
/* Proceed to next character */
first = second;
}
}
int main(int argc, char*argv[])
{
size_t* freq_tbl = calloc(1 << 16, sizeof(size_t));;
FILE* pFile;
size_t i;
/* Handle some I/O errors */
if(argc < 2)
{
perror ("No file given");
return EXIT_FAILURE;
}
if(! (pFile = fopen(argv[1],"r")))
{
perror ("Error opening file");
return EXIT_FAILURE;
}
if(feof(pFile))
{
perror ("Empty file");
return EXIT_FAILURE;
}
count_frequencies(freq_tbl, pFile);
/* Print frequencies */
for(i = 0; i <= 0xffff; ++i)
if(freq_tbl[i] > 0)
printf("%c%c : %d\n", (char) (i >> 8), (char) (i & 0xff), freq_tbl[i]);
free(freq_tbl);
return EXIT_SUCCESS;
}
Sorry for the bit operations and hex notation. I just happen to like them in such a context of char tables, but they can be replaced with multiplications and additions, etc for clarity.
I am new to C programming and I am getting confused with the pointer math. I have an array of characters of size 32. It is my understanding that this means that the array is also 32 bytes since a character variable is 1 byte big therefore 32 characters * 1 byte = 32 bytes. The problem is when having a function that has a void pointer that is pointing to an array of characters as described before. I believe that the code segment
for (count = 0; count < size; count++)
*((int*) raw_sk + count) = 0
should set all of the slots in the raw_sk buffer should be set to 0. However, when I run the program, I get a segmentation fault. I thought that it could be possibly be the fact that I am adding count to the address. I thought that if I were to add one to an address I would be moving to the next slot in the array. Can someone please point out where I am going wrong? The function I am using is below.
Thanks!
void
write_skfile (const char *skfname, void *raw_sk, size_t raw_sklen)
{
int fdsk = 0;
char *s = NULL;
int status = 0;
int count = 0;
int size = (raw_sklen);
/* armor the raw symmetric key in raw_sk using armor64 */
s = armor64(raw_sk, raw_sklen);
/* now let's write the armored symmetric key to skfname */
if ((fdsk = open (skfname, O_WRONLY|O_TRUNC|O_CREAT, 0600)) == -1) {
perror (getprogname ());
/*scrubs the armored buffer*/
for(count = 0; count < armor64len(s); count++)
s[count] = '0';
free (s);
/* scrub the buffer that's holding the key before exiting */
for (count = 0; count < size; count++)
*((int*)raw_sk + count) = 0;
exit (-1);
}
else {
status = write (fdsk, s, strlen (s));
if (status != -1) {
status = write (fdsk, "\n", 1);
}
for (count = 0; (size_t)count < 22; count++)
*((int*)raw_sk + count) = 0;
free (s);
close (fdsk);
/* do not scrub the key buffer under normal circumstances
(it's up to the caller) */
if (status == -1) {
printf ("%s: trouble writing symmetric key to file %s\n",
getprogname (), skfname);
perror (getprogname ());
/* scrub the buffer that's holding the key before exiting */
/* scrub the buffer that's holding the key before exiting MY CODE
for (count = 0; count < size; count++)
*((int*)raw_sk + count) = 0;*/
exit (-1);
}
}
}
You are incrementing the pointer by the size of an int. That is wrong. If you want to zero out the array you increment by the size of a char. Better yet, just use memset.
Your loop iterates over size*sizeof(int) bytes in total (where most probably sizeof(int)==4), but the array is only size bytes large. Hence, segmentation fault.
I think you meant to do
*((char*) raw_sk + count) = 0
since I assume raw_sk is pointing to char array
pointer arithmatic works by moving the memory address by size of type so in this case you want char