IdManager improved, added Fixed ID mechanism

Fixed UB in get_current_id()
This commit is contained in:
Nekotekina 2015-08-04 13:46:05 +03:00
parent c7ee8cadde
commit 9e5daa1737
5 changed files with 187 additions and 101 deletions

View File

@ -61,8 +61,19 @@ class ID_manager
{
std::mutex m_mutex;
// 0 is invalid ID
// 1..0x7fffffff : general purpose IDs
// 0x80000000+ : occupied by fixed IDs
std::unordered_map<u32, ID_data_t> m_id_map;
u32 m_cur_id = 1; // first ID
// contains the next ID or 0x80000000 | current_ID
u32 m_cur_id = 1;
static u32 get_type_fixed_id(const std::type_info& type)
{
// TODO: more reliable way of fixed ID generation
return 0x80000000 | static_cast<u32>(type.hash_code());
}
public:
// check if ID exists and has specified type
@ -70,7 +81,7 @@ public:
{
std::lock_guard<std::mutex> lock(m_mutex);
auto f = m_id_map.find(id);
const auto f = m_id_map.find(id);
return f != m_id_map.end() && f->second.info == typeid(T);
}
@ -80,26 +91,20 @@ public:
{
std::lock_guard<std::mutex> lock(m_mutex);
auto f = m_id_map.find(id);
const auto f = m_id_map.find(id);
return f != m_id_map.end() && f->second.type == type;
}
// must be called from the constructor called through make() to get further ID of current object
// must be called from the constructor called through make() or make_ptr() to get further ID of current object
u32 get_current_id()
{
// if called correctly from make(), the mutex is locked
// if called illegally, the mutex is unlocked with high probability (wrong ID is returned otherwise)
if (m_mutex.try_lock())
if ((m_cur_id & 0x80000000) == 0)
{
// schedule unlocking
std::lock_guard<std::mutex> lock(m_mutex, std::adopt_lock);
throw EXCEPTION("Current ID is not available");
}
return m_cur_id;
return m_cur_id & 0x7fffffff;
}
void clear()
@ -110,6 +115,36 @@ public:
m_cur_id = 1; // first ID
}
// add fixed ID of specified type only if it doesn't exist (each type has unique id)
template<typename T, typename... Args, typename = std::enable_if_t<std::is_constructible<T, Args...>::value>> std::shared_ptr<T> make_fixed(Args&&... args)
{
std::lock_guard<std::mutex> lock(m_mutex);
const u32 type = ID_type<T>::type;
static const u32 id = get_type_fixed_id(typeid(T));
const auto found = m_id_map.find(id);
// ensure that this ID doesn't exist
if (found == m_id_map.end())
{
auto ptr = std::make_shared<T>(std::forward<Args>(args)...);
m_id_map.emplace(id, ID_data_t(ptr, type, id));
return std::move(ptr);
}
// ensure that this ID is not occupied by the object of another type
if (found->second.info == typeid(T))
{
return nullptr;
}
throw EXCEPTION("Collision occured ('%s' and '%s', id=0x%x)", found->second.info.name(), typeid(T).name(), id);
}
// add new ID of specified type with specified constructor arguments (returns object)
template<typename T, typename... Args, typename = std::enable_if_t<std::is_constructible<T, Args...>::value>> std::shared_ptr<T> make_ptr(Args&&... args)
{
@ -117,11 +152,20 @@ public:
const u32 type = ID_type<T>::type;
auto ptr = std::make_shared<T>(std::forward<Args>(args)...);
m_cur_id |= 0x80000000;
m_id_map.emplace(m_cur_id, ID_data_t(ptr, type, m_cur_id));
if (const u32 id = m_cur_id & 0x7fffffff)
{
auto ptr = std::make_shared<T>(std::forward<Args>(args)...);
return m_cur_id++, std::move(ptr);
m_id_map.emplace(id, ID_data_t(ptr, type, id));
m_cur_id = id + 1;
return std::move(ptr);
}
throw EXCEPTION("Out of IDs");
}
// add new ID of specified type with specified constructor arguments (returns id)
@ -131,9 +175,35 @@ public:
const u32 type = ID_type<T>::type;
m_id_map.emplace(m_cur_id, ID_data_t(std::make_shared<T>(std::forward<Args>(args)...), type, m_cur_id));
m_cur_id |= 0x80000000;
return m_cur_id++;
if (const u32 id = m_cur_id & 0x7fffffff)
{
m_id_map.emplace(id, ID_data_t(std::make_shared<T>(std::forward<Args>(args)...), type, id));
m_cur_id = id + 1;
return id;
}
throw EXCEPTION("Out of IDs");
}
// load fixed ID of specified type Orig, optionally static_cast to T
template<typename T, typename Orig = T> auto get() -> decltype(std::shared_ptr<T>(static_cast<T*>(std::declval<Orig*>())))
{
std::lock_guard<std::mutex> lock(m_mutex);
static const u32 id = get_type_fixed_id(typeid(T));
const auto found = m_id_map.find(id);
if (found == m_id_map.end() || found->second.info != typeid(Orig))
{
return nullptr;
}
return std::static_pointer_cast<T>(found->second.data);
}
// load ID created with type Orig, optionally static_cast to T
@ -141,14 +211,14 @@ public:
{
std::lock_guard<std::mutex> lock(m_mutex);
auto f = m_id_map.find(id);
const auto found = m_id_map.find(id);
if (f == m_id_map.end() || f->second.info != typeid(Orig))
if (found == m_id_map.end() || found->second.info != typeid(Orig))
{
return nullptr;
}
return std::static_pointer_cast<T>(f->second.data);
return std::static_pointer_cast<T>(found->second.data);
}
// load all IDs created with type Orig, optionally static_cast to T
@ -171,18 +241,38 @@ public:
return result;
}
template<typename T> bool remove(u32 id)
// remove fixed ID created with type T
template<typename T> bool remove()
{
std::lock_guard<std::mutex> lock(m_mutex);
auto item = m_id_map.find(id);
static const u32 id = get_type_fixed_id(typeid(T));
if (item == m_id_map.end() || item->second.info != typeid(T))
const auto found = m_id_map.find(id);
if (found == m_id_map.end() || found->second.info != typeid(T))
{
return false;
}
m_id_map.erase(item);
m_id_map.erase(found);
return true;
}
// remove ID created with type T
template<typename T> bool remove(u32 id)
{
std::lock_guard<std::mutex> lock(m_mutex);
const auto found = m_id_map.find(id);
if (found == m_id_map.end() || found->second.info != typeid(T))
{
return false;
}
m_id_map.erase(found);
return true;
}
@ -224,7 +314,7 @@ public:
}
// get sorted ID list
template<typename T> std::set<u32> get_IDs()
template<typename T> std::set<u32> get_set()
{
std::lock_guard<std::mutex> lock(m_mutex);
@ -244,7 +334,7 @@ public:
}
// get sorted ID list
std::set<u32> get_IDs(u32 type)
std::set<u32> get_set(u32 type)
{
std::lock_guard<std::mutex> lock(m_mutex);

View File

@ -1,14 +1,14 @@
#include "stdafx.h"
#include "Ini.h"
#include "Emu/Memory/Memory.h"
#include "Emu/IdManager.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "cellCamera.h"
extern Module cellCamera;
std::unique_ptr<camera_t> g_camera;
s32 cellCameraInit()
{
cellCamera.Warning("cellCameraInit()");
@ -18,53 +18,50 @@ s32 cellCameraInit()
return CELL_CAMERA_ERROR_DEVICE_NOT_FOUND;
}
if (g_camera->init)
const auto camera = Emu.GetIdManager().make_fixed<camera_t>();
if (!camera)
{
return CELL_CAMERA_ERROR_ALREADY_INIT;
}
if (Ini.CameraType.GetValue() == 1)
{
g_camera->attr[CELL_CAMERA_SATURATION] = { 164 };
g_camera->attr[CELL_CAMERA_BRIGHTNESS] = { 96 };
g_camera->attr[CELL_CAMERA_AEC] = { 1 };
g_camera->attr[CELL_CAMERA_AGC] = { 1 };
g_camera->attr[CELL_CAMERA_AWB] = { 1 };
g_camera->attr[CELL_CAMERA_ABC] = { 0 };
g_camera->attr[CELL_CAMERA_LED] = { 1 };
g_camera->attr[CELL_CAMERA_QS] = { 0 };
g_camera->attr[CELL_CAMERA_NONZEROCOEFFS] = { 32, 32 };
g_camera->attr[CELL_CAMERA_YUVFLAG] = { 0 };
g_camera->attr[CELL_CAMERA_BACKLIGHTCOMP] = { 0 };
g_camera->attr[CELL_CAMERA_MIRRORFLAG] = { 1 };
g_camera->attr[CELL_CAMERA_422FLAG] = { 1 };
g_camera->attr[CELL_CAMERA_USBLOAD] = { 4 };
camera->attr[CELL_CAMERA_SATURATION] = { 164 };
camera->attr[CELL_CAMERA_BRIGHTNESS] = { 96 };
camera->attr[CELL_CAMERA_AEC] = { 1 };
camera->attr[CELL_CAMERA_AGC] = { 1 };
camera->attr[CELL_CAMERA_AWB] = { 1 };
camera->attr[CELL_CAMERA_ABC] = { 0 };
camera->attr[CELL_CAMERA_LED] = { 1 };
camera->attr[CELL_CAMERA_QS] = { 0 };
camera->attr[CELL_CAMERA_NONZEROCOEFFS] = { 32, 32 };
camera->attr[CELL_CAMERA_YUVFLAG] = { 0 };
camera->attr[CELL_CAMERA_BACKLIGHTCOMP] = { 0 };
camera->attr[CELL_CAMERA_MIRRORFLAG] = { 1 };
camera->attr[CELL_CAMERA_422FLAG] = { 1 };
camera->attr[CELL_CAMERA_USBLOAD] = { 4 };
}
else if (Ini.CameraType.GetValue() == 2)
{
g_camera->attr[CELL_CAMERA_SATURATION] = { 64 };
g_camera->attr[CELL_CAMERA_BRIGHTNESS] = { 8 };
g_camera->attr[CELL_CAMERA_AEC] = { 1 };
g_camera->attr[CELL_CAMERA_AGC] = { 1 };
g_camera->attr[CELL_CAMERA_AWB] = { 1 };
g_camera->attr[CELL_CAMERA_LED] = { 1 };
g_camera->attr[CELL_CAMERA_BACKLIGHTCOMP] = { 0 };
g_camera->attr[CELL_CAMERA_MIRRORFLAG] = { 1 };
g_camera->attr[CELL_CAMERA_GAMMA] = { 1 };
g_camera->attr[CELL_CAMERA_AGCLIMIT] = { 4 };
g_camera->attr[CELL_CAMERA_DENOISE] = { 0 };
g_camera->attr[CELL_CAMERA_FRAMERATEADJUST] = { 0 };
g_camera->attr[CELL_CAMERA_PIXELOUTLIERFILTER] = { 1 };
g_camera->attr[CELL_CAMERA_AGCLOW] = { 48 };
g_camera->attr[CELL_CAMERA_AGCHIGH] = { 64 };
camera->attr[CELL_CAMERA_SATURATION] = { 64 };
camera->attr[CELL_CAMERA_BRIGHTNESS] = { 8 };
camera->attr[CELL_CAMERA_AEC] = { 1 };
camera->attr[CELL_CAMERA_AGC] = { 1 };
camera->attr[CELL_CAMERA_AWB] = { 1 };
camera->attr[CELL_CAMERA_LED] = { 1 };
camera->attr[CELL_CAMERA_BACKLIGHTCOMP] = { 0 };
camera->attr[CELL_CAMERA_MIRRORFLAG] = { 1 };
camera->attr[CELL_CAMERA_GAMMA] = { 1 };
camera->attr[CELL_CAMERA_AGCLIMIT] = { 4 };
camera->attr[CELL_CAMERA_DENOISE] = { 0 };
camera->attr[CELL_CAMERA_FRAMERATEADJUST] = { 0 };
camera->attr[CELL_CAMERA_PIXELOUTLIERFILTER] = { 1 };
camera->attr[CELL_CAMERA_AGCLOW] = { 48 };
camera->attr[CELL_CAMERA_AGCHIGH] = { 64 };
}
// TODO: Some other default attributes? Need to check the actual behaviour on a real PS3.
if (g_camera->init.exchange(true))
{
throw EXCEPTION("Unexpected");
}
return CELL_OK;
}
@ -72,16 +69,11 @@ s32 cellCameraEnd()
{
cellCamera.Warning("cellCameraEnd()");
if (!g_camera->init)
if (!Emu.GetIdManager().remove<camera_t>())
{
return CELL_CAMERA_ERROR_NOT_INIT;
}
if (!g_camera->init.exchange(false))
{
throw EXCEPTION("Unexpected");
}
return CELL_OK;
}
@ -113,7 +105,9 @@ s32 cellCameraGetType(s32 dev_num, vm::ptr<s32> type)
{
cellCamera.Warning("cellCameraGetType(dev_num=%d, type=*0x%x)", dev_num, type);
if (!g_camera->init.load())
const auto camera = Emu.GetIdManager().get<camera_t>();
if (!camera)
{
return CELL_CAMERA_ERROR_NOT_INIT;
}
@ -165,7 +159,9 @@ s32 cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm::ptr<u
const auto attr_name = camera_t::get_attr_name(attrib);
if (!g_camera->init.load())
const auto camera = Emu.GetIdManager().get<camera_t>();
if (!camera)
{
return CELL_CAMERA_ERROR_NOT_INIT;
}
@ -175,8 +171,8 @@ s32 cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm::ptr<u
return CELL_CAMERA_ERROR_PARAM;
}
*arg1 = g_camera->attr[attrib].v1;
*arg2 = g_camera->attr[attrib].v2;
*arg1 = camera->attr[attrib].v1;
*arg2 = camera->attr[attrib].v2;
return CELL_OK;
}
@ -187,7 +183,9 @@ s32 cellCameraSetAttribute(s32 dev_num, s32 attrib, u32 arg1, u32 arg2)
const auto attr_name = camera_t::get_attr_name(attrib);
if (!g_camera->init.load())
const auto camera = Emu.GetIdManager().get<camera_t>();
if (!camera)
{
return CELL_CAMERA_ERROR_NOT_INIT;
}
@ -197,7 +195,7 @@ s32 cellCameraSetAttribute(s32 dev_num, s32 attrib, u32 arg1, u32 arg2)
return CELL_CAMERA_ERROR_PARAM;
}
g_camera->attr[attrib] = { arg1, arg2 };
camera->attr[attrib] = { arg1, arg2 };
return CELL_OK;
}
@ -306,8 +304,6 @@ s32 cellCameraRemoveNotifyEventQueue2(u64 key)
Module cellCamera("cellCamera", []()
{
g_camera = std::make_unique<camera_t>();
REG_FUNC(cellCamera, cellCameraInit);
REG_FUNC(cellCamera, cellCameraEnd);
REG_FUNC(cellCamera, cellCameraOpen); // was "renamed", but exists

View File

@ -315,8 +315,6 @@ struct CellCameraReadEx
// Custom struct to keep track of cameras
struct camera_t
{
std::atomic<bool> init{ false };
struct attr_t
{
u32 v1, v2;

View File

@ -113,7 +113,7 @@ s32 sys_process_get_id(u32 object, vm::ptr<u32> buffer, u32 size, vm::ptr<u32> s
case SYS_LWCOND_OBJECT:
case SYS_EVENT_FLAG_OBJECT:
{
const auto objects = Emu.GetIdManager().get_IDs(object);
const auto objects = Emu.GetIdManager().get_set(object);
u32 i = 0;

View File

@ -14,7 +14,9 @@
#include "Emu/SysCalls/lv2/sys_cond.h"
#include "Emu/SysCalls/lv2/sys_semaphore.h"
#include "Emu/SysCalls/lv2/sys_event.h"
#include "Emu/SysCalls/lv2/sys_process.h"
#include "Emu/SysCalls/lv2/sys_event_flag.h"
#include "Emu/SysCalls/lv2/sys_prx.h"
#include "Emu/SysCalls/lv2/sys_memory.h"
#include "KernelExplorer.h"
@ -78,12 +80,12 @@ void KernelExplorer::Update()
// TODO: FileSystem
// Semaphores
if (u32 count = Emu.GetIdManager().get_count(SYS_SEMAPHORE_OBJECT))
if (u32 count = Emu.GetIdManager().get_count<lv2_sema_t>())
{
sprintf(name, "Semaphores (%d)", count);
const auto& node = m_tree->AppendItem(root, name);
for (const auto id : Emu.GetIdManager().get_IDs(SYS_SEMAPHORE_OBJECT))
for (const auto id : Emu.GetIdManager().get_set<lv2_sema_t>())
{
const auto sem = Emu.GetIdManager().get<lv2_sema_t>(id);
sprintf(name, "Semaphore: ID = 0x%x '%s', Count = %d, Max Count = %d, Waiters = %#llx", id, &name64(sem->name), sem->value.load(), sem->max, sem->sq.size());
@ -92,12 +94,12 @@ void KernelExplorer::Update()
}
// Mutexes
if (u32 count = Emu.GetIdManager().get_count(SYS_MUTEX_OBJECT))
if (u32 count = Emu.GetIdManager().get_count<lv2_mutex_t>())
{
sprintf(name, "Mutexes (%d)", count);
const auto& node = m_tree->AppendItem(root, name);
for (const auto id : Emu.GetIdManager().get_IDs(SYS_MUTEX_OBJECT))
for (const auto id : Emu.GetIdManager().get_set<lv2_mutex_t>())
{
const auto mutex = Emu.GetIdManager().get<lv2_mutex_t>(id);
sprintf(name, "Mutex: ID = 0x%x '%s'", id, &name64(mutex->name));
@ -106,12 +108,12 @@ void KernelExplorer::Update()
}
// Light Weight Mutexes
if (u32 count = Emu.GetIdManager().get_count(SYS_LWMUTEX_OBJECT))
if (u32 count = Emu.GetIdManager().get_count<lv2_lwmutex_t>())
{
sprintf(name, "Lightweight Mutexes (%d)", count);
const auto& node = m_tree->AppendItem(root, name);
for (const auto id : Emu.GetIdManager().get_IDs(SYS_LWMUTEX_OBJECT))
for (const auto id : Emu.GetIdManager().get_set<lv2_lwmutex_t>())
{
const auto lwm = Emu.GetIdManager().get<lv2_lwmutex_t>(id);
sprintf(name, "Lightweight Mutex: ID = 0x%x '%s'", id, &name64(lwm->name));
@ -120,12 +122,12 @@ void KernelExplorer::Update()
}
// Condition Variables
if (u32 count = Emu.GetIdManager().get_count(SYS_COND_OBJECT))
if (u32 count = Emu.GetIdManager().get_count<lv2_cond_t>())
{
sprintf(name, "Condition Variables (%d)", count);
const auto& node = m_tree->AppendItem(root, name);
for (const auto id : Emu.GetIdManager().get_IDs(SYS_COND_OBJECT))
for (const auto id : Emu.GetIdManager().get_set<lv2_cond_t>())
{
const auto cond = Emu.GetIdManager().get<lv2_cond_t>(id);
sprintf(name, "Condition Variable: ID = 0x%x '%s'", id, &name64(cond->name));
@ -134,12 +136,12 @@ void KernelExplorer::Update()
}
// Light Weight Condition Variables
if (u32 count = Emu.GetIdManager().get_count(SYS_LWCOND_OBJECT))
if (u32 count = Emu.GetIdManager().get_count<lv2_lwcond_t>())
{
sprintf(name, "Lightweight Condition Variables (%d)", count);
const auto& node = m_tree->AppendItem(root, name);
for (const auto id : Emu.GetIdManager().get_IDs(SYS_LWCOND_OBJECT))
for (const auto id : Emu.GetIdManager().get_set<lv2_lwcond_t>())
{
const auto lwc = Emu.GetIdManager().get<lv2_lwcond_t>(id);
sprintf(name, "Lightweight Condition Variable: ID = 0x%x '%s'", id, &name64(lwc->name));
@ -148,12 +150,12 @@ void KernelExplorer::Update()
}
// Event Queues
if (u32 count = Emu.GetIdManager().get_count(SYS_EVENT_QUEUE_OBJECT))
if (u32 count = Emu.GetIdManager().get_count<lv2_event_queue_t>())
{
sprintf(name, "Event Queues (%d)", count);
const auto& node = m_tree->AppendItem(root, name);
for (const auto id : Emu.GetIdManager().get_IDs(SYS_EVENT_QUEUE_OBJECT))
for (const auto id : Emu.GetIdManager().get_set<lv2_event_queue_t>())
{
const auto queue = Emu.GetIdManager().get<lv2_event_queue_t>(id);
sprintf(name, "Event Queue: ID = 0x%x '%s', Key = %#llx", id, &name64(queue->name), queue->key);
@ -162,12 +164,12 @@ void KernelExplorer::Update()
}
// Event Ports
if (u32 count = Emu.GetIdManager().get_count(SYS_EVENT_PORT_OBJECT))
if (u32 count = Emu.GetIdManager().get_count<lv2_event_port_t>())
{
sprintf(name, "Event Ports (%d)", count);
const auto& node = m_tree->AppendItem(root, name);
for (const auto id : Emu.GetIdManager().get_IDs(SYS_EVENT_PORT_OBJECT))
for (const auto id : Emu.GetIdManager().get_set<lv2_event_port_t>())
{
const auto port = Emu.GetIdManager().get<lv2_event_port_t>(id);
sprintf(name, "Event Port: ID = 0x%x, Name = %#llx", id, port->name);
@ -176,14 +178,14 @@ void KernelExplorer::Update()
}
// Modules
if (u32 count = Emu.GetIdManager().get_count(SYS_PRX_OBJECT))
if (u32 count = Emu.GetIdManager().get_count<lv2_prx_t>())
{
sprintf(name, "Modules (%d)", count);
const auto& node = m_tree->AppendItem(root, name);
//sprintf(name, "Segment List (%l)", 2 * objects.size()); // TODO: Assuming 2 segments per PRX file is not good
//m_tree->AppendItem(node, name);
for (const auto& id : Emu.GetIdManager().get_IDs(SYS_PRX_OBJECT))
for (const auto& id : Emu.GetIdManager().get_set<lv2_prx_t>())
{
sprintf(name, "PRX: ID = 0x%x", id);
m_tree->AppendItem(node, name);
@ -191,12 +193,12 @@ void KernelExplorer::Update()
}
// Memory Containers
if (u32 count = Emu.GetIdManager().get_count(SYS_MEM_OBJECT))
if (u32 count = Emu.GetIdManager().get_count<lv2_memory_container_t>())
{
sprintf(name, "Memory Containers (%d)", count);
const auto& node = m_tree->AppendItem(root, name);
for (const auto& id : Emu.GetIdManager().get_IDs(SYS_MEM_OBJECT))
for (const auto& id : Emu.GetIdManager().get_set<lv2_memory_container_t>())
{
sprintf(name, "Memory Container: ID = 0x%x", id);
m_tree->AppendItem(node, name);
@ -204,12 +206,12 @@ void KernelExplorer::Update()
}
// Event Flags
if (u32 count = Emu.GetIdManager().get_count(SYS_EVENT_FLAG_OBJECT))
if (u32 count = Emu.GetIdManager().get_count<lv2_event_flag_t>())
{
sprintf(name, "Event Flags (%d)", count);
const auto& node = m_tree->AppendItem(root, name);
for (const auto& id : Emu.GetIdManager().get_IDs(SYS_EVENT_FLAG_OBJECT))
for (const auto& id : Emu.GetIdManager().get_set<lv2_event_flag_t>())
{
sprintf(name, "Event Flag: ID = 0x%x", id);
m_tree->AppendItem(node, name);