Malloc and pointer - c

I'm trying to understand one code which I found on YouTube. I know how malloc works but I don't understand how this code works. He points to the first element in the heap and allocate space for another entities?
#define u8 uint8_t
#define u16 uint16_t
#define STACK_SIZE 32
#define HEAP_SIZE STACK_SIZE * 4
#define HEADER 4
static u16 IN_USE;
typedef struct virtual_memory
{
u8 stack[STACK_SIZE];
char** unmapped;
u8 heap[HEAP_SIZE];
struct
{
char** data;
char** bss;
char* text;
}data_t;
}virtual_memory_t;
typedef struct entity
{
u8* ptr;
int size;
}entity_t;
entity_t LIST[40];
entity_t* new_entity(size_t size)
{
if (LIST[0].ptr == NULL && LIST[0].size == 0)
{
static virtual_memory_t vm;
LIST[0].ptr = vm.heap;
LIST[0].size = HEAP_SIZE;
IN_USE++;
}
entity_t* best = LIST;
for (unsigned i = 0; i < IN_USE; i++)
{
if (LIST[i].size >= size && LIST[i].size < best->size)
{
best = &LIST[i];
}
}
return best;
}
void* w_malloc(size_t size)
{
assert(size <= HEAP_SIZE);
size += HEADER;
entity_t* e = new_entity(size);
u8* start = e->ptr;
u8* user_ptr = start + HEADER;
*start = size;
e->ptr += size;
e->size -= size;
assert(e->size >= 0);
return user_ptr;
}
void w_free(void* ptr)
{
u8* start = (u8*)ptr - HEADER;
LIST[IN_USE].ptr = &(*start);
LIST[IN_USE].size = (u8) * ((u8*)ptr - HEADER);
IN_USE++;
}
Question:
LIST[IN_USE].ptr = &(*start);
LIST[IN_USE].size = (u8) * ((u8*)ptr - HEADER);
Why this piece of code the same like this?
LIST[IN_USE].ptr = start;
LIST[IN_USE].size = *start;
I can't understand the logic of this process.

u8* start = e->ptr;
u8* user_ptr = start + HEADER;
in malloc function, the address that user_ptr point to start + HEADER, so in free function, we just restore the address of start to original address:
u8* start = (u8*)ptr - HEADER;
LIST[IN_USE].ptr = &(*start);
Here, we reset ptr points to start. It's similar to
LIST[IN_USE].ptr = &(*start);
because, *start we deference the pointer to have the value that start pointer pointing to. Then, we use reference to have the address of this value, this is exactly the address of start pointer pointing to.
Here:
LIST[IN_USE].size = (u8) * ((u8*)ptr - HEADER);
(u8*)ptr - HEADER is start. So * ((u8*)ptr - HEADER) is *start. Then u8 *(start) is value that start points to with the type u8

Related

Valgrind memcpy Invalid write of size 8 (uintptr_t *)

