private методы в Objective-C

Когда я только начал работать с Objective-C, мне очень не нравился тот факт, что в этом языке нет возможности объявить какой-либо метод класса приватным. Это действительно доставляет большое количество неудобств, т.к. пользователю класса приходится разбираться с большим количеством методов используемых для внутренних целей класса и совершенно ему не нужных. Continue reading

Дружественные шаблонные операторы

Как человек, довольно редко использующий шаблоны и метаопрограммирование, периодически путаюсь них. Недавно был сильно озадачен, пытаясь написать оператор << для шаблонного класса. Хотелось получить поддержку следующего синтаксиса:

Buffer<int> buff;
int data1 = 100;
int data2 = 200;

buff << data1 << data2;


Казалось бы ничего сложного (да и без казалось ничего сложного), тем не менее пришлось подумать. Основная проблема – синтаксис который позволял использовать компилятор из вендовой студии не сработал:

template<typename T>
class Buffer
{
public:
friend Buffer<T>& operator<< ( Buffer<T> buff, const T& data );

Buffer()
{}
~Buffer()
{}
};

template<typename T>
Buffer<T>& operator<<( Buffer<T>& buff, const T& data )
{
// do smth
return buff;
}

Погуглив, я понял, что эта проблема волнует не только меня, но врет решения предлагались несколько кривоваты, например можно сделать так:

template<typename U>
friend Buffer& operator<< ( Buffer& buff, const U& data );

Но это не то что требуется. Хотя на самом деле, все просто и логично:

template<typename T>
class Buffer;

template<typename T>
Buffer<T>& operator<<( Buffer<T>& buff, const T& data );

template<typename T>
class Buffer
{
public:
friend Buffer<T>& operator<< <T> ( Buffer<T>& buff, const T& data );

Buffer()
{}
~Buffer()
{}
};

template<typename T>
Buffer<T>& operator<<( Buffer<T>& buff, const T& data )
{
// do smth
return buff;
}

Автоопределение прокси

Казалось бы, тривиальнейшая задача – определить настройки прокси сервиса, заданные при помощи .pac файла либо полученные в результате работы автоконфигурации. А в действительности оказывается что информации в интернете кот наплакал, а та что есть посвящена венде (что еще печальнее). Чтобы исправить эту жутко не справедливую ситуацию, я опишу как можно определить настройки прокси в Mac OS X приложении.
Итак, необходимый API появился в Mac OS X начиная с версии 10.5, так же API присутствует в iOS, но деталей по версиям я уже сказать не могу. Continue reading

printf и CoreFoudation

На мой взгляд, CoreFoudation очень интересная библиотека. Я бы сказал это лучший вариант реализации объектно ориентированной модели при разработке на Си, который я когда-либо видел. Но иногда возникают досадные мелочи, например невозможность использовать printf для стандартных объектов из CoreFoudation, а как было бы здорово.
Но, все не так уж и плохо, хотя и в гугле ответ находится не сразу:

#include <CoreFoundation/CoreFoundation.h>

int main (int argc, const char * argv[])
{
    CFStringRef outStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("Output string: %@, %d"), CFSTR("additional string"), 10);
    CFShow( outStr );
    CFRelease( outStr );
    return 0;
}

Можно это дело еще в макрос завернуть, наверное, но зачем? Вобщем, пусть так будет.

Перехват вызовов DTrace

В очередной раз столкнувшись c необходимостью отследить создание новых процессов, я подумал: а почему бы не посмотреть на то, как это делает DTrace? В отличие от стандартного и общеизвестного алгоритма с патчем таблицы системных вызовов, который работает только с системным вызовами, DTrace позволяет перехватить что угодно. На мой взгляд, подобный функционал можно было реализовать путем добавления переходов на свой обработчик в начало перехватываемой функции, но все оказалось куда более элегантно.

Изучение DTrace стоит начать с его “эпицентра” (как утверждают авторы фрэймворка) – функции dtrace_probe. В целом, код достаточно понятен и содержит в себе большое количество комментариев. После внимательного изучения этой функции становится ясно, что искомое находится чуть дальше, в функции fbt_provide_module, которую можно найти в файле fbt.c директории bsd/dev/dtrace исходных кодов XNU. Эта функция как раз и используется для патчинга перехватываемых функций.
Итак, что же он делает в случае с 64 битной архитектурой (для 32 битной или PPC используется тот-же принцип)? Сам процесс установки перехватчика выглядит следующим образом: у каждого модуля берется таблица символов (struct nlist_64) и каждый глобальный символ, имеющий имя, сверяется со списком требуемых “проб”. При этом DTrace отказывается перехватывать ряд системных функций, например, такие как собственные функции (dtrace_*), функции, отвечающие за отладку (kdp_*, kdbg_*, kernel_debug), работу таймеров (etimer_*, clock_*, absolutetime_to_*), управление питанием (acpi_*), и ряд других. Если найденную функцию необходимо перехватить, то делается проверка того, что функция начинается со следующей последовательности команд (адрес начала функции получается из той же таблицы символов):

push %rbp                       ; 0x55
mov %rsp, %rbp                  ; 0x48, 0x89, 0xE5

Затем ищется конец функции. Если все прошло успешно, то создается “проба”, в которой сохраняется внутренняя информация, включая информацию о найденных адресах. На этом создание пробы завершается и начинается обработка следующей функции из списка.

Ну, а теперь самое интересное. После того как проба становится активной (функция fbt_enable), второй байт от начала перехватываемой функции подменяется на 0xF0. Копирование происходит по физическим адресам в памяти при помощи функции ml_nofault_copy. В результате возникает гарантировано неверная команда и, как следствие, возникновение исключения при попытке ее обработки процессором. Ну, а дальше все довольно очевидно. Возникающее исключение перехватывается DTrace, и идет обработка сработавшей “пробы” с последующим вызовом оригинальной функции.

Лично мне механизм очень понравился, но, к сожалению, при всей своей элегантности алгоритм, используемый DTrace, не подходит для использования в сторонних приложениях, т.е. воспользоваться им, конечно, можно, но ни к чему хорошему это не приведет.