// RequestUnflattener.cpp
#include <stdlib.h>
#include <ByteOrder.h>
#include "Compatibility.h"
#include "DebugSupport.h"
#include "RequestUnflattener.h"
const int32 kMaxSaneStringSize = 4096; // 4 KB
const int32 kMaxSaneDataSize = 128 * 1024; // 128 KB
// constructor
Reader::Reader()
{
}
// destructor
Reader::~Reader()
{
}
// Read
status_t
Reader::Read(int32 size, void** buffer, bool* mustFree)
{
// check params
if (size < 0 || !buffer || mustFree)
return B_BAD_VALUE;
// deal with size == 0
if (size == 0) {
*buffer = NULL;
*mustFree = false;
return B_OK;
}
// allocate the buffer and read
*buffer = malloc(size);
if (!*buffer)
return B_NO_MEMORY;
status_t error = Read(*buffer, size);
if (error != B_OK) {
free(buffer);
return error;
}
return error;
}
// Skip
status_t
Reader::Skip(int32 size)
{
if (size <= 0)
return B_OK;
if (size > 8)
return B_BAD_VALUE;
char buffer[8];
return Read(buffer, size);
}
// RequestUnflattener
// constructor
RequestUnflattener::RequestUnflattener(Reader* reader)
: RequestMemberVisitor(),
fReader(reader),
fStatus(B_OK),
fBytesRead(0)
{
}
// GetStatus
status_t
RequestUnflattener::GetStatus() const
{
return fStatus;
}
// GetBytesRead
int32
RequestUnflattener::GetBytesRead() const
{
return fBytesRead;
}
// Visit
void
RequestUnflattener::Visit(RequestMember* member, bool& data)
{
uint8 netData;
if (Read(&netData, 1) == B_OK)
data = netData;
}
// Visit
void
RequestUnflattener::Visit(RequestMember* member, int8& data)
{
Read(&data, 1);
}
// Visit
void
RequestUnflattener::Visit(RequestMember* member, uint8& data)
{
Read(&data, 1);
}
// Visit
void
RequestUnflattener::Visit(RequestMember* member, int16& data)
{
if (Read(&data, 2) == B_OK)
data = B_BENDIAN_TO_HOST_INT16(data);
}
// Visit
void
RequestUnflattener::Visit(RequestMember* member, uint16& data)
{
if (Read(&data, 2) == B_OK)
data = B_BENDIAN_TO_HOST_INT16(data);
}
// Visit
void
RequestUnflattener::Visit(RequestMember* member, int32& data)
{
if (Read(&data, 4) == B_OK)
data = B_BENDIAN_TO_HOST_INT32(data);
}
// Visit
void
RequestUnflattener::Visit(RequestMember* member, uint32& data)
{
if (Read(&data, 4) == B_OK)
data = B_BENDIAN_TO_HOST_INT32(data);
}
// Visit
void
RequestUnflattener::Visit(RequestMember* member, int64& data)
{
if (Read(&data, 8) == B_OK)
data = B_BENDIAN_TO_HOST_INT64(data);
}
// Visit
void
RequestUnflattener::Visit(RequestMember* member, uint64& data)
{
if (Read(&data, 8) == B_OK)
data = B_BENDIAN_TO_HOST_INT64(data);
}
// Visit
void
RequestUnflattener::Visit(RequestMember* member, Data& data)
{
void* buffer;
int32 size;
bool mustFree;
if (ReadData(buffer, size, mustFree) != B_OK)
return;
// we can't deal with mustFree buffers currently
if (mustFree) {
free(buffer);
fStatus = B_ERROR;
return;
}
data.address = buffer;
data.size = size;
}
// Visit
void
RequestUnflattener::Visit(RequestMember* member, StringData& data)
{
void* buffer;
int32 size;
bool mustFree;
if (ReadData(buffer, size, mustFree) != B_OK)
return;
// we can't deal with mustFree buffers currently
if (mustFree) {
free(buffer);
fStatus = B_ERROR;
return;
}
data.address = buffer;
data.size = size;
// TODO: Check null termination.
}
// Visit
void
RequestUnflattener::Visit(RequestMember* member, RequestMember& subMember)
{
subMember.ShowAround(this);
}
// Visit
void
RequestUnflattener::Visit(RequestMember* member,
FlattenableRequestMember& subMember)
{
if (fStatus != B_OK)
return;
status_t status = subMember.Unflatten(this);
if (fStatus == B_OK)
fStatus = status;
}
// Read
status_t
RequestUnflattener::Read(void* buffer, int32 size)
{
if (fStatus != B_OK)
return fStatus;
fStatus = fReader->Read(buffer, size);
if (fStatus == B_OK)
fBytesRead += size;
return fStatus;
}
// Read
status_t
RequestUnflattener::Read(int32 size, void*& buffer, bool& mustFree)
{
if (fStatus != B_OK)
return fStatus;
fStatus = fReader->Read(size, &buffer, &mustFree);
if (fStatus == B_OK)
fBytesRead += size;
return fStatus;
}
// Align
status_t
RequestUnflattener::Align(int32 align)
{
if (fStatus != B_OK)
return fStatus;
if (align > 1) {
int32 newBytesRead = fBytesRead;
if (!(align & 0x3))
newBytesRead = (fBytesRead + 3) & ~0x3;
else if (!(align & 0x1))
newBytesRead = (fBytesRead + 1) & ~0x1;
if (newBytesRead > fBytesRead) {
fStatus = fReader->Skip(newBytesRead - fBytesRead);
if (fStatus == B_OK)
fBytesRead = newBytesRead;
}
}
return fStatus;
}
// ReadBool
status_t
RequestUnflattener::ReadBool(bool& data)
{
return Read(&data, 1);
}
// ReadInt32
status_t
RequestUnflattener::ReadInt32(int32& data)
{
if (Read(&data, 4) == B_OK)
data = B_BENDIAN_TO_HOST_INT32(data);
return fStatus;
}
// ReadData
status_t
RequestUnflattener::ReadData(void*& buffer, int32& _size, bool& mustFree)
{
if (fStatus != B_OK)
return fStatus;
// read size
int32 size;
if (ReadInt32(size) != B_OK)
return fStatus;
// check size for sanity
if (size < 0 || size > kMaxSaneDataSize) {
fStatus = B_BAD_DATA;
return fStatus;
}
// read data
if (size > 0) {
if (Read(size, buffer, mustFree) != B_OK)
return fStatus;
} else {
buffer = NULL;
mustFree = false;
}
_size = size;
return fStatus;
}
// ReadString
status_t
RequestUnflattener::ReadString(HashString& string)
{
void* buffer;
int32 size;
bool mustFree;
if (ReadData(buffer, size, mustFree) == B_OK) {
if (!string.SetTo((const char*)buffer))
fStatus = B_NO_MEMORY;
if (mustFree)
free(buffer);
}
return fStatus;
}
↑ V522 Dereferencing of the null pointer 'mustFree' might take place.