I have an issue with memcpy and valgrind, telling me about an Invalid write of size 8.
I got to the point of figuring out where the faulty code is, but I have no clue as to why it is faulty...
I'm aware that there are other questions regarding that, but they don't help me really.
The following is an excerpt of the most important bits of my approach on a somewhat "universal" stack, when my regular value would be of type uintptr_t.
Here are two defines that I used below:
// default stack batch size
#define STACK_BATCH_DEFAULT 8
// size of one value in the stack
#define STACK_SIZEOF_ONE sizeof(uintptr_t)
The structure of the stack is as follows:
typedef struct Stack
{
size_t count; // count of values in the stack
size_t size; // size of one value in bytes
size_t alloced; // allocated count
uintptr_t *value; // the values
int batch; // memory gets allocated in those batches
}
Stack;
I have an initialization function for the stack:
bool stack_init(Stack *stack, size_t size, int batch)
{
if(!stack) return false;
stack->batch = batch ? batch : STACK_BATCH_DEFAULT;
stack->size = size;
stack->count = 0;
stack->value = 0;
stack->alloced = 0;
return true;
}
Then the stack_push function, where valgrind throws the error Invalid write of size 8:
bool stack_push(Stack *stack, uintptr_t *value)
{
if(!stack || !value) return false;
// calculate required amount of elements
size_t required = stack->batch * (stack->count / stack->batch + 1);
// allocate more memory if we need to
if(required > stack->alloced)
{
uintptr_t *tmp = realloc(stack->value, required * stack->size);
if(!tmp) return false;
stack->value = tmp;
stack->alloced = required;
}
// set the value
if(stack->size > STACK_SIZEOF_ONE)
{
memcpy(stack->value + stack->size * stack->count, value, stack->size); // <--- valgrind throws the error here
}
else
{
stack->value[stack->count] = *value;
}
// increment count
stack->count++;
return true;
}
Then in my program I'm calling the functions as follows:
Stack stack = {0};
stack_init(&stack, sizeof(SomeStruct), 0);
/* ... */
SomeStruct push = { // this is a struct that is larger than STACK_SIZEOF_ONE
.int_a = 0,
.int_b = 0,
.int_c = 0,
.id = 0,
.pt = pointer_to_struct, // it is a pointer to some other struct that was allocated beforehand
};
stack_push(&stack, (uintptr_t *)&push);
And with universal I meant that I can also have a regular stack:
Stack stack = {0};
stack_init(&stack, sizeof(uintptr_t), 0);
/* ... */
uintptr_t a = 100;
stack_push(&stack, &a);
Also, I'm open to hear general tips and advices if there are any things that should/could be improved :)
Edit: Below is a runnable code.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
// default stack batch size
#define STACK_BATCH_DEFAULT 8
// size of one value in the stack
#define STACK_SIZEOF_ONE sizeof(uintptr_t)
#define TESTCOUNT 10
#define MAX_BUF 16
typedef struct Stack
{
size_t count; // count of values in the stack
size_t size; // size of one value in bytes
size_t alloced; // allocated count
uintptr_t *value; // the values
int batch; // memory gets allocated in those batches
}
Stack;
typedef struct SomeStruct
{
size_t a;
size_t b;
size_t c;
size_t id;
char *str;
}
SomeStruct;
bool stack_init(Stack *stack, size_t size, int batch)
{
if(!stack) return false;
stack->batch = batch ? batch : STACK_BATCH_DEFAULT;
stack->size = size;
stack->count = 0;
stack->value = 0;
stack->alloced = 0;
return true;
}
bool stack_push(Stack *stack, uintptr_t *value)
{
if(!stack || !value) return false;
// calculate required amount of elements
size_t required = stack->batch * (stack->count / stack->batch + 1);
// allocate more memory if we need to
if(required > stack->alloced)
{
uintptr_t *tmp = realloc(stack->value, required * stack->size);
if(!tmp) return false;
stack->value = tmp;
stack->alloced = required;
}
// set the value
if(stack->size > STACK_SIZEOF_ONE)
{
memcpy(stack->value + stack->size * stack->count, value, stack->size); // <--- valgrind throws the error here
}
else
{
stack->value[stack->count] = *value;
}
// increment count
stack->count++;
return true;
}
bool stack_pop(Stack *stack, uintptr_t *value)
{
if(!stack) return false;
if(!stack->count) return false;
// decrement count of elements
stack->count--;
// return the value if we have an address
if(value)
{
if(stack->size > STACK_SIZEOF_ONE)
{
memcpy(value, stack->value + stack->size * stack->count, stack->size);
}
else
{
*value = stack->value[stack->count];
}
}
int required = stack->batch * (stack->count / stack->batch + 1);
if(required < stack->alloced)
{
uintptr_t *tmp = realloc(stack->value, required * stack->size);
if(!tmp) return false;
stack->value = tmp;
stack->alloced = required;
}
if(!stack->value) return false;
return true;
}
int main(void)
{
// initialize variables
bool valid = false;
Stack default_stack = {0};
Stack some_stack = {0};
// initialize stacks
stack_init(&default_stack, sizeof(uintptr_t), 0);
stack_init(&some_stack, sizeof(SomeStruct), 0);
// test default case - push
printf("Testing the default case, pushing...\n");
for(int i = 0; i < TESTCOUNT; i++)
{
uintptr_t push = i;
valid = stack_push(&default_stack, &push);
if(!valid) return -1;
}
// ...now pop
printf("Testing the default case, popping...\n");
do
{
uintptr_t pop = 0;
valid = stack_pop(&default_stack, &pop);
if(valid) printf("%llu,", pop);
}
while(valid);
printf("\n");
// test some case - push
printf("Testing some case, pushing...\n");
for(int i = 0; i < TESTCOUNT; i++)
{
// generate the push struct
SomeStruct push = {
.a = i * 10,
.b = i * 100,
.c = i * 1000,
.id = i,
.str = 0,
};
// allocate a string
push.str = malloc(MAX_BUF + 1);
snprintf(push.str, MAX_BUF, "%d", i);
// push
valid = stack_push(&some_stack, (uintptr_t *)&push);
if(!valid) return -1;
}
// ...now pop
printf("Testing some case, popping...\n");
do
{
SomeStruct pop = {0};
valid = stack_pop(&some_stack, (uintptr_t *)&pop);
if(valid)
{
printf("a=%d,b=%d,c=%d,id=%d,str=%s\n", pop.a, pop.b, pop.c, pop.id, pop.str);
free(pop.str);
}
}
while(valid);
printf("\n");
/* leave out free functions for this example.... */
return 0;
}
After hours I figured it out :D The mistake happened because I very rarely do pointer arithmetic... In short, I was assuming that it would always calculate with a byte.
Let's take a look at the lines containing:
memcpy(stack->value + stack->size * stack->count, value, stack->size);
...and break it down, so it is more readable. And also, I'll even add a handy dandy comment in it:
size_t offset = stack->size * stack->count; // offset in bytes
void *dest = stack->value + offset;
void *src = value;
memcpy(dest, src, stack->size);
Now the pro C-programmer should instantly spot the problem. It is with the calculation of stack->value + offset, where it should add offset in bytes but it is not, because the stack->value is of type uintptr_t * and not of type uint8_t *.
So to fix it, I replaced it with this line:
void *dest = (uint8_t *)stack->value + offset;
And the code works.

