От новичка до гуру: Курсы программирования на CyberDuff

Может ли указатель на членов обойти уровень доступа члена?

В нашем печально известном litb есть интересная статья о том, как обойти проверка доступа.

Это полностью демонстрируется этим простым кодом:

#include <iostream>

template<typename Tag, typename Tag::type M>
struct Rob { 
  friend typename Tag::type get(Tag) {
    return M;
  }
};

// use
struct A {
  A(int a):a(a) { }
private:
  int a;
};

// tag used to access A::a
struct A_f { 
  typedef int A::*type;
  friend type get(A_f);
};

template struct Rob<A_f, &A::a>;

int main() {
  A a(42);
  std::cout << "proof: " << a.*get(A_f()) << std::endl;
}

Который компилируется и запускается (выход 42) с gcc 4.3.4, gcc 4.5.1, gcc 4.7.0 (см. комментарий пользователя 1131467) и компилируется с Clang 3.0 и Comeau C/C++ 4.3.10.1 в C++ 03 строгий режим и MSVC 2005.

Меня спросил Лучиан в этот ответ, в котором я использовал его, чтобы доказать, что это действительно законно. Я согласен с Лучианом в том, что это странно, однако и Clang, и Comeau являются близкими претендентами на звание наиболее доступных «стандартных» компиляторов (гораздо больше, чем MSVC по умолчанию)...

И я не смог ничего найти в черновиках стандартов, которые у меня есть (n3337 — последняя версия, которую я получил).

Итак... может ли кто-нибудь на самом деле обосновать, что это законно или нет?


  • FYI Это выводит proof:42 с g++-4.7 (Debian 4.7.0-1) 4.7.0 как в -std=c++11, так и в -std=gnu++11 28.03.2012
  • Извините, это моя беда. Это компилируется, то, что не компилируется, было stackoverflow.com/a/6886432/673730 - и я пытался получить доступ частная функция, а не член данных. 28.03.2012
  • Кстати, я все еще ищу ответ на этот вопрос, если бы ответ сработал, это было бы именно то, что я искал, но это не так. 28.03.2012
  • @LuchianGrigore: нет проблем, спасибо за исправление вопроса. 28.03.2012
  • @ user1131467: Спасибо за тестирование. 28.03.2012
  • Я рад, что это работает во всех реализациях. 28.03.2012
  • @JohannesSchaub-litb: Честно говоря, это все еще кажется непреднамеренным эффектом §14.7.2/12. Возможность законного обхода конфиденциальности, вероятно, нежелательна. 28.03.2012

Ответы:


1

Да, это законно. Соответствующий текст находится в §14.7.2/12, в котором говорится о явном создании экземпляра шаблона:

12 Обычные правила проверки доступа не применяются к именам, используемым для указания явных экземпляров. [ Примечание: В частности, аргументы и имена шаблонов, используемые в деклараторе функций (включая типы параметров, типы возвращаемых значений и спецификации исключений), могут быть частными типами или объектами, которые обычно недоступны, и шаблон может быть шаблоном-членом или функцией-членом, которые обычно недоступны. — конец примечания ]

Эмпазис мой.

