Template Class Type Sizing - c++

I have written a template class for a circular buffer:
template <class T> class CRingBuffer { /* ... */ };
Some of the operations this class performs rely on an accurate evaluation of the size of T. This seems to work okay when T is BYTE (i.e. sizeof(T) == 1, check). However, when I try to use the same class where T is DWORD, for some reason sizeof(T) evaluates to 16. The last time I checked, a double-word is 4 bytes, not 16. Does anyone know why this is happening? Thanks.
ADDITIONAL INFO
I can't post all the code due to its proprietary nature, but here is the class declaration and the function definition in question:
template <class T> class CRingBuffer
{
#pragma pack( push , 1 ) // align on a 1-byte boundary
typedef struct BUFFER_FLAGS_tag
{
T * pHead; // Points to next buffer location to write
T * pTail; // Points to next buffer location to read
BOOL blFull; // Indicates whether buffer is full.
BOOL blEmpty; // Indicates whether buffer is empty.
BOOL blOverrun; // Indicates buffer overrun.
BOOL blUnderrun; // Indicates buffer underrun.
DWORD dwItemCount; // Buffer item count.
} BUFFER_FLAGS, *LPBUFFER_FLAGS;
#pragma pack( pop ) // end 1-byte boundary alignment
// Private member variable declarations
private:
T * m_pBuffer; // Buffer location in system memory
T * m_pStart; // Buffer start location in system memory
T * m_pEnd; // Buffer end location in system memory
BUFFER_FLAGS m_tFlags; // Buffer flags.
DWORD m_dwCapacity; // The buffer capacity.
// CRingBuffer
public:
CRingBuffer( DWORD items = DEFAULT_BUF_SIZE );
~CRingBuffer();
// Public member function declarations
public:
DWORD Add( T * pItems, DWORD num = 1, LPDWORD pAdded = NULL );
DWORD Peek( T * pBuf, DWORD num = -1, DWORD offset = 0, LPDWORD pWritten = NULL );
DWORD Delete( DWORD num, LPDWORD pDeleted = NULL );
DWORD Remove( T * pBuf, DWORD num = 1, LPDWORD pRemoved = NULL );
void Flush( void );
DWORD GetItemCount( void );
BYTE GetErrorStatus( void );
// Private member function declarations
private:
void IncrementHead( LPBUFFER_FLAGS pFlags = NULL );
void IncrementTail( LPBUFFER_FLAGS pFlags = NULL );
};
template <class T> void CRingBuffer<T>::IncrementHead( LPBUFFER_FLAGS pFlags )
{
ASSERT(this->m_pBuffer != NULL);
ASSERT(this->m_pStart != NULL);
ASSERT(this->m_pEnd != NULL);
ASSERT(this->m_tFlags.pHead != NULL);
ASSERT(this->m_tFlags.pTail != NULL);
pFlags = ( pFlags == NULL ) ? &(this->m_tFlags) : pFlags;
// Verify overrun condition is not set.
if ( pFlags->blOverrun == FALSE )
{
pFlags->pHead += sizeof(T); // increament buffer head pointer
pFlags->blUnderrun = FALSE; // clear underrun condition
// Correct for wrap condition.
if ( pFlags->pHead == this->m_pEnd )
{
pFlags->pHead = this->m_pStart;
}
// Check for overrun.
if ( pFlags->pHead == pFlags->pTail )
{
pFlags->blOverrun = TRUE;
}
}
}
The problem described above occurs when pFlags->pHead += sizeof(T); of IncrementHead is executed.

Oh, this is really simple after all :)
Without realising it, in pFlags->pHead += sizeof(T); you use pointer arithmetic. pHead is a pointer to T, and when you increase it by sizeof(T), it means you move it forward by that many elements of type T, and not by that many bytes as you thought. So the size of T gets squared. If your goal is to move the pointer to the next element of the buffer, you should just increment it by 1: pFlags->pHead += 1;

Related

DbgHelp: Wrong address of function parameter when it is a pass-by-value symbol on x64