Circular buffer does not give the correct size of the buffer after 6-th element

I have written the code for the circular buffer in C and it works well until some extent. I took the size of the buffer being equal to 10. When I fill the buffer till element 6 - it works fine. But at the moment when I fill the 7-th element - I get the result "The size of the buffer is equal to 767". For the element 8 - it does not work. I use "head" to write and "tail" to extract values. Could you please help me with this?
#include<stdio.h>
#include<stdint.h>
#include <stdbool.h>
typedef struct RingBuffer {
uint16_t* buffer;
size_t head;
size_t tail;
size_t max;
bool full;
}*cbuf_handle_t;
cbuf_handle_t init_RingBuffer (uint8_t* buffer, size_t size){
cbuf_handle_t cbuf = malloc (sizeof(cbuf_handle_t));
cbuf->buffer = buffer;
cbuf->max = size;
return cbuf;
}
void RingBuffer_free(cbuf_handle_t cbuf){
free(cbuf);
}
void RingBuffer_reset(cbuf_handle_t cbuf){
cbuf->head = 0;
cbuf->tail = 0;
cbuf->full = false;
}
bool RingBuffer_full (cbuf_handle_t cbuf){
return cbuf->full;
}
bool RingBuffer_empty(cbuf_handle_t cbuf){
return (!cbuf->full && (cbuf->tail == cbuf->head));
}
size_t RingBuffer_Capacity(cbuf_handle_t cbuf){
return cbuf->max;
}
size_t RingBuffer_size(cbuf_handle_t cbuf){
size_t size = cbuf->max;
if (!cbuf->full){
if (cbuf->head >= cbuf->tail)
{
size = (cbuf->head - cbuf->tail);}
else
{
size = (cbuf->head - cbuf->tail + cbuf->max);
}
}
return size;
}
void RingBuffer_AdvancePointer(cbuf_handle_t cbuf){
if (cbuf->full){
cbuf->tail = (cbuf->tail+1)%cbuf->max;
}
cbuf->head = (cbuf->head + 1)%cbuf->max;
cbuf->full = (cbuf->head == cbuf->tail);
}
void RingBuffer_retreatPointer (cbuf_handle_t cbuf){
cbuf->full = false;
cbuf->tail = (cbuf->tail + 1)%cbuf->max;
}
void RingBuffer_addValue (cbuf_handle_t cbuf, uint8_t data){
cbuf->buffer[cbuf->head] = data;
RingBuffer_AdvancePointer(cbuf);
}
int RingBuffer_Remove (cbuf_handle_t cbuf, uint8_t *data){
int r = -1;
if (!RingBuffer_empty(cbuf)){
*data = cbuf->buffer[cbuf->tail];
RingBuffer_retreatPointer(cbuf);
r = 0;
}
return r;
}
int main (){
uint8_t arr[10];
cbuf_handle_t cpt = init_RingBuffer(arr, 10);
//initialzie the buffer, tail and head and max
int i = 0;
RingBuffer_reset(cpt);
for ( i = 0 ; i< 6; i++){
RingBuffer_addValue(cpt, i);
}
size_t size = RingBuffer_size(cpt);
printf("The size of the buffer %d", size);
}
Thank you in advance!
Regards
Rostyslav
As said in comments, the declaration of the structure as a pointer is generally not recommended. However you can fix that bug by changing the way you allocate it using malloc :
cbuf_handle_t cbuf = malloc (sizeof(*cbuf));
This is because, cbuf being a pointer to the structure, if you dereference it you get the structure and thus its real size when you pass it to sizeof.