28.03.2012
  • Ах! Это, наверное, то, что мне больше всего нравится в Стандарте, чтобы иметь полное представление о чем-то, вам просто нужно пройти через все это и собрать кусочки воедино. 28.03.2012
  • @MatthieuM.: Но именно поэтому я ненавижу стандарт! :) РЕДАКТИРОВАТЬ: Ух! 28.03.2012
  • Это должно было быть ироничным ;) Хотя теперь, когда он есть на github, возможно, мы могли бы предложить редактирование, чтобы связать этот абзац из процитированного Джеймсом! 28.03.2012
  • @MatthieuM.: Ах да, я забыл об этом изменении. ... Я позволю тебе сделать это. Я бы, наверное, просто опозорился. 28.03.2012
  • @мат, о, хорошо. вы случайно не знаете URL-адрес github? 28.03.2012
  • @ildjarn о, теперь я вижу. Я думал, ты говоришь о моем маленьком взломе. 28.03.2012
  • @GManNickG: я никогда не отправлял отчет о дефектах, поэтому я связался с сопровождающим основного языка, чтобы попросить его совета. 28.03.2012

  • 2

    Код явно незаконен (и требует диагностики во время компиляции). В соответствии:

    template struct Rob<A_f, &A::a>;
    

    выражение A::a обращается к частному члену A.

    Стандарт очень ясно говорит об этом: управление доступом применяется единообразно ко всем именам, независимо от того, ссылаются ли имена из объявлений или выражений. (§11/4, курсив добавлен). Поскольку a является частным именем в A, любая ссылка на него за пределами A недопустима.

    28.03.2012
  • На самом деле это не является незаконным, исключение добавляется позже для явных экземпляров шаблона. Все, что есть, явно вводит в заблуждение, это все, если не указано иное. Я не буду минусовать, потому что это довольно неинтуитивно. 28.03.2012
  • @GManNickG На самом деле, это неясно, и я думаю, что DR в порядке. В стандарте все означает все, а не все, если не указано иное, и контекст в §14.7.2 может допускать другие интерпретации (хотя они и не очень естественны). Это выглядит как противоречие, что означает, что DR в порядке. 28.03.2012
  • Вы правы, эта квалификация не нужна. 28.03.2012
  • Хотя вы правы (ИМО), указывая на это противоречие в спецификации, это не означает, что код явно незаконен. Это означает, как и для любого серьезного юридического языка, если какое-либо правило этого закона окажется дефектным или незаконным, оно должно быть заменено правилом, которое как можно лучше соответствует намеченной цели. (оговорка о делимости). Нельзя взять правило и на основании противоречия интерпретировать его вопреки намерениям комитета. 28.03.2012
  • Вы также можете просмотреть проблемы на странице текущих проблем wg21 и отклонить буквально любую программу из-за того, что не применили разумных исправлений дефектных правил в Стандарте. 28.03.2012
  • @JamesKanze: я планировал отправить DR с просьбой о перекрестных ссылках. Если вы отправляете один из-за противоречия, сообщите мне, поскольку я не хочу отправлять дубликат. 28.03.2012
  • @MatthieuM. Я думаю, что это может означать нечто иное, чем то, что мы думали. имя имеет двойное значение в спецификации. Одним из значений является идентификатор, объявленный в декларативной области. Этот идентификатор (или оператор-функция-идентификатор, литеральный-оператор-идентификатор и т. д.) после этого называется именем. Например, объявление члена объявляет имя-члена своего класса. Объявление класса объявляет имя класса в окружающей области видимости и в самом себе (внедренное имя класса). Другим значением имени является идентификатор, идентификатор оператора-функции и т. д., который появляется в выражениях или объявлениях. 28.03.2012
  • Теперь обратите внимание на то, что он точно говорит: Контроль доступа применяется одинаково ко всем именам, независимо от того, ссылаются ли имена из объявлений или выражений.. Если бы речь шла о втором значении имени (а мы до сих пор думали, что это так), то... ссылки из деклараций или выражений не имели бы никакого смысла. Вы не можете ссылаться на объявление или выражение из самого себя! Следовательно, речь идет о первом значении имени. Например, на имя члена может ссылаться выражение id в выражении доступа к члену класса. 28.03.2012
  • На самом деле, если читать в контексте 11/4, кажется очень ясным, что речь идет о значении #1 имени. 29.03.2012
  • @JohannesSchaub-litb: Ах, спасибо... Мне было трудно определить эти термины, но если они их перегружают... Что ж, в данном случае это не было бы противоречием, но все равно было бы хорошо (я думаю ) для перекрестной ссылки на раздел для тех из нас, плохих читателей, которые пытаются разобраться в правилах. 29.03.2012
  • @JohannesSchaub-litb Когда я написал явно незаконно, я не знал о противоречащем тексте в §14.7.2/12. Зная это, я бы, наверное, написал, что это незаконно при самой разумной интерпретации стандарта, но здесь стандарт нуждается в пояснении. Цель §11/4 очевидна; цель §14.7.2/12 менее ясна. 29.03.2012
  • @james как автор класса A, как бы вы иначе написали явное создание экземпляра, не нарушая доступ? 29.03.2012
  • Новые материалы

    Представляем Narwhal Technologies (Nrwl)
    6 декабря 2016 г. Маунтин-Вью, Калифорния С тех пор, как Виктор Савкин и я (Джефф Кросс) присоединились к команде Angular в Google на заре Angular 1, Angular продемонстрировал феноменальный..

    Путь AWS  — «Изучение машинного обучения — 10 начинающих ИИ и машинного обучения на AWS».
    Универсальный ресурсный центр для изучения искусственного интеллекта и машинного обучения. НОЛЬ или ГЕРОЙ, начните свое путешествие здесь. Получите решения и пройдите обучение у экспертов AWS...

    5 простых концепций Python, ставших сложными
    #заранее извините 1) Переменные x = 4 y = 5 Переменная в Python — это символическое представление объекта. После присвоения некоторого объекта переменной Python мы приобретаем..

    «Освоение вероятности: изучение совместной, предельной, условной вероятности и теоремы Байеса —…
    Виды вероятности: Совместная вероятность Предельная вероятность Условная вероятность Диаграмма Венна в вероятностях: В “Set Theory” мы создаем диаграмму Венна...

    Основы Spring: Bean-компоненты, контейнер и внедрение зависимостей
    Как лего может помочь нашему пониманию Когда мы начинаем использовать Spring, нам бросают много терминов, и может быть трудно понять, что они все означают. Итак, мы разберем основы и будем..

    Отслеживание состояния с течением времени с дифференцированием снимков
    Время от времени что-то происходит и революционизирует часть моего рабочего процесса разработки. Что-то более забавное вместо типичного утомительного и утомительного процесса разработки. В..

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