I am using the Windows DbgHelp library to dump a callstack of my C++ application. The PDB is in the right place and I am successfully reporting the stack frames. I have an involved type traversal system that prints out all of the locals and this is mostly working. However, in some cases I am getting the wrong address and causing access violations. One case is when a function is passed an object by value:
struct Object { float x,y,z; }
void foo( Object objectByValue)
{
// dump callstack
}
In this case, the address calculated for objectByValue is wrong. It is near the correct place on the stack, but not exactly. I am having some difficulties finding information on the right address. I am doing the following:
Set the correct context with SymSetContext(...)
Invoke SymEnumSymbols with a callback
Inside the callback, check if SYMFLAG_REGREL is set
Assign Address = SymInfo->Address + context.rbp or context.rsp depending on
the SymInfo.Register value (CV_AMD64_RBP or CV_AMD64_RSP are only
ever present )
Then I use that address to access the variable.
For variables on the stack this address is correct, as it is for most other cases. However, it is not in some, including this case.
I have included a working example below with the following output:
main-> Address of on stack: 000000000020B0D0 = { 1.000000, 2.000000,
3.000000 }
foo-> Address of parameters: 000000000020D6F8 = { 1.000000, 2.000000, 3.000000 }
Print stack from bottom up:
Frame: foo Variable: objByValue offset=0xe0 address=0x20b090 size=8204
Frame: main Variable: objOnStack offset=0x10 address=0x20b0d0 size=8204
You can see in the example that the address calculate from the variable on the stack is correct, but for the pass by value it is wrong.
Does anyone have any insight on how I can correctly calculate this value?
#include "stdafx.h"
#include <windows.h>
#include <stdint.h>
#pragma comment(lib, "dbghelp.lib")
#pragma pack( push, before_imagehlp, 8 )
#include <imagehlp.h>
#pragma pack( pop, before_imagehlp )
// Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL')
#define USED_CONTEXT_FLAGS CONTEXT_FULL
#if defined(_M_AMD64)
const int ImageFileMachine = IMAGE_FILE_MACHINE_AMD64;
#else
const int ImageFileMachine = IMAGE_FILE_MACHINE_I386;
#endif
struct BaseAddresses
{
uint64_t Rsp;
uint64_t Rbp;
};
const int C_X64_REGISTER_RBP = 334; // Frame Base Pointer register
const int C_X64_REGISTER_RSP = 335; // Stack Pointer register (common in release builds with frame pointer removal)
BOOL EnumSymbolsCallback(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext)
{
BaseAddresses * pBaseAddresses = (BaseAddresses*)UserContext;
ULONG64 base = 0;
if ((pSymInfo->Flags & SYMFLAG_REGREL) != 0)
{
switch (pSymInfo->Register)
{
case C_X64_REGISTER_RBP:
base = (ULONG64)pBaseAddresses->Rbp;
break;
case C_X64_REGISTER_RSP:
base = (ULONG64)pBaseAddresses->Rsp;
break;
default:
exit(0);
}
}
ULONG64 address = base + pSymInfo->Address;
printf("Variable: %s offset=0x%llx address=0x%llx size=%lu\n", pSymInfo->Name, pSymInfo->Address, address, pSymInfo->Size);
return TRUE;
}
DWORD DumpStackTrace()
{
HANDLE mProcess = GetCurrentProcess();
HANDLE mThread = GetCurrentThread();
if (!SymInitialize(mProcess, NULL, TRUE)) // load symbols, invasive
return 0;
CONTEXT c;
memset(&c, 0, sizeof(CONTEXT));
c.ContextFlags = USED_CONTEXT_FLAGS;
RtlCaptureContext(&c);
// SYMBOL_INFO & buffer storage
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
STACKFRAME64 frame;
memset(&frame, 0, sizeof(STACKFRAME64));
DWORD64 displacement_from_symbol = 0;
printf("Print stack from bottom up:\n");
int framesToSkip = 1; // skip reporting this frame
do
{
// Get next stack frame
if (!StackWalk64(ImageFileMachine, mProcess, mThread, &frame, &c, nullptr, SymFunctionTableAccess64, SymGetModuleBase64, nullptr))
{
break;
}
// Lookup symbol name using the address
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
if (!SymFromAddr(mProcess, (ULONG64)frame.AddrPC.Offset, &displacement_from_symbol, pSymbol))
return false;
if (framesToSkip > 0)
{
framesToSkip--;
continue;
}
printf("Frame: %s\n", pSymbol->Name);
// Setup the context to get to the parameters
IMAGEHLP_STACK_FRAME imSFrame = { 0 };
imSFrame.InstructionOffset = frame.AddrPC.Offset;
if (!SymSetContext(mProcess, &imSFrame, NULL))
return false;
BaseAddresses addresses;
addresses.Rbp = c.Rbp;
addresses.Rsp = c.Rsp;
if (!SymEnumSymbols(mProcess, 0, 0, EnumSymbolsCallback, &addresses))
{
return false;
}
if (strcmp(pSymbol->Name, "main") == 0)
break;
} while (frame.AddrReturn.Offset != 0);
SymCleanup(mProcess);
return 0;
}
struct Structure
{
float x, y, z;
};
void foo(Structure objByValue)
{
printf("foo-> Address of parameters: %p = { %f, %f, %f }\n", &objByValue, objByValue.x, objByValue.y, objByValue.z);
DumpStackTrace();
}
int main()
{
Structure objOnStack = { 1, 2, 3 };
printf("main-> Address of on stack: %p = { %f, %f, %f }\n", &objOnStack, objOnStack.x, objOnStack.y, objOnStack.z);
foo(objOnStack);
return 0;
}
After reading the documentation on X64 calling convention I discovered the following sentence:
Any argument that doesn’t fit in 8 bytes, or isn't 1, 2, 4, or 8
bytes, must be passed by reference 1
So that explains the funny address - what the debug symbols are giving me is the address of the memory storing the reference to the full data. So my code flow essentially says:
if ( symbol is a parameter and the size > 8 )
address = *(uint64_t)address; // dereference
And then passing that address through my type system resolves correctly.
I thought other people might find this useful as it is not documented anywhere in the DbgHelp library, and while some people might understand the calling conventions, it didn't occur to me that the symbol data passed back wouldn't contain something helpful to indicate this.