Why does LC_SYMTAB have invalid stroff/strsize but only for some loaded images?

I wrote the below program to iterate over all images in memory and dump their string tables.
#include <mach-o/dyld.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv) {
uint32_t count = _dyld_image_count();
for (uint32_t i = 0 ; i < count ; i++) {
const char* imageName = _dyld_get_image_name(i);
printf("IMAGE[%u]=%s\n", i, imageName);
const struct mach_header* header = _dyld_get_image_header(i);
if (header->magic != MH_MAGIC_64)
continue;
struct mach_header_64* header64 = (struct mach_header_64*)header;
char *ptr = ((void*)header64) + sizeof(struct mach_header_64);
for (uint32_t j = 0; j < header64->ncmds; j++) {
struct load_command *lc = (struct load_command *)ptr;
ptr += lc->cmdsize;
if (lc->cmd != LC_SYMTAB)
continue;
struct symtab_command* symtab = (struct symtab_command*)lc;
printf("\t\tLC_SYMTAB.stroff=%u\n", symtab->stroff);
printf("\t\tLC_SYMTAB.strsize=%u\n", symtab->strsize);
if (symtab->strsize > 100*1024*1024) {
printf("\t\tHUH? Don't believe string table is over 100MiB in size!\n");
continue;
}
char *strtab = (((void*)header64) + symtab->stroff);
uint32_t off = 0;
while (off < symtab->strsize) {
char *e = &(strtab[off]);
if (e[0] != 0)
printf("\t\tSTR[%u]=\"%s\"\n", off, e);
off += strlen(e) + 1;
}
}
}
return 0;
}
It seems to randomly work for some images, but for others the stroff/strsize have nonsensical values:
LC_SYMTAB.stroff=1266154560
LC_SYMTAB.strsize=143767728
It seems to always be the same two magic values, but I'm not sure if this is system-dependent in some way or if other people will get the same specific values.
If I comment out the check for strsize being over 100MiB, then printing the string table segfaults.
Most images seem to have this problem, but some don't. When I run it, I get the issue for 29 images out of 38.
I can't observe any pattern as to which do and which won't. What is going on here?
If it is relevant, I am testing on macOS 10.14.6 and compiling with Apple LLVM version 10.0.1 (clang-1001.0.46.4).
As you already worked out, those are from the dyld_shared_cache. And the 0x80000000 flag is indeed documented, in the headers shipped with Xcode or any semi-recent XNU source:
#define MH_DYLIB_IN_CACHE 0x80000000 /* Only for use on dylibs. When this bit
is set, the dylib is part of the dyld
shared cache, rather than loose in
the filesystem. */
As you've also discovered, the stroff/strsize values do not yield usable results when added to the dyld_shared_cache base. That is because those are not memory offsets, but file offsets. This is true for all Mach-O's, it's just often the case that the segments of non-cached binaries have the same relative position in file and memory offsets. But this is definitely not true for the shared cache.
To translate the file offset into a memory address, you'll have to parse the segments in the shared cache header. You can find struct definitions in the dyld source.
Here's a program which prints out the contents of the string table of the dyld shared cache.
My original program in the question can be enhanced to skip dumping string table of images with MH_DYLIB_IN_CACHE set, and combined with this program to dump the shared cache string table. (All images in the shared cache share the same string table.)
#include <mach-o/dyld.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
const void* _dyld_get_shared_cache_range(size_t* cacheLen);
struct dyld_cache_header {
char magic[16];
uint32_t mappingOffset;
uint32_t mappingCount;
// Omitted remaining fields, not relevant to this task
};
struct dyld_cache_mapping_info {
uint64_t address;
uint64_t size;
uint64_t fileOffset;
uint32_t maxProt;
uint32_t initProt;
};
#ifndef MH_DYLIB_IN_CACHE
# define MH_DYLIB_IN_CACHE 0x80000000
#endif
// Finds first shared cache DYLD image. Any will do, just grab the first
const struct mach_header_64* findSharedCacheDyldImage(void) {
uint32_t count = _dyld_image_count();
for (uint32_t i = 0 ; i < count ; i++) {
const struct mach_header* header = _dyld_get_image_header(i);
if (header->magic != MH_MAGIC_64)
continue;
const struct mach_header_64* header64 = (const struct mach_header_64*)header;
if (!(header64->flags & MH_DYLIB_IN_CACHE))
continue;
return header64;
}
return NULL;
}
// Find first instance of given load command in image
const struct load_command* findFirstLoadCommand(const struct mach_header_64* header64, uint32_t cmd) {
const char *ptr = ((void*)header64) + sizeof(struct mach_header_64);
for (uint32_t j = 0; j < header64->ncmds; j++) {
const struct load_command *lc = (const struct load_command *)ptr;
ptr += lc->cmdsize;
if (lc->cmd == cmd)
return lc;
}
return NULL;
}
// Translates a shared cache file offset to a memory address
void *translateOffset(const struct dyld_cache_header *cache, uint64_t offset) {
const struct dyld_cache_mapping_info* mappings = (struct dyld_cache_mapping_info*)(((void*)cache) + cache->mappingOffset);
for (uint32_t i = 0; i < cache->mappingCount; i++) {
if (offset < mappings[i].fileOffset) continue;
if (offset >= (mappings[i].fileOffset + mappings[i].size)) continue;
return (void*)(mappings[i].address - mappings[0].address + (offset - mappings[i].fileOffset) + (uint64_t)cache);
}
return NULL;
}
int main(int argc, char** argv) {
size_t cacheLen;
const struct dyld_cache_header *cache = _dyld_get_shared_cache_range(&cacheLen);
const struct mach_header_64* sharedCacheDyldImage = findSharedCacheDyldImage();
const struct symtab_command* symtab = (const struct symtab_command*)findFirstLoadCommand(sharedCacheDyldImage,LC_SYMTAB);
const void *stringTbl = translateOffset(cache, symtab->stroff);
uint32_t off = 0;
while (off < symtab->strsize) {
const char *e = &(stringTbl[off]);
if (e[0] != 0)
printf("STR[%u]=\"%s\"\n", off, e);
off += strlen(e) + 1;
}
return 0;
}

