1
0
forked from 0ad/0ad

bugfixes related to "lying about user's buffer" feature

also rearranged + cleaned up a bit

This was SVN commit r959.
This commit is contained in:
janwas 2004-08-10 16:01:04 +00:00
parent 7c36638fd0
commit 023592d23f

View File

@ -29,15 +29,121 @@ struct Mem
H_TYPE_DEFINE(Mem); H_TYPE_DEFINE(Mem);
//////////////////////////////////////////////////////////////////////////////
static bool has_shutdown = false;
// raw pointer -> Handle
typedef std::map<void*, Handle> PtrToH;
typedef PtrToH::iterator It;
static PtrToH* _ptr_to_h;
static void ptr_to_h_shutdown()
{
has_shutdown = true;
delete _ptr_to_h;
_ptr_to_h = 0;
}
// undefined NLSO init order fix
static PtrToH& get_ptr_to_h()
{
if(!_ptr_to_h)
{
if(has_shutdown)
debug_warn("mem.cpp: ptr -> handle lookup used after module shutdown");
// crash + burn
_ptr_to_h = new PtrToH;
atexit2(ptr_to_h_shutdown);
}
return *_ptr_to_h;
}
#define ptr_to_h get_ptr_to_h()
// not needed by other modules - mem_get_size and mem_assign is enough.
static Handle find_alloc(void* target_p, It* out_it = 0)
{
// early out optimization (don't pay for full subset check)
It it = ptr_to_h.find(target_p);
if(it != ptr_to_h.end())
return it->second;
// not found; now check if target_p is within one of the mem ranges
for(it = ptr_to_h.begin(); it != ptr_to_h.end(); ++it)
{
std::pair<void*, Handle> item = *it;
void* p = item.first;
Handle hm = item.second;
// not before this alloc's p; could be it. now do range check.
if(target_p >= p)
{
Mem* m = (Mem*)h_user_data(hm, H_Mem);
if(m)
{
// found it within this mem range.
if(target_p <= (char*)m->raw_p + m->raw_size)
{
if(out_it)
*out_it = it;
return hm;
}
}
}
}
// not found
return 0;
}
// raw_p must be in map!
static void remove_alloc(void* raw_p)
{
size_t num_removed = ptr_to_h.erase(raw_p);
assert(num_removed == 1 && "remove_alloc: not in map");
}
// raw_p must not already be in map!
static void set_alloc(void* raw_p, Handle hm)
{
// verify it's not already in the mapping
#ifndef NDEBUG
It it = ptr_to_h.find(raw_p);
if(it != ptr_to_h.end())
{
debug_warn("set_alloc: already in map");
return;
}
#endif
ptr_to_h[raw_p] = hm;
}
//////////////////////////////////////////////////////////////////////////////
static void Mem_init(Mem* m, va_list args) static void Mem_init(Mem* m, va_list args)
{ {
UNUSED(m); // HACK: we pass along raw_p from h_alloc for use in Mem_reload
UNUSED(args); // (that means add/remove from mapping code is only here)
m->raw_p = va_arg(args, void*);
} }
static void Mem_dtor(Mem* m) static void Mem_dtor(Mem* m)
{ {
remove_alloc(m->raw_p);
if(m->dtor) if(m->dtor)
m->dtor(m->raw_p, m->raw_size, m->ctx); m->dtor(m->raw_p, m->raw_size, m->ctx);
} }
@ -45,8 +151,11 @@ static void Mem_dtor(Mem* m)
// can't alloc here, because h_alloc needs the key when called // can't alloc here, because h_alloc needs the key when called
// (key == pointer we allocate) // (key == pointer we allocate)
static int Mem_reload(Mem* /*m*/, const char* /*fn*/, Handle /*h*/) static int Mem_reload(Mem* m, const char* fn, Handle hm)
{ {
UNUSED(fn);
set_alloc(m->raw_p, hm);
return 0; return 0;
} }
@ -132,119 +241,27 @@ static void* pool_alloc(const size_t raw_size, uintptr_t& ctx)
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
static bool has_shutdown = false; int mem_free_h(Handle& hm)
typedef std::map<void*, Handle> PtrToH;
static PtrToH* _ptr_to_h;
static void ptr_to_h_shutdown()
{ {
has_shutdown = true;
delete _ptr_to_h;
_ptr_to_h = 0;
}
// undefined NLSO init order fix
static PtrToH& get_ptr_to_h()
{
if(!_ptr_to_h)
{
if(has_shutdown)
debug_warn("mem.cpp: ptr -> handle lookup used after module shutdown");
// crash + burn
_ptr_to_h = new PtrToH;
atexit2(ptr_to_h_shutdown);
}
return *_ptr_to_h;
}
#define ptr_to_h get_ptr_to_h()
// not needed by other modules - mem_get_size and mem_assign is enough.
static Handle find_alloc(void* target_p)
{
// early out optimization (don't pay for full subset check)
PtrToH::const_iterator it = ptr_to_h.find(target_p);
if(it != ptr_to_h.end())
return it->second;
// not found; now check if target_p is within one of the mem ranges
for(it = ptr_to_h.begin(); it != ptr_to_h.end(); ++it)
{
std::pair<void*, Handle> item = *it;
void* p = item.first;
Handle hm = item.second;
// not before this alloc's p; could be it. now do range check.
if(target_p >= p)
{
Mem* m = (Mem*)h_user_data(hm, H_Mem);
if(m)
{
// found it within this mem range.
if(target_p <= (char*)m->p + m->size)
return hm;
}
}
}
// not found
return 0;
}
// returns the handle that will be removed, for mem_free convenience.
// makes sure p is in the mapping.
static Handle remove_alloc(void* p)
{
PtrToH::iterator it = ptr_to_h.find(p);
if(it == ptr_to_h.end())
{
debug_warn("remove_alloc: pointer not in map");
return 0;
}
Handle hm = it->second;
ptr_to_h.erase(it);
return hm;
}
// p must not alread be in mapping!
static void set_alloc(void* p, Handle hm)
{
ptr_to_h[p] = hm;
}
//////////////////////////////////////////////////////////////////////////////
int mem_free_p(void*& p)
{
if(!p)
return ERR_INVALID_PARAM;
Handle hm = remove_alloc(p);
p = 0;
return h_free(hm, H_Mem); return h_free(hm, H_Mem);
} }
int mem_free_h(Handle& hm) int mem_free_p(void*& p)
{ {
void* p = mem_get_ptr(hm); Handle hm = find_alloc(p);
hm = 0; p = 0;
return mem_free_p(p); if(hm <= 0)
{
debug_warn("mem_free_p: not found in map");
return -1;
}
return mem_free_h(hm);
} }
Handle mem_assign(void* p, size_t size, uint flags, void* raw_p, size_t raw_size, MEM_DTOR dtor, uintptr_t ctx) Handle mem_assign(void* p, size_t size, uint flags, void* raw_p, size_t raw_size, MEM_DTOR dtor, uintptr_t ctx)
{ {
// we've already allocated that pointer - returns its handle // we've already allocated that pointer - returns its handle
@ -258,12 +275,10 @@ Handle mem_assign(void* p, size_t size, uint flags, void* raw_p, size_t raw_size
return 0; return 0;
} }
hm = h_alloc(H_Mem, (const char*)p, flags | RES_KEY); hm = h_alloc(H_Mem, (const char*)p, flags|RES_KEY|RES_NO_CACHE, raw_p);
if(!hm) if(!hm)
return 0; return 0;
set_alloc(p, hm);
H_DEREF(hm, Mem, m); H_DEREF(hm, Mem, m);
m->p = p; m->p = p;
m->size = size; m->size = size;
@ -282,9 +297,9 @@ int mem_assign_user(Handle hm, void* user_p, size_t user_size)
// security check: must be a subset of the existing buffer // security check: must be a subset of the existing buffer
// (otherwise, could reference other buffers / cause mischief) // (otherwise, could reference other buffers / cause mischief)
char* end = (char*)m->p + m->size; char* raw_end = (char*)m->raw_p + m->raw_size;
char* user_end = (char*)user_p + user_size; char* user_end = (char*)user_p + user_size;
if(user_p < m->p || user_end > end) if(user_p < m->raw_p || user_end > raw_end)
{ {
debug_warn("mem_assign_user: user buffer not contained in real buffer"); debug_warn("mem_assign_user: user buffer not contained in real buffer");
return -EINVAL; return -EINVAL;