gpt4 book ai didi

c++ - 使用 std vector 作为库中存储的缓冲区和在另一个库中使用此缓冲区的困难

转载 作者:行者123 更新时间:2023-11-28 00:55:18 25 4
gpt4 key购买 nike

我有一个名为 IBuffer 的类,它使用 std::vector 作为 unsigned char 数据的存储。这个类是我名为 core.lib 的基础库的一部分。此类的职责是将数据写入缓冲区并从中读取。好的现在我在另一个库中使用这个类来序列化和反序列化从网络接收的消息。

当我尝试将新数据推回 std::vector 时,我总是遇到内存访问冲突读取位置 0Xxxxxxx 的问题。因为很难在这里写上千行代码,所以我把堆栈跟踪放在这里,我希望有人能帮助我解决这个问题。

        ntdll.dll!@RtlpLowFragHeapFree@8()  + 0x2c bytes    
ntdll.dll!_RtlFreeHeap@12() + 0x7e bytes
kernel32.dll!_HeapFree@12() + 0x14 bytes
msvcr100d.dll!__free_base() + 0x29 bytes
msvcr100d.dll!__free_dbg_nolock() + 0x4ae bytes
msvcr100d.dll!__free_dbg() + 0x50 bytes
msvcr100d.dll!operator delete() + 0xb9 bytes
> ICore.dll!std::allocator<unsigned char>::deallocate(unsigned char * _Ptr=0x002c7810, unsigned int __formal=1) Line 182 + 0x9 bytes C++
ICore.dll!std::vector<unsigned char,std::allocator<unsigned char> >::_Insert_n(std::_Vector_const_iterator<std::_Vector_val<unsigned char,std::allocator<unsigned char> > > _Where=221 'Ý', unsigned int _Count=2, const unsigned char & _Val='') Line 1375 C++
ICore.dll!std::vector<unsigned char,std::allocator<unsigned char> >::insert(std::_Vector_const_iterator<std::_Vector_val<unsigned char,std::allocator<unsigned char> > > _Where=221 'Ý', unsigned int _Count=1, const unsigned char & _Val='') Line 1060 C++
ICore.dll!Utils::IBuffer::WriteShort(unsigned short data=256) Line 63 + 0x56 bytes C++
ICore.dll!Serialization::IBufferWriter::writeUShort(unsigned short data=256) Line 82 C++
IRNet.dll!IRNetwork::IStunMessage::AcceptWriter(Serialization::IIWriter * writer=0x0040f080) Line 340 + 0x2e bytes C++
IRNet.dll!Serialization::IBufferWriter::WriteObject<IRNetwork::IStunMessage>(const Object::IObject * object=0x002cb5f0) Line 105 + 0x17 bytes C++
IRNet.dll!IRNetwork::IStunMessage::Serialize(Object::SharedPtr<Utils::IBuffer> buffer={...}) Line 769 C++
IRNet.dll!IRNetwork::IStun::SendUnReliably(IRNetwork::IStunMessage * message=0x002cb5f0) Line 157 C++
IRNet.dll!IRNetwork::IStun::SendBind() Line 61 + 0xc bytes C++
IRNet.dll!IRNetwork::IStun::Bind(unsigned int localfd=184) Line 48 C++
IRNet.dll!IRNetwork::INatContext::StunBind(unsigned int fd=184) Line 52 + 0xc bytes C++
testDhcpv4.exe!TestStunAttribute::Start() Line 48 + 0x24 bytes C++
testDhcpv4.exe!wmain(int argc=1, wchar_t * * argv=0x002c71d8) Line 69 C++
testDhcpv4.exe!__tmainCRTStartup() Line 552 + 0x19 bytes C
testDhcpv4.exe!wmainCRTStartup() Line 371 C
kernel32.dll!@BaseThreadInitThunk@12() + 0x12 bytes
ntdll.dll!___RtlUserThreadStart@8() + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x1b bytes

IBUffer.h