How to fix copy of struct to array of structs segfault

I have the following two structs:
typedef struct {
char* key;
char* value;
} kvpair;
typedef struct {
kvpair ** array;
size_t length;
} kvarray;
And I want to copy new key and value pairs to the kvarray. I use realloc to allocate memory for each new item to be added to the kvpair array but struggling to work out how to copy the key and value.
If I do it like this:
kvs->array resized using realloc
// *** get segfault here!!! how to fix ***
kvs->array[kvs->length]->key = key;
kvs->array[kvs->length]->value = value;
But if I allocate memory separately for a kvpair* and do this way:
kvpair* kvp = malloc(sizeof(kvpair));
// copy key and value
// This below then works
kvs->array[kvs->length] = kvp;
// but there is a memory leak - or seems to be double allocation of memory for same thing
How to do this correctly?
The code is below (see // * get segfault here!!! how to fix * comment)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct {
char* key;
char* value;
} kvpair;
typedef struct {
kvpair ** array;
size_t length;
} kvarray;
kvarray * readKVs(const char** array, size_t length);
void freeKVs(kvarray * pairs);
int main() {
const char* things[] = { "wood=brown\n", "brick=red\n",
"grass=green", "hedge=green", "leaf=green" };
const size_t sz = sizeof(things) / sizeof(things[0]);
kvarray* kvs = readKVs(things, sz);
freeKVs(kvs);
}
kvarray * readKVs(const char** array, size_t length) {
kvarray* kvs = NULL;
for (size_t i = 0; i < length; ++i) {
const char* line = array[i];
if (kvs == NULL) {
kvs = malloc(sizeof(kvarray));
kvs->length = 0;
kvs->array = NULL;
}
char * found = strchr(line, '=');
if (found == NULL) {
// skip to next line
continue;
}
size_t len = strlen(line);
size_t pos = found - array[i];
char* value = NULL;
if (len > (pos + 1)) {
// non-blank value
// length of value is len - pos
value = malloc(len - (pos + 1));
strncpy(value, &line[pos + 1], (len - (pos + 1)) - 1);
// null terminate string
value[len - (pos + 1) - 1] = '\0';
printf("value:'%s'\n", value);
}
char* key = malloc(found - line + 1); // +1 for null terminator
strncpy(key, line, pos);
// remember strncpy bug!
key[found - line] = '\0'; // ensure null termination.
printf("key:'%s', length=%lu\n", key, strlen(key));
/*
// if I allocate an individual pair, then I am duplicating memory so should have to do this below
kvpair* kvp = malloc(sizeof(kvpair));
//kvpair kvp = {NULL, NULL};
printf("about to assign kvs->key = key\n");
kvp->key = key;
printf("about to assign kvs->value = value\n");
kvp->value = value;
*/
kvs->array = realloc(kvs->array, (kvs->length + 1) * sizeof(kvpair*));
// I want to be able to do this 2 lines below - but crashes
// *** get segfault here!!! how to fix ***
kvs->array[kvs->length]->key = key;
kvs->array[kvs->length]->value = value;
kvs->length++;
printf("kvs->length now=%lu\n", kvs->length);
}
return kvs;
}
void freeKVs(kvarray * pairs) {
if (pairs == NULL) {
return;
}
for (size_t i = 0; i < pairs->length; ++i) {
free(pairs->array[i]->key);
free(pairs->array[i]->value);
free(pairs->array[i]);
}
free(pairs);
}
When you do
kvs->array = realloc(kvs->array, (kvs->length + 1) * sizeof(kvpair*));
the contents of the new memory allocated will be indeterminate, it's not initialized. That means the next line
kvs->array[kvs->length]->key = key;
you will dereference an invalid pointer kvs->array[kvs->length]. That of course will lead to undefined behavior.
The solution is of course to make kvs->array[kvs->length] point somewhere valid, for example by doing
kvs->array[kvs->length] = malloc(sizeof(kvpair));

