I'm having problems trying to save a struct to a new PE section and then reading.
The struct looks like:
#pragma pack(push, 1)
typedef struct _SCRIPT_STRUCT
{
DWORD dwKeySize;
unsigned char *lpKeyBuffer;
DWORD dwScriptSize;
unsigned char *lpScriptBuffer;
} SCRIPT, *PSCRIPT;
#pragma pack(pop)
lpKeyBuffer is a random hex values (0-255) array and lpScriptBuffer contains an encrypted (RC4) script (in Lua if that matters).
I think the struct is successfully written in the new section created but I can't read the buffers.
(Writting):
SCRIPT tScript;
tScript.dwKeySize = KEY_SIZE;
tScript.lpKeyBuffer = new unsigned char[tScript.dwKeySize];
GenerateKey(tScript.lpKeyBuffer, KEY_SIZE);
tScript.dwScriptSize = szScript.size();
tScript.lpScriptBuffer = new unsigned char[tScript.dwScriptSize];
memcpy(tScript.lpScriptBuffer, szScript.c_str(), tScript.dwScriptSize);
tScript.lpScriptBuffer = (unsigned char*)szScript.c_str();
rc4_encryption(tScript.lpScriptBuffer, tScript.dwScriptSize, tScript.lpKeyBuffer, tScript.dwKeySize);
DWORD dwScriptStructSize = sizeof(DWORD) + tScript.dwKeySize + sizeof(DWORD) + tScript.dwScriptSize;
char lpStructBuffer[dwScriptStructSize];
ZeroMemory(lpStructBuffer, dwScriptStructSize);
memcpy(lpStructBuffer, &tScript, dwScriptStructSize);
//CreateFile, create new section, etc
SetFilePointer(hCurrent, LastHeader->PointerToRawData, NULL, FILE_BEGIN);
WriteFile(hCurrent, lpStructBuffer, dwScriptStructSize, &dwRead, 0);
(Reading):
SCRIPT tScript;
memcpy(&tScript, lpScriptBuffer, dwSectionSize);
tScript.lpKeyBuffer = new unsigned char[tScript.dwKeySize];
tScript.lpKeyBuffer[tScript.dwKeySize] = 0x00;
tScript.lpScriptBuffer = new unsigned char[tScript.dwScriptSize];
tScript.lpScriptBuffer[tScript.dwScriptSize] = 0x00;
printf("dwScriptSize = %lu\n", tScript.dwScriptSize);
printf("dwKeySize = %lu\n", tScript.dwKeySize);
rc4_encryption(tScript.lpScriptBuffer, tScript.dwScriptSize, tScript.lpKeyBuffer, tScript.dwKeySize);
printf("script: %s\n", tScript.lpScriptBuffer);
The DWORD outputs are correct but the last printf shows strange symbols.
You can't save pointers to a file from one process, and read them from another process and expect it to work. Pointers are generally unique per process, especially to dynamically allocated data. When you read a pointer from a file from another process (even if it's the same program) that pointer will no longer point to the allocated data, it will just be a "random" stray pointer, and dereferencing it (like you do when printing it as a string) will lead to undefined behavior.
You need to save the string separately from the structure. When reading it's easy since you have the sizes of the variable-length data, and you know where (in relation to the structure) the data is saved.
The comment from shrike made me think and take a closer look at the code you present. It's not complete so this is all guess work, but the actual problem might actually be something different from what I described above.
Lets take a look at a few lines from your "reading" code (which doesn't actually show any reading):
SCRIPT tScript;
memcpy(&tScript, lpScriptBuffer, dwSectionSize);
tScript.lpKeyBuffer = new unsigned char[tScript.dwKeySize];
tScript.lpKeyBuffer[tScript.dwKeySize] = 0x00;
tScript.lpScriptBuffer = new unsigned char[tScript.dwScriptSize];
tScript.lpScriptBuffer[tScript.dwScriptSize] = 0x00;
Now assuming you read the structure into a character buffer lpScriptBuffer (similar to how you use one when writing, not really needed though), then you still have the same problem with the pointers I told about above, but there is another issue: You reassigning the pointers to point to some newly allocated memory. This is all well and good, but the problem here is that you don't actually try to initialize that memory. Not that you really can't with the code you show, but that's beside the point. The problem with you not initializing the memory is precisely that, it's uninitialized and therefore will have an indeterminate contents, seemingly random, and most likely not valid text. Using uninitialized memory is, like dereferencing stray pointers, undefined behavior.
There is also yet another issue: You writing out of bounds of the memory you allocate. As you hopefully knows, indexes in array are zero-based. So if you allocate size bytes then valid indexes are from (and including) 0 to size - 1.
Since you allocate e.g. tScript.dwKeySize bytes of memory then the top index is tScript.dwKeySize - 1 but then you use tScript.dwKeySize as index, which is out of bounds and again will lead to undefined behavior.
You need to allocate tScript.dwKeySize + 1 bytes instead, if the size doesn't already include the string terminator.
Related
I have a file containing the strings of 3 chromosome, which I want to concatenate into one genome. And then I have to access this concatenated string across multiple threads (I use pthread_t). To to this I have to use pthread_mutex_lock when extracting the data, then I use strcat to concatenate the data which are extracted using the function fai_fetch using const char* and then I am saving the data as a char* (see below).
// genome_size the size of all the chromosomes together
// chr_total the number of chromosomes I wish to concatenate
char* genome = (char*) malloc(sizeof(char) * (genome_size+chr_total));
for (int i = 0; i < chr_total; i++){
pthread_mutex_lock(&data_mutex);
const char *data = fai_fetch(seq_ref,chr_names[i],&chr_sizes[i]);
pthread_mutex_unlock(&data_mutex);
//sprintf(&genome[strlen(genome)],data);
strcat(genome,data);
//sprintf(genome+strlen(genome),data); //All three gives conditional jump or move error
//sprintf(genome,data); // THIS SOLVES VALGRIND ISSUE ONE BUT DOES NOT GIVE A CONCATENATED CHAR*
}
All of this works, but then running valgrind I get
Conditional jump or move depends on uninitialized value(s) referring to the "strcat(genome,data); "
and Uninitialized value was created by a heap allocation referring to
"char* genome = (char*) malloc(sizeof(char) * (genome_size+chr_total));"
Based on other StackOverflow answers I tried sprintf(&genome[strlen(genome)],data); and sprintf(genome+strlen(genome),data); instead of strcat. However they too gives the same valgrind message.
The only thing that seems to alleviate this error is using sprintf(genome,data); however then i will not get the full genome but just a single chromosome.
Trying genome += sprintf(genome,data); gives me ./a.out': munmap_chunk(): invalid pointer: and ./a.out': free()
In regards to the "Uninitialized value was created by a heap allocation" error -> then my issue is that I am only able to free that memory after all of the threads are done running. So I am not sure how to initialize the values in the heap allocation when I am using malloc.
Is it possible to solve some of these specific valgrind errors?
Using Valgrind to locate the problematic code
The "Conditional jump or move depends on uninitialised value(s)" message means Valgrind has determined that some result of your program depends on uninitialized memory.
Use the --track-origins=yes flag to track the origin of the uninitialized value. It might help you finding that value. From man 1 valgrind:
When set to yes, Memcheck keeps track of the origins of all uninitialised values. Then, when an uninitialised value error is reported, Memcheck will try to show the origin of the value. An origin can be one of the following four places: a heap block, a stack allocation, a client request, or miscellaneous other sources (eg, a call to brk).
More specifically in your program:
Problem 1: Using uninitialized genome
The line
char* genome = (char*) malloc(sizeof(char) * (genome_size+chr_total));
Allocates the genome buffer using malloc(2) and then consumes it in:
strcat(genome,data);
Please note that functions such as strlen(3) and strcat(3) works on C-strings, which are buffers that terminate with a null character ('\0').
malloc(2) just allocates memory and it doesn't initialize it so your allocated buffer may contain any value (and considered as uninitialized). You should avoid using string related functions with an uninitialized buffers as it results undefined behavior.
Fortunately calloc(2) does the trick - it allocates the buffer and initializes all of its bits to zero, resulting a valid 0 length C-string you can operate on. I suggest the following fix to ensure that genome is initialized:
char* genome = calloc(genome_size+chr_total+1, sizeof(char));
Also note that I've added +1 to the length of the allocated buffer. It is done to guarantee that the resulting genome will end with a null terminator (assuming that genome_size+chr_total is the total size of all the buffers returned from fai_fetch).
Also note that in terms of performance calloc is a bit slower than malloc (because it initializes the data) but for my opinion it is safer as it initializes the whole buffer. For the purposes of your specific program, you could save the performance burden by using malloc and initializing just the first byte:
char* genome = malloc(sizeof(char) * (genome_size + chr_total + 1));
if (NULL == genome) {
perror("malloc of genome failed");
exit(1);
}
// So it will be a valid 0 length c-string
genome[0] = 0;
We don't have to initialize the last byte to be 0 because strcat writes the terminating null character for us.
(Potential) Problem 2: Using potentially non-null terminated data with strcat
As you described in your question, the fai_fetch extracts some data:
const char *data = fai_fetch(seq_ref,chr_names[i],&chr_sizes[i]);
and then consumes it in the strcat line:
strcat(genome,data);
As I wrote above, because you use strcat, data should be null-terminated as well.
I'm not sure how fai_fetch is implemented but if it returns a valid C-string then you're all good.
If it doesn't then you should use strncat which works on buffers that are not null-terminated.
From man 3 strcat:
The strncat() function is similar, except that
it will use at most n bytes from src; and
src does not need to be null-terminated if it contains n or
more bytes.
I suggest the following fix:
// I'm not sure what type `&chr_sizes[i]` is, assuming it's `size_t`
size_t length = &chr_sizes[i];
const char *data = fai_fetch(seq_ref,chr_names[i], length);
// Use strcat
strncat(genome, used_data, length);
This is my code
char *t = type1[j];
int ln = strlen(t);
char *s = new char[ln];
cout<<"ln "<<ln<<" s "<<strlen(s)<<endl;
When I run it:
Why are the lengths different?
When you dynamically allocate an array with new[], you get a pointer to an uninitialized block of memory. You can't call strlen on it, as that function expects a pointer to a character array that contains a null-terminated string. It works by reading each byte in the array until it finds a null byte and returning the count of how many bytes it read before it found a null byte. And since the array is uninitialized, calling strlen does make sense. In fact, it invokes undefined behavior.
There's no way to look at a dynamically allocated buffer and find out how big that buffer is. You need to keep track of the size of the buffer separately. Since you used new char[ln] to create the buffer, you know that you have a buffer large enough to hold ln variables of type char.
When debugging an application I have found in memory a structure that I am 100% certain only consists of 4 strings. Though I am not quite sure how I would convert it to a data structure so I can use the structures pointer address to access values. For example here is what the data struct looks like in memory (as an example lets say it is CONSISTENTLY located at the memory address 0x123456)
The data structureconsists of 4 separate strings
string 1 = ad
string 2 = dgdhkkkkkkhkk
string 3 = ggghhjk
string 4 = dgcfoh
And I have tried creating a data struct like
struct reversedConnectionDat_t
{
char * data1;
char * data2;
char * data3;
char * data4;
}
and this is how I tried accessing the data
reversedConnectionDat_t * storeDat = (reversedConnectionDat_t*)0x123456;
print(storeDat->data3);
But it does not seem to work. Am I not reading the strings from memory properly?
(Oh and the strings will sometimes change from what I posted in the example code posted above, i.e sometimes string 1 will be 7 in length and string 3 will only be 2 in length etc...)
You have a pointer to a structure of pointers so even if you point the structure to the correct memory address, you still have uninitialized pointers inside the structure. You need to provide them with actual memory. I would try setting up your structure like this ...
struct reversedConnectionDat_t
{
char data1 [3];
char data2 [50];
char data3 [50];
char data4 [50];
}
BTW, I didn't count the spaces. I just kind of guessed at it but you get the idea.
I think you've mis-identified that data structure. I suspect that what you have is three independent buffers, each of which can hold one or more null-terminated strings.
The first structure is 68 bytes long and contains "ad\0dgdhkkkkkkhkk\0" (followed by enough \0 to fill the buffer.
It's possible that this buffer is really only 64 bytes long, and that the four bytes after it are used for some other data element.
The second buffer looks to be 64 bytes long, containing a single string and padded with \0 characters to fill out the 64 bytes.
It's impossible to say how long the third buffer is. All we know is that it's long enough to hold the string "dgcfoh\0". I'd guess that the buffer is 64 bytes long, but be willing to revise that opinion if I get more data.
I think the structure you want is:
struct s
{
char data1[68]; // buffer holds one or more null-terminated strings
char data2[64];
char data3[64].
}
Based on the scant information you've given us, that's what I'd start with. Then you need a way to parse a buffer of null-terminated strings. That is, get the two individual strings from the first buffer. That's a pretty easy bit of C code.
I couldn't understand what's wrong with your code except for your magicnumber:0x123456, casting which might not suit your structure. Are you sure your magic-number results in data compatible to the struct defined by you? Like, if you'll try to access storeDat->data3, it'll definitely be leading to seg-fault except you do something as follows or you are very lucky.
struct R{
char *a;
char *b;
};
int main(void)
{
struct R *r1 = (struct R*) malloc(sizeof(struct R));
r1->a = "12333"; //Pointing to a string literal
r1->b = "12331"; //Pointing to a string literal
int address = (int)&r1;
struct R *r2 = (struct R*) address;
std::cout<<r2->b;
return 0;
}
P.S. - I'm not a good programmer. But was just curious to answer, as I thought it might be of some help. Sorry, if I couldn't understand your problem properly.
You are using pointers(char*) and the structure size of your structure is the size of the 4 pointers. If you want to get the strings you should use arrays(char[]) with fixed size.
This will only work if your string size are equal to the buffer size.
IMO the best way is to get the in a char array then find the null terminators
/0 and then configure your pointers to point to the start of each string(at the start and right after the first 3 null terminators).
char* pointerToMem = something; //your strings data
yourStruct.str1 = pointerToMem;
while(*pointerToMem != '\0')
{
pointerToMem++;
}
yourStruct.str2 = pointerToMem + 1;
This is how you can make the struct of pointers work. This code is not optimal and you should not use it as it but it shows how can you get the strings from the memory. To have a C string you only need the address of the first character and some null terminator at the end.
I'm trying to read data from a file but I'm getting a STATUS_STACK_BUFFER_OVERRUN error and the app crashes.
I have a struct:
struct BSPEntities
{
char* ents;
};
And I'm reading the file:
BSPEntities entities
ifstream mapfile;
int size = 54506;
int offset = 5182600;
entities.ents = new char[size];
mapfile.seekg(offset, ios::beg);
mapfile.read((char *)(&entities.ents), size);
"size" and "offset" are values loaded from the file and known to be valid. I have preprocessor directives #pragma pack(1) and #pragma push around the BSPEntities struct.
Thanks.
&entities.ents is a pointer to a pointer to char. The object pointed to (a pointer to char) is probably only 4 or 8 bytes depending on the architecture you're targeting, but you're trying to write 54,506 bytes to it. Obviously 54,506 is larger than 8, so you're writing past the end of the pointer, and the behavior is undefined.
That read should just be mapfile.read(entities.ents, size);
Also you don't need to mess around with #pragma pack here, unless there's something more complicated going on that you're not showing.
mapfile.read((char *)(&entities.ents), size);
Should be
mapfile.read(entities.ents, size);
Instead of passing the address of the heap memory block that ents points to, you are passing the address of ents itself. And since ents is being allocated on the stack, you are reading bytes onto the stack until it overruns.
I am having an issue with a function that concatenates a number to the end of a char array. I honestly can't see the issue:
void x(int num, char* originalArray) {
char* concat_str = new char[1];
sprintf(concat_str, "%d", num);
for (int i = 0; i < 1; i++)
originalArray[i + 10] = concat_str[i];
delete [] concat_str;
}
The error message is:
HEAP CORRUPTION DETECTED: after Normal block (#147) at 0x01204CA0. CRT detected that the application wrote to the memory after the end of heap buffer.
Any ideas? I'm a beginning programmer, but I've done this same kind of thing many times and never had this issue. Thanks.
concat_str needs to be large enough to hold the number of digits in num plus a null terminator. Since it size is one you only have enough room for the null terminator. Trying to add anything else is undefined behavior as it accesses memory you do not own and causing the heap corruption.
You're allocating one byte for concat_str, and sprintf'ing something that requires more space than that.
First of all, note that your API is a C api. If you want a dynamic array in C++, use std::vector<char>.
But, assuming you need to stick to the C API, there's no way to guarantee that your originalArray is large enough to hold the result. Furthermore, the temporary buffer is unnecessary.
You should modify the API and the implementation as follows:
Take the size of the destination, to guarantee that it doesn't write past its end.
Write the string in place in the destination buffer. Putting it into a temporary buffer and then copying to the destination is a waste of time.
Use snprintf, not sprintf. The latter is not safe: you can't guarantee it won't write past the end of your buffer.
You should assert the precondition that the offset is at least smaller than the destination size.
If the precondition holds, the destination will be always properly zero-terminated, although the text representation of num might not fit in it.
You can return the length of the destination that is necessary for the value to fit.
Thus:
size_t fun(int num, char * dest, size_t dest_size) {
const size_t offset = 10;
assert(dest_size > offset);
return offset + snprintf(dest + offset, dest_size - offset, "%d", num);
}