Какой самый чистый способ победить квалификацию C ++? - PullRequest
2 голосов
/ 29 сентября 2010

Я решил обойти ошибку в GNU libstdc ++, обратившись к внутренней переменной.Вспоминая, что Йоханнес решил эту проблему в своем блоге, я проверил это… но не смог понять код, кроме основной концепции получения статического инициализатора для грязной работы.Итак, я сводил это к этому, что довольно компактно.

Но, как уже отмечалось, это приводит к тому, что небольшие объекты и функции доступа дублируются на единицу перевода, вызывая неприятный каскад.Есть ли канонический способ сделать это, скажем, лучший метод Boost?

Извиняюсь за плохой юмор, но это не даром ... мы бы не хотели, чтобы этот код был "безопасным для работы"!

/* This hack installs a static initializer, so to avoid the ordering fiasco,
make one fresh copy per translation unit, via anonymous namespace. */
namespace {

template< typename T, T value, T &dest >
struct class_rape {
    class_rape() { dest = value; } // you've been raped in the class!
    static class_rape r;
};
template< typename T, T value, T &dest >
class_rape< T, value, dest > class_rape< T, value, dest >::r;


// Usage (cvt_[w]filebuf is a specialization of GCC basic_filebuf)

typedef bool cvt_filebuf::*cvt_fb_reading_t;
typedef bool cvt_wfilebuf::*cvt_wfb_reading_t;

/* Access these variables, or functions accessing them (applies recursively),
only in anonymous namespace or in non-header file, per one-definition rule. */
cvt_fb_reading_t cvt_filebuf_reading;
cvt_wfb_reading_t cvt_wfilebuf_reading;

template struct class_rape
    < cvt_fb_reading_t, &cvt_filebuf::_M_reading, cvt_filebuf_reading >;
template struct class_rape
    < cvt_wfb_reading_t, &cvt_wfilebuf::_M_reading, cvt_wfilebuf_reading >;

}

Кстати, вот контекст: http://pastie.org/1188625.

Обновление

Я решил проблему с дублированием в своем ответе ниже.Так что теперь я заинтересован в детерминированном, четко определенном решении, которое не включает редактирование какого-либо целевого кода и позволяет одновременно взламывать несколько специализаций шаблона.(Для данного хака требуется новая реализация для каждой целевой специализации шаблона.)

Ответы [ 3 ]

3 голосов
/ 29 сентября 2010

Незаконный доступ:

class ClassIWantToViolate
{
    // Internal State
    public:
        template<typename T> void violate() {} // Do nothing
};

Тогда в вашем коде вы можете нарушить класс следующим образом:

namespace { struct Attack {}; }

template<>
void ClassIWantToViolate::violate<Attack>()
{
     // Access to internal state here.

     // This is your own version of violate based on a local specialization
     // Thus it is unique but still has access to internal state of the class.
}
0 голосов
/ 29 сентября 2010

Бах, было слишком поздно, когда я отправил это ... Я должен был спать на нем.

Я могу избежать как фиаско статического порядка инициализации, так и проблемы дублирования, сделав переменные по-настоящему глобальными, и просто инициализирую их несколько раз. Поскольку значение инициализации всегда одинаково, не имеет значения, когда они происходят. Первая инициализация происходит перед первым доступом, потому что инициализация появляется первой в каждой единице перевода, где доступ может произойти.

typedef bool cvt_filebuf::*cvt_fb_reading_t;
typedef bool cvt_wfilebuf::*cvt_wfb_reading_t;

/* Place accessible variables in global, non-anonymous namespace. */
cvt_fb_reading_t cvt_filebuf_reading;
cvt_wfb_reading_t cvt_wfilebuf_reading;

/* This hack installs a static initializer, so to avoid the ordering fiasco,
make one fresh copy per translation unit, via anonymous namespace. */
namespace {

template< typename T, T value, T &dest >
class class_rape { // change access qualification of hack to guarantee ODR, LOL
    class_rape() { dest = value; } // you've been raped in the class!
    static class_rape r;
};
template< typename T, T value, T &dest >
class_rape< T, value, dest > class_rape< T, value, dest >::r;

template struct class_rape
    < cvt_fb_reading_t, &cvt_filebuf::_M_reading, cvt_filebuf_reading >;
template struct class_rape
    < cvt_wfb_reading_t, &cvt_wfilebuf::_M_reading, cvt_wfilebuf_reading >;

}

/* Accessor functions go here, also outside anonymous namespace. */
0 голосов
/ 29 сентября 2010

Я бы, наверное, пошел с менее умным подходом. Доступ к закрытым членам класса извне - такая редкая вещь, или, по крайней мере, для меня (никогда этого не делал). На моей реализации я смог сделать это за несколько минут ...

  • скопировать fstream в локальный файл проекта, который я назвал evil_fstream.h
  • изменить пространство имен в evil_fstream.h с std на evil
  • удалить все экземпляры private: и protected: из evil_fstream.h

Затем этот код компилируется:

#include <fstream>
#include "evil_fstream.h"

using namespace std;

typedef evil::basic_filebuf<char, char_traits<char> > evil_filebuf_t;

int main() {

   std::basic_filebuf<char, char_traits<char> > fb;

   evil_filebuf_t* efb = (evil_filebuf_t*)&fb;

   efb->_Pcvt; // access a private member

   return 1;
}
...