2014-01-23 2 views
1

У меня есть C++ API с оболочкой C. Клиент C может получить дескриптор базового объекта C++, а затем использовать его для получения другой информации об объекте, например.Проверьте, нет ли непрозрачной ручки C

PersonHandle handle = createPerson("NisseIHult"); 
char* name = getPersonName(handle); //Get person takes a void* pointer 

В приведенном выше коде дескриптор задается классом класса C++ Person.

Вопрос в том, как я могу проверить внутри getPersonName, что аргумент, handle, является допустимым дескриптором? Например, если клиент делает это:

char * name = getPersonName (1234);

это приведет к нарушению доступа внутри getPersonName. Мне нужен способ проверить и проверить дескриптор, а в приведенном выше случае вернуть NULL?

+2

Как пользователи API 'C' создают объекты PersonHandle? Какой-то тип 'createPerson()' API? Отслеживать действительных лиц, которые фактически созданы оттуда. – Chad

+1

Как вы решаете ручку? Если вы внедрили какой-то реестр сопоставления объектов handle-object, вы можете проверить его. – tiguchi

+0

Мне нравится идея наличия внутреннего списка созданных дескрипторов. Затем я могу проверить и проверить адреса. Хорошая идея! –

ответ

3

Поскольку ручки являются указателями на объекты C++, нет надежного способа проверить их достоверность, не вызывая некоторое неопределенное поведение.

Я видел два решения этой проблемы:

  • Make обрабатывает целые числа для полного контроля - а не раздавать указатели, держать указатели внутри - скажем, в неупорядоченном карте от int к указателю, наряду с некоторыми метаданными, и дают пользователям целые числа для использования в качестве дескрипторов. Это вводит дополнительный поиск хэша в процессе доступа к человеку, но вы можете сделать это совершенно надежным, потому что все int s находятся под вашим контролем. Например, если вы выдаете дескрипторы объектов разных типов, вы можете создать подробное сообщение об ошибке, например. «ручка к объекту Horse была использована там, где требуется ручка Person». Это решение имеет дополнительное преимущество в том, что у вас нет обвисших ссылок: пользователь может передать дескриптор, который вы сделали недействительным, но вы можете быстро сказать, что объект удален.
  • Вывести все объекты, на которые вы указываете ручки из общего базового класса, и поместить «магическое число» в первый член этого класса. - «Магическое число» - это бит-шаблон, который вы помещаете, скажем, в a int, и установите его в каждом объекте Person. После прокачки вы можете проверить if (personFromHandle->magic != 0xBEEFBEEF) ..., чтобы увидеть, есть ли шаблон. Это решение является обычным явлением, но я бы рекомендовал его против, поскольку он имеет неопределенное поведение при передаче недопустимого дескриптора. Это не нормально использовать, если операция должна продолжаться после неудачной попытки использовать дескриптор. Это решение также сломается, если будет передана ссылка на освобожденный объект.
+0

Мне нравятся оба подхода. Я могу получить внутреннюю карту, содержащую дескриптор (pointeraddress как long) и тип дескриптора. Затем я могу легко проверить оба параметра, если дескриптор является допустимым дескриптором, и если его тип указал тоже, подходит для фактической функции API. –

+0

@TotteKarlsson "также сломается, если передана ссылка на объект, освобожденный от несанкционированного доступа" - вы можете просто стереть это магическое число при уничтожении объекта. Он по-прежнему не защищен от передачи недействительного дескриптора, указывающего на недоступную память. Но вы можете проверить, есть ли адрес памяти, если он доступен для чтения, прежде чем обращаться к нему. Скажем, для Linux это можно сделать следующим образом: http://stackoverflow.com/a/7138421/1259152 – olegst

+0

@TotteKarlsson И магическое число для каждого нового объекта может быть рассчитано с помощью какого-то фантастического алгоритма, чтобы вы были уверены, что магическое число действительно уникален и не совпадает с каким-то мусором. – olegst

1

Подобно первой части вышеуказанного ответа, поместить адрес каждого объекта вы раздайте в std::set (или аналогичный контейнер) и тест на наличие в set перед заливкой.

Смежные вопросы