Memory comparison causes system halt

I am working on a kernel module and I need to compare two buffers to find out if they are equivalent. I am using the memcmp function defined in the Linux kernel to do so. My first buffer is like this:
cache_buffer = (unsigned char *)vmalloc(4097);
cache_buffer[4096] = '/0';
The second buffer is from a page using the page_address() function.
page = bio_page(bio);
kmap(page);
write_buffer = (char *)page_address(page);
kunmap(page);
I have printed the contents of both buffers before hand and not only to they print correctly, but they also have the same content. So next, I do this:
result = memcmp(write_buffer, cache_buffer, 2048); // only comparing up to 2048 positions
This causes the kernel to freeze up and I cannot figure out why. I checked the implementation of memcmp and saw nothing that would cause the freeze. Can anyone suggest a cause?
Here is the memcmp implementation:
int memcmp(const void *cs, const void *ct, size_t count)
{
const unsigned char *su1, *su2;
int res = 0;
for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
if ((res = *su1 - *su2) != 0)
break;
return res;
}
EDIT: The function causing the freeze is memcmp. When I commented it out, everything worked. Also, when I did I memcmp as follows
memcmp(write_buffer, write_buffer, 2048); //comparing two write_buffers
Everything worked as well. Only when I throw the cache_buffer into the mix is when I get the error. Also, above is a simplification of my actual code. Here is the entire function:
static int compare_data(sector_t location, struct bio * bio, struct cache_c * dmc)
{
struct dm_io_region where;
unsigned long bits;
int segno;
struct bio_vec * bvec;
struct page * page;
unsigned char * cache_data;
char * temp_data;
char * write_data;
int result, length, i;
cache_data = (unsigned char *)vmalloc((dmc->block_size * 512) + 1);
where.bdev = dmc->cache_dev->bdev;
where.count = dmc->block_size;
where.sector = location << dmc->block_shift;
printk(KERN_DEBUG "place: %llu\n", where.sector);
dm_io_sync_vm(1, &where, READ, cache_data, &bits, dmc);
length = 0;
bio_for_each_segment(bvec, bio, segno)
{
if(segno == 0)
{
page = bio_page(bio);
kmap(page);
write_data = (char *)page_address(page);
//kunmap(page);
length += bvec->bv_len;
}
else
{
page = bio_page(bio);
kmap(page);
temp_data = strcat(write_data, (char *)page_address(page));
//kunmap(page);
write_data = temp_data;
length += bvec->bv_len;
}
}
printk(KERN_INFO "length: %u\n", length);
cache_data[dmc->block_size * 512] = '\0';
for(i = 0; i < 2048; i++)
{
printk("%c", write_data[i]);
}
printk("\n");
for(i = 0; i < 2048; i++)
{
printk("%c", cache_data[i]);
}
printk("\n");
result = memcmp(write_data, cache_data, length);
return result;
}
EDIT #2: Sorry guys. The problem was not memcmp. It was the result of memcmp. When ever it returned a positive or negative number, the function that called my function would play with some pointers, one of which was uninitialized. I don't know why I didn't realize it before. Thanks for trying to help though!
I'm no kernel expert, but I would assume you need to keep this memory mapped while doing the comparison? In other words, don't call kunmap until after the memcmp is complete. I would presume that calling it before will result in write_buffer pointing to a page which is no longer mapped.
Taking your code in the other question, here is a rough attempt at incremental. Still needs some cleanup, I'm sure:
static int compare_data(sector_t location, struct bio * bio, struct cache_c * dmc)
{
struct dm_io_region where;
unsigned long bits;
int segno;
struct bio_vec * bvec;
struct page * page;
unsigned char * cache_data;
char * temp_data;
char * write_data;
int length, i;
int result = 0;
size_t position = 0;
size_t max_size = (dmc->block_size * 512) + 1;
cache_data = (unsigned char *)vmalloc(max_size);
where.bdev = dmc->cache_dev->bdev;
where.count = dmc->block_size;
where.sector = location << dmc->block_shift;
printk(KERN_DEBUG "place: %llu\n", where.sector);
dm_io_sync_vm(1, &where, READ, cache_data, &bits, dmc);
bio_for_each_segment(bvec, bio, segno)
{
// Map the page into memory
page = bio_page(bio);
write_data = (char *)kmap(page);
length = bvec->bv_len;
// Make sure we don't go past the end
if(position >= max_size)
break;
if(position + length > max_size)
length = max_size - position;
// Compare the data
result = memcmp(write_data, cache_data + position, length);
position += length;
kunmap(page);
// If the memory is not equal, bail out now and return the result
if(result != 0)
break;
}
cache_data[dmc->block_size * 512] = '\0';
return result;
}

Resources