#include "stdafx.h"
#include "ICoreConfig.h"
#include "ILMutex.hxx"
#include "ILock.hxx"
#include <vector>
using namespace IThreading;
using namespace std;
namespace Utils
{
/*
#ifdef EXP_STL
# define DECLSPECIFIER __declspec(dllexport)
# define EXPIMP_TEMPLATE
#else
# define DECLSPECIFIER __declspec(dllimport)
# define EXPIMP_TEMPLATE extern
#endif

EXPIMP_TEMPLATE template class DECLSPECIFIER std::vector<unsigned char>;*/

template class ICORE_API std::allocator<unsigned char>;
template class ICORE_API std::vector<unsigned char,std::allocator<unsigned char> >;
/// <summary>
///
/// </summary>
typedef enum
{
/*Begin Of Buffer*/
BOB = 0,
/*End Of Buffer*/
EOB = 1,
/*Unknown*/
UNK = 2
} BufferState_t;
class ICORE_API IBuffer
{
public:
IBuffer(void);
IBuffer(IBuffer* newbuff);
~IBuffer(void);
//Methods
int Write(const void* data,size_t size);
int Write(const void** data, size_t sz);
int Write(size_t position , const void* data,size_t sz);
int WriteShort(unsigned short data);
int WriteShort(uint32_t position,unsigned short data);
int WriteByte(unsigned char data);
int WriteUInt(unsigned int data);
int WriteUlong(unsigned long data);



//************************************
// Method: ReadByte
// FullName: BufferPool::ReadByte
// Access: public
// Returns: unsigned char
// Qualifier:
//Description: Read and return one byte of data by starting from begining of buffer
//************************************
unsigned char ReadByte();
unsigned short ReadShort();
unsigned int ReadUint32();
unsigned long ReadUlong();
unsigned char* Read(size_t sz);

/** Converts a 16-bit value from host to TCP/IP network byte order (big-endian).
* @param x The 16-bit (in host byte order) value to convert.
* @retval @a x in TCP/IP network byte order.
*/
unsigned short HostToNetworkByteOrder(unsigned short x);

/* Memory alignment hack */
//************************************
// Method: HostToNetworkByteOrder
// FullName: BufferPool::HostToNetworkByteOrder
// Access: public
// Returns: unsigned short
// Qualifier:
// Parameter: const void * px
// Description: This method used when we want to Pars existing buffer
//************************************
unsigned short HostToNetworkByteOrder(const void* px);

unsigned short NetworkToHostByteOrder(const unsigned short x);

/** Converts a 32-bit value from host to TCP/IP network byte order (big-endian).
* @param x The 32-bit (in host byte order) value to convert.
* @retval @a x in TCP/IP network byte order.
*/
unsigned long HostToNetworkByteOrder(unsigned long x);

/* Memory alignment hack */
//************************************
// Method: HostToNetworkByteOrderUL
// FullName: BufferPool::HostToNetworkByteOrderUL
// Access: public
// Returns: unsigned long
// Qualifier:
// Parameter: const void * px
// Description: this method used when we want to pars existing buffer
//************************************
unsigned long HostToNetworkByteOrderUL(const void* px);
//* parse unsigned int type to byte array as is
vector<unsigned char> Uint32ToByteArray(unsigned int x);

uint8_t* ToUInt8ptr();

unsigned long NetworkToHostByteOrder(const unsigned long x);


/* IBuffer operator =(const IBuffer &buf);*/
IBuffer& operator =(IBuffer &Rhs);
IBuffer& operator =(char* rhs);

operator char*();
operator void*();
operator uint8_t*();

//************************************
// Method: operator++
// FullName: BufferPool::operator++
// Access: public
// Returns: BufferPool
// Qualifier:
// Description: This method increment dataPtr
// read one byte , increment dataPtr by one
// read short , increment dataPtr by two
// read unsigned int increment dataPtr by 4
// note : each read function set currPosion in suitable way
// we do this because of continuous buffer reading
//************************************
void operator ++();
bool operator<(const IBuffer& buff)
{
return this->Size() < buff.Size() ? true : false;
}

bool operator==(const IBuffer& buff)
{
return this->buffer == buff.buffer;
}
//Properties
bool IsEmpty();
unsigned char* Value();

/** Indicates whether we are on a Big Endian host or not.<br>
* IMPORTANT: Before calling this function, you should initialize the network stack by using
* @ref tnet_startup().
* @retval @a true if the program is running on a Big Endian host and @a false otherwise.
*/
bool IsBigEndian();
inline unsigned char HI_Uint16(unsigned short x)
{
return (((x) >> 8) & 0xFF) ;
}
inline unsigned char LOW_Uint16(unsigned short x)
{
return ((x) & 0xFF);
}
size_t Size() const;
void SetPtr();

void CleanUp();

void Move(int32_t count);
private:
inline int GetPosition()
{
return currPosition;
}

int SetPosition(int newpos);
public:
static class _Convert
{
public:
static inline unsigned short ToUShort(const unsigned char* u8_ptr)
{
return (((unsigned short)(u8_ptr)[0]) | ((unsigned short)(u8_ptr)[1])<<8);
}
static inline unsigned int ToUint32(const unsigned char* u8_ptr)
{
return (((unsigned int)(u8_ptr)[3]) | ((unsigned int)(u8_ptr)[2])<<8 | ((unsigned int)(u8_ptr)[1])<<16 | ((unsigned int)(u8_ptr)[0])<<24);
}

static inline signed int ToInt32(const unsigned char* u8_ptr)
{
return (((signed int)(u8_ptr)[0]) | ((signed int)(u8_ptr)[1])<<8 | ((signed int)(u8_ptr)[2])<<16 | ((signed int)(u8_ptr)[3])<<24);
}
protected:

private:
} Convert;
static BufferState_t bstate;
Mutex mMutex;
private:
vector<unsigned char> buffer;
vector<unsigned char>::pointer dataPtr;
int currPosition;
bool ptrSet;
};
}