Access Violation exception before entering into a function

I have this function which simply encrypts a string (this function works fine, and tested).
DWORD SomeObj::Encrypt(string * To_Enc) {
DWORD text_len = (To_Enc->length());
if (!CryptEncrypt(this->hKey,
NULL, // hHash = no hash
1, // Final
0, // dwFlags
(PBYTE)(*To_Enc).c_str(), //*pbData
&text_len, //*pdwDataLen
128)) { //dwBufLen
return SERVER_ERROR;
}
return SERVER_SUCCESS;
}
And I have this piece of code:
string s= "stringTest";
Encrypt(&s);
which simply call the function passing the pointer of a string.
The program is causing an access violation exception right when it calls the function Encrypt(&s), I guess that it's something about the parameter &s being passed but I can't figure this out. Any idea from your experience ?
This answer will reiterate important points already made in the comments, with example code.
Your current code:
DWORD SomeObj::Encrypt(string * To_Enc) {
DWORD text_len = (To_Enc->length());
if (!CryptEncrypt(this->hKey,
NULL, // hHash = no hash
1, // Final
0, // dwFlags
(PBYTE)(*To_Enc).c_str(), //*pbData
&text_len, //*pdwDataLen
128)) { //dwBufLen
return SERVER_ERROR;
}
return SERVER_SUCCESS;
}
On the line:
(PBYTE)(*To_Enc).c_str(), //*pbData
Note that you are casting away const-ness from the pointer value returned from the c_str() method call.
This should immediately be a red flag; there may be times when casting away const-ness is a valid use case, but it is more the exception than the rule.
Untested, but using a temporary, mutable buffer should solve your problem, such as:
#include <cstddef>
#include <vector>
...
DWORD SomeObj::Encrypt(string * To_Enc) {
std::vector<std::string::value_type> vecBuffer(To_Enc->length() * 3, 0); // use the maximum value that could be output, possibly some multiple of the length of 'To_Enc'
std::size_t nIndex = 0;
for (auto it = To_Enc->cbegin(); it != To_End->cend(); ++it)
{
vecBuffer[nIndex++] = *it;
}
DWORD text_len = (To_Enc->length());
if (!CryptEncrypt(this->hKey,
NULL, // hHash = no hash
1, // Final
0, // dwFlags
reinterpret_cast<PBYTE>(&vecBuffer[0]), //*pbData
&text_len, //*pdwDataLen
vecBuffer.size())) { //dwBufLen
return SERVER_ERROR;
}
To_Enc->assign(&vecBuffer[0], text_len); // assumes 'text_len' is returned with the new length of the buffer
return SERVER_SUCCESS;
}

