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:
parent
7c36638fd0
commit
023592d23f
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user