IBuffer.cpp

    #include "StdAfx.h"
#include "IBufferPool.h"
#include <iostream>
namespace Utils
{

IBuffer::IBuffer(void)
: currPosition(0), ptrSet(false)
{
/*buffer.push_back('\0');*/
SetPtr();
}

IBuffer::IBuffer( IBuffer* newbuff )
:currPosition(0)
{
}

IBuffer::~IBuffer(void)
{
if (GetPosition() != 0)
{
dataPtr = buffer.data();
}

buffer.clear();
dataPtr = NULL;
SetPosition(0);
/*std::cout<<"Ibuffer Freed \n";*/
}

//************************************
// Method: WriteByte
// FullName: BufferPool::WriteByte
// Access: public
// Returns: int
// Qualifier:
// Parameter: unsigned char data
// Description: write data of type byte in to buffer
//************************************
int IBuffer::WriteByte(unsigned char data)
{
Lock lock(mMutex);
buffer.push_back(data);
SetPtr();
return 0;
}

//tested OK
int IBuffer::WriteShort(unsigned short data)
{
Lock lock(mMutex);
unsigned char temp;
//first we convert to network byte order
/*unsigned short tmpData = HostToNetworkByteOrder(data);*/
//lower byte

temp = LOW_Uint16(/*tmpData*/data);
//buffer.push_back(temp); /// Access violation
buffer.insert(buffer.end(),1,temp);
temp = HI_Uint16(/*tmpData*/data);
//buffer.push_back(temp); /// Access violation
buffer.insert(buffer.end(),1,temp);
SetPtr();
return 0;
}

int IBuffer::WriteShort( uint32_t position,unsigned short data )
{
Lock lock(mMutex);
vector<unsigned char>::pointer pt = buffer.data();
pt+=position;

*pt=LOW_Uint16(data);
pt++;
*pt=HI_Uint16(data);
SetPtr();
return 0;
}

int IBuffer::WriteUInt(unsigned int data)
{
Lock lock(mMutex);
//unsigned int and unsigned long both have 4 byte length except that unsigned long can accept floating point numbers

vector<unsigned char> vt = Uint32ToByteArray(data);

for each(const unsigned char &i in vt)
{
buffer.push_back(i);
}
SetPtr();
return 0;
}

int IBuffer::WriteUlong( unsigned long data )
{
Lock lock(mMutex);
return WriteUInt(data);
}

vector<unsigned char> IBuffer::Uint32ToByteArray(unsigned int x)
{
Lock lock(mMutex);
vector<unsigned char> arrayOfByte(4);
for (int i = 0; i < 4; i++)
arrayOfByte[3 - i] = (x >> (i * 8));
return arrayOfByte;
}

uint8_t* IBuffer::ToUInt8ptr()
{
Lock lock(mMutex);
uint8_t* u8arr = (uint8_t*)this->buffer.data();
size_t sz = this->buffer.size();
u8arr[sz] = '\0';
return u8arr;
}

bool IBuffer::IsEmpty()
{
if(!buffer.size())
return true;
return false;
}


unsigned char* IBuffer::Value()
{
if(!dataPtr)
{
dataPtr = buffer.data();
}
return dataPtr;
}


unsigned short IBuffer::HostToNetworkByteOrder(unsigned short x)
{
Lock lock(mMutex);
if(IsBigEndian()){
return x;
}
else{
return ((((unsigned short)(x) & 0xff00) >> 8) |
(((unsigned short)(x) & 0x00ff) << 8));
}
}


unsigned short IBuffer::HostToNetworkByteOrder(const void* px)
{
Lock lock(mMutex);
unsigned short y = IBuffer::Convert.ToUShort((const unsigned char*)px);//IRV_TO_UINT16((const unsigned char*)px);
return HostToNetworkByteOrder(y);
}


unsigned long IBuffer::HostToNetworkByteOrder(unsigned long x)
{
Lock lock(mMutex);
if(IsBigEndian()){
return x;
}
else{
return ((((unsigned int)(x) & 0xff000000) >> 24) | \
(((unsigned int)(x) & 0x00ff0000) >> 8) | \
(((unsigned int)(x) & 0x0000ff00) << 8) | \
(((unsigned int)(x) & 0x000000ff) << 24));
}
}


unsigned long IBuffer::HostToNetworkByteOrderUL(const void* px)
{
Lock lock(mMutex);
unsigned long y = IBuffer::Convert.ToUShort((const unsigned char*)px);
return HostToNetworkByteOrder(y);
}

unsigned long IBuffer::NetworkToHostByteOrder(const unsigned long x)
{
Lock lock(mMutex);
if(IsBigEndian()){
return x;
}
else{
return ((((unsigned int)(x) & 0x000000ff) << 24) | \
(((unsigned int)(x) & 0x0000ff00) << 8) | \
(((unsigned int)(x) & 0x00ff0000) >> 8) | \
(((unsigned int)(x) & 0xff000000) >> 24));
}
}

unsigned short IBuffer::NetworkToHostByteOrder( const unsigned short x )
{
Lock lock(mMutex);
if(IsBigEndian()){
return x;
}
else{
return ((((unsigned short)(x) & 0x00ff) << 8) |
(((unsigned short)(x) & 0xff00) >> 8));
}
}

bool IBuffer::IsBigEndian(){
/* If LITTLE_ENDIAN or BIG_ENDIAN macros have been defined in config.h ==> use them
* otherwise ==> dyn retrieve the endianness
*/
short word = 0x4321;
#if LITTLE_ENDIAN
return false;
#elif BIG_ENDIAN
return true;
#else
return ((*(signed char *)&word) != 0x21);
#endif
}

/*
IBuffer IBuffer::operator=( const IBuffer &buf )
{
IBuffer bf;
bf.buffer = buf.buffer;
return bf;
}*/

IBuffer& IBuffer::operator=(IBuffer& Rhs)
{
if (this != &Rhs)
{
if (this->dataPtr && this->Size()>0 && this->GetPosition()>0)
{
delete this;
}
buffer=Rhs.buffer;
dataPtr = Rhs.dataPtr;
currPosition = Rhs.GetPosition();
}
return *this;

}

IBuffer& IBuffer::operator=( char* rhs )
{
Lock lock(mMutex);
if (this->buffer.size() != 0)
{
this->buffer.clear();
}
if (this->currPosition !=0)
{
this->currPosition = 0;
}
this->Write(rhs,strlen(rhs));
return * this;
}

//Move forward data pointer by one
void IBuffer::operator++()
{
dataPtr++;
SetPosition(1);
//dataPtr+=GetPosition();
}

//************************************
// Method: ReadByte
// FullName: BufferPool::ReadByte
// Access: public
// Returns: unsigned char
// Qualifier:
// Parameter:
// Description: read data of type byte and move forward data pointer
//************************************
unsigned char IBuffer::ReadByte()
{
Lock lock(mMutex);
unsigned char ret = (*(dataPtr));
dataPtr++;
SetPosition(1);
return ret;
}

unsigned short IBuffer::ReadShort()
{
Lock lock(mMutex);
unsigned short ret=/*HostToNetworkByteOrder((unsigned char*)(dataPtr))*/IBuffer::Convert.ToUShort((unsigned char*)(dataPtr));
dataPtr+=2;
SetPosition(2);
return ret;
}

unsigned int IBuffer::ReadUint32()
{
Lock lock(mMutex);
//I DON NOT KHNOW MUST CONVERT RECIEVED MESSAGE TO LITTLE ENDIAN OR NOT?
unsigned int ui=/*HostToNetworkByteOrderUL((unsigned char*)(dataPtr))*/Convert.ToUint32((unsigned char*)(dataPtr));
dataPtr+=4;
SetPosition(4);
return ui;
}

unsigned long IBuffer::ReadUlong()
{
Lock lock(mMutex);
return (unsigned long) ReadUint32();
}

unsigned char* IBuffer::Read(size_t sz)
{
Lock lock(mMutex);
//return a block of data
unsigned char* tmp = new unsigned char;
/*Lock lock(mMutex);*/
for (int i = 1;i<=sz;i++)
{
tmp[i-1] = *dataPtr++;
}
//dataPtr +=sz;
tmp[sz] = '\0';
SetPosition(sz);
return tmp;
}

IBuffer::operator char*()
{
Lock lock(mMutex);
char* ret = (char*)buffer.data();
ret[buffer.size()] = '\0';
return ret;
}

IBuffer::operator void*()
{
return (void*)buffer.data();
}

int IBuffer::Write(const void* data,size_t size )
{
Lock lock(mMutex);
unsigned char* udata = (unsigned char*)data;
/*Lock lock(mMutex);*/
for (size_t i=0;i<size;i++)
{
buffer.push_back(*udata++);
}
SetPtr();
return 0;
}

int IBuffer::Write( const void** data, size_t sz )
{
Lock lock(mMutex);
unsigned char* udata = (unsigned char*)data;
/*Lock lock(mMutex);*/
for (size_t i=0;i<sz;i++)
{
buffer.push_back(*udata++);
}
SetPtr();
return 0;
}

int IBuffer::Write( size_t position , const void* data,size_t sz )
{
Lock lock(mMutex);
unsigned char* udata = (unsigned char*)data;
vector<unsigned char>::pointer pt = buffer.data();
/*Lock lock(mMutex);*/
pt+=position;
for (size_t i=0;i<sz;i++)
{
*pt=(unsigned char)(*udata++);
pt++;
}
SetPtr();
return 0;
}

IBuffer::operator uint8_t*()
{
return (uint8_t*) buffer.data();
}

void IBuffer::CleanUp()
{
if (this->Size() > 0 && this->dataPtr)
{
this->buffer.clear();
this->SetPosition(0);
this->dataPtr = NULL;
}
}

void IBuffer::SetPtr()
{
if (!IsEmpty() /*&& !ptrSet*/)
{
dataPtr=buffer.data();
ptrSet=true;
bstate = BOB;
}
}

size_t IBuffer::Size() const
{
return buffer.size();
}

int IBuffer::SetPosition( int newpos )
{
//if before read function take placed then current position must be updated to new position
//our CURSOR move forward by newpos
if (currPosition == 0)
{
currPosition = newpos;
}
else
{
currPosition += newpos;
if (this->Size() == currPosition)
{
bstate = EOB;
}
}

return 0;
}

void IBuffer::Move( int32_t count )
{
SetPosition(count);
dataPtr+=count;
}

BufferState_t IBuffer::bstate(BOB);

这 2 个类不是最终类。我只是测试是否可以以这种方式使用 vector 作为缓冲区,我选择或不选择。我认为这不是个好主意。

编辑:

i change the implementation of Ibuffer by using HeapAlloc and HeapRealloc but i got this exeption

Unhandled exception at 0x774a2913 (ntdll.dll) in testDhcpv4.exe: 0xC0000374: A heap has been corrupted.

请帮助我。

祝愿

最佳答案

代码太多,但我发现了这一点

IBuffer::operator char*()
{
Lock lock(mMutex);
char* ret = (char*)buffer.data();
ret[buffer.size()] = '\0';
return ret;
}

这是未定义的行为(超出数组末尾的写入)。

还有一个危险信号是您正试图同时维护一个 vector 和一个指向它的数据的指针。显然修改 vector (例如通过 push_back)会使指针无效。我没有看到任何让我认为你弄错了的东西但是因为这样做没有任何好处(只需使用整数并在需要时调用 vector::data() )你最好摆脱.

关于c++ - 使用 std vector 作为库中存储的缓冲区和在另一个库中使用此缓冲区的困难,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11815234/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com