Debugging software that can check for NULL dereferences?

Is there software smart enough to figure out that you got a pointer from somewhere and the returned pointer could be NULL and no where in the block do you do:
ptr = getSomeDataThatCouldReturnNULLAt(-1);
...
if(ptr)
{
//code
}
or
if(!ptr)
{
return;
}
Is there software that can let you know all the places where this might not be checked?
Thanks
Checking for runtime problems.
the better way to code this would be as follows :
s32 getSomeDataThatCouldReturnNULLAt( s32 intParam, void **inputPointer);
and then in your function where you want to invoke this function :
s32 returnValue = 0 ;
void * ptr = NULL ;
if((returnValue = getSomeDataThatCouldReturnNULLAt( -1, &ptr) ) != ERROR ||
ptr ==NULL )
return returnValue;
returnValue can indicate the error that occured in your getSomeDataThatCouldReturnNULLAt

Resource instead of external file C++

I am reusing some old code(originally developed on c, not c++) with some functions to open/read/manipulate text-files. The path to the text-files is passed to the functions as a string (char*) then opened using: FileToUse = fopen(filename, "rb"); then multiple calls to fread() and fseek() are used. This code is known to work for external text-files, but now I would like to include the textfiles as resources in my project (MFC C++ in visual studio).
I found some examples on the web on how to use resources rusulting in this code:
HINSTANCE hInst = AfxGetResourceHandle();
HRSRC hResource = FindResource(hInst, MAKEINTRESOURCE(IDR_TEXTFILE1), "TEXTFILE");
if (hResource){
HGLOBAL hLoadedResource = LoadResource(hInst, hResource);
if (hLoadedResource){
const char* pResource = LockResource(hLoadedResource);
if (pResource){
DWORD dwResourceSize = SizeofResource(hInst, hResource);
if (0 != dwResourceSize){ // if(FileToUse){
memcpy(&Buffer, pResource, (15 * 2)); // fread($Buffer, 15, 2, FileToUse);
pTemp = pResource + 200; // fseek(FileToUse, 200, SEEK_SET);
pTemp = pTemp + 100; // fseek(FileToUse, 100, SEEK_CUR);
pTemp = pResource + (dwResourceSize - 1) - 40; // fseek(FileToUse, -40, SEEK_END);
}
}
}
}
I replaced the fread call by memcpy() as shown, but I'm missing the return value of fread (actual read items) and in the original code the filepointer was moved by fseek, I wonder whether my approach using a temporary pointer is correct.
My ultimate goal is to simulate the fread and fseek calls for resources with similar function prototypes:
size_t resread( void* buffer, size_t size, size_t count, char* resource );
int resseek( char* resource, long offset, int origin );
Any suggestions are much appreciated.
Thanks for your help, based on the Agent_L's suggestion this is what I came up with:
Text-resource type:
struct _resource {
const char * content; // File content
size_t size; // File size
size_t ptrloc; // 'Pointer' location
};
typedef struct _resource RES_TXT;
resread based on fread:
size_t resread( void* buffer, size_t size, size_t count, RES_TXT * resource)
{
size_t actualCount = ( resource->size - resource->ptrloc ) / size;
actualCount = min( count, actualCount );
if ( actualCount <= 0 ) return 0;
memcpy(buffer, (resource->_ptr + resource->ptrloc), (actualCount * size) );
resource->ptrloc += (actualCount * size);
return actualCount;
}
and to complete resseek based on fseek:
int resseek( RES_TXT * resource, long offset, int origin ) {
size_t nextloc;
switch ( origin ) {
case SEEK_SET: nextloc = 0;
break;
case SEEK_CUR: nextloc = resource->ptrloc;
break;
case SEEK_END: nextloc = resource->size;
break;
default: return -1;
}
nextloc += offset;
if ( nextloc >= 0 && nextloc < resource->size )
resource->ptrloc = nextloc;
else
return -1;
return 0;
}
Any call to fseek and fread can now be replaced to use a resource instead of an external file.
The file handle contains not only the data but also it's length and current position. You have to duplicate that.
(handwirtten code, unproven):
struct resFile
{
char* pData;
int iLenght;
int iCurrPosition;
};
size_t resread( void* buffer, size_t size, size_t count, resFile* resource)
{
int ActualRead = min(size*count, resource->iLenght - resource->iCurrPosition);
memcpy(buffer, resource->pData + resource->iCurrPosition, ActualRead);
resource->iCurrPostion += ActualRead;
return ActualRead;
}
Let me notify you that fread shifts current file position. This means that you don't need invoke fseek each time. From this perspective may be you code can avoid implementation of resseek by simple increasing Buffer pointer

Why I got crash when allocating buffer?

I am developing a driver with Filter. So when I write the SendNetBufferListsComplete function in filter.cpp I got a crash (bluescreen). WinDbug pointed to some buffer allocation. The code is here:
Edited:
sendNetBufferListsComplete(
IN PNET_BUFFER_LIST NetBufferLists,
IN ULONG SendCompleteFlags) {
PNET_BUFFER_LIST pNetBufferList = NetBufferLists;
PNET_BUFFER_LIST pNextNetBufferList = NULL;
while (pNetBufferList)
{
pNextNetBufferList = NET_BUFFER_LIST_NEXT_NBL(pNetBufferList);
NET_BUFFER_LIST_NEXT_NBL(pNetBufferList) = NULL;
PNET_BUFFER_LIST pParentNetBufferList = pNetBufferList->ParentNetBufferList;
if (pParentNetBufferList != NULL)
{
NDIS_STATUS status = NET_BUFFER_LIST_STATUS(pNetBufferList);
NdisFreeNetBufferList(pNetBufferList);
if (NdisInterlockedDecrement(&pParentNetBufferList->ChildRefCount) == 0) {
NET_BUFFER_LIST_STATUS(pParentNetBufferList) = status;
NdisFSendNetBufferListsComplete(m_hFilter, pParentNetBufferList, SendCompleteFlags);
}
}
else
{
if(pNetBufferList != NULL)
{
**---windbug pointed here---****
PVOID pBuffer = *(PVOID*) NET_BUFFER_LIST_CONTEXT_DATA_START(pNetBufferList);
PMDL pMdl = NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pNetBufferList));
if(pMdl)
NdisFreeMdl(pMdl);
if(pBuffer)
delete[] (UCHAR*) pBuffer;
NdisFreeNetBufferList(pNetBufferList);
}
}
NdisInterlockedDecrement(&m_nSendNetBufferListCount);
pNetBufferList = pNextNetBufferList;
}
What is the actual problem? Is it overflow? Or NULL check problems?
In ndish.h
#define NET_BUFFER_LIST_CONTEXT_DATA_START(_NBL) ((PUCHAR)(((_NBL)->Context)+1)+(_NBL)->Context->Offset)
like this . and in Wdm.h
//
// I/O system definitions.
//
// Define a Memory Descriptor List (MDL)
//
// An MDL describes pages in a virtual buffer in terms of physical pages. The
// pages associated with the buffer are described in an array that is allocated
// just after the MDL header structure itself.
//
typedef
_Struct_size_bytes_(_Inexpressible_(sizeof(struct _MDL) + // 747934
(ByteOffset + ByteCount + PAGE_SIZE-1) / PAGE_SIZE * sizeof(PFN_NUMBER)))
struct _MDL {
struct _MDL *Next;
CSHORT Size;
CSHORT MdlFlags;
struct _EPROCESS *Process;
PVOID MappedSystemVa; /* see creators for field size annotations. */
PVOID StartVa; /* see creators for validity; could be address 0. */
ULONG ByteCount;
ULONG ByteOffset;
} MDL, *PMDL;