Re[23]: Есть ли будущее у Native Code?
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.06.09 11:30
Оценка:
Здравствуйте, swined, Вы писали:
S>как вариант — поддержка всех этих конструкций на уровне байткода. их не так много, а выигрыш должен быть заметным.
За счёт чего? Выигрыш может случиться только за счёт отказа от других инструкций, которые теперь не нужно будет верифицировать.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: Есть ли будущее у Native Code?
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.06.09 11:30
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

S>>Но, к примеру, в x86 ассемблере никаких "переменных" нет. Есть регистры и стек; компилятор генерирует исключительно обращения к ним.


PD>В школу! В первый класс!!!

Да, по запарке написал "стек" вместо памяти. В том смысле, что сам по себе стек ничего нового к модели "регистры+память" не добавляет, это просто CISC-шорткат для инструкций косвенной адресации.

PD>Обоснуй. Кто мне мешает там кучу завести ?

Флаг R/O, надо полагать.
PD>И не надо. Его туда (в R/O) должен помещать специальный конструктор или new или вместе
А специальный конструктор будет Волей Божьей работать, или как?
PD>immutable Type a = new immutable Type(...);
Ага. Надо полагать, это будет разворачиваться в псевдокод "снять защиту со страницы; положить данные; вернуть защиту на страницу".
В середине этого все остальные объекты в пределах этой же страницы будут точно так же изменчивы. Упс, дыра получилась.
S>>Использование аппаратной защиты для обеспечения иммутабельности на реальной аппаратуре просадит производительность.
PD>Нет. Я уже тысячу раз объяснял — проверки записи в процессоре аппаратны и делаются всегда при записи.
Это-то да, но стоимость переключения флагов страницы при вызовах конструктора/деструктора куда денется?
PD>А зачем тебе доступ с этой гранулярностью ? Никаких проблем и сейчас нет.
Я показал проблему выше. Может быть, у неё есть какое-то очевидное решение?

PD>А хочешь, я тебе секрет открою? В С++ есть иммутабельный объект. Защищается именно механизмом страничной защиты. Догадался, о чем речь идет ?

Надо полагать, ты про нулевой адрес.

PD>Мне уровни абстракции нужны в этих рассуждениях , как корове седло. Оставь их для других случаев, там я могу их обсуждать. А здесь я одно утверждаю — что ни делайте, какие средства ни придумывайте, но пока аппаратура нынешняя. все равно вы мимо этого слоя не пройдете. Вот и все.

С тем же успехом можно утверждать, что и мимо микрокода пройти нельзя. Тем не менее, ты совершенно спокойно его игнорируешь в своих рассуждениях, несмотря на его принудительное наличие между тобой и кремнием.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[24]: Есть ли будущее у Native Code?
От: swined Россия  
Дата: 25.06.09 11:41
Оценка: -1 :)))
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, swined, Вы писали:

S>>как вариант — поддержка всех этих конструкций на уровне байткода. их не так много, а выигрыш должен быть заметным.
S>За счёт чего? Выигрыш может случиться только за счёт отказа от других инструкций, которые теперь не нужно будет верифицировать.

большинство циклов — foreach. проход по коллекциям, массивам итд. верифицировать такое в разы проще, чем ковырять то, во что оно в итоге развернется. ну и оставшийся один из тысячи обычный цикл, где по логике программы действительно надо перебрать все индексы, будет верифицирован как обычный цикл.
Re[17]: Есть ли будущее у Native Code?
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.06.09 11:47
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>А поподробнее можно ? Вот передаем некоей Win API не тот буфер, не того размера. Насильно передаем. Объясни, что же будет.
Странно, что такие простые вещи нужно объяснять. Ищем уязвимость в существующем софте (как правило, она состоит именно в переполнении буфера), при помощи чего вызываем исполнение злонамеренного кода в контексте доверенного процесса.
Напрямую лезть в нулевое кольцо этому коду не надо — ему достаточно инсталлировать в систему драйвер, оставаясь в рамках третьего кольца. После ближайшего рестарта (или даже без него) система самостоятельно запустит нужный код в нулевом кольце, рядом со всеми остальными драйверами.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[25]: Есть ли будущее у Native Code?
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.06.09 12:04
Оценка:
Здравствуйте, swined, Вы писали:
S>большинство циклов — foreach. проход по коллекциям, массивам итд. верифицировать такое в разы проще, чем ковырять то, во что оно в итоге развернется. ну и оставшийся один из тысячи обычный цикл, где по логике программы действительно надо перебрать все индексы, будет верифицирован как обычный цикл.
Ты, по-моему, чего-то не понимаешь. Совершенно неважно, сколько там foreach. Верификация того, "во что оно в итоге развернётся" уже занимает O(N). Что ты собрался ускорять?
Устранять проверки границ в случае, если foreach шарашит по массиву?

Ну так этим занимается JIT, который работает уже после верификатора.

Хочешь математически доказать, что обращений за границы не будет вообще никогда-никогда, а не только в случае for (var i=0; i< a.Length; i++)?
Для зависимых типов это возможно — но выигрыш в производительности будет недостаточно большим.
Фишка в том, что для успешного вывода типов нужна "хорошая" алгебра, которая была бы замкнута относительно заметного количества операций.
В частности, с Null/Notnull это так.
Легко ввести тип "чётное число" по тем же причинам.
А вот ввести тип "валидный аргумент операции myArray[i]" — тяжело. Потому, что любая арифметика выводит значение за пределы этого типа.
И тебе, соответственно, придётся делать проверки при каждой операции.
То есть index++, index+=2, index*=2 и так далее будут бросать OutOfRangeException.
Стоимость этой лишней проверки будет пренебрежимой только если удастся объединить её с проверкой условия выхода из цикла, и если обращений к массиву внутри цикла достаточно много.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[27]: Есть ли будущее у Native Code?
От: WolfHound  
Дата: 25.06.09 12:31
Оценка: +1
Здравствуйте, thesz, Вы писали:

T>В Cayenne, Agda и тп нет оператора casetype. Поэтому ты не можешь типы в Cayenne, Agda и тп не могут зависеть от значений времени выполнения.

Тут я немного криво выразился.

T>А вот связать значения из типов со значениями времени выполнения путём доказательств возможно.

Я именно это и имел в виду.

T>И в C++ тоже (хотя и не очень уверен).

Я в свое время изучил все возможные метаизвращения на С++ но не вижу никакой возможности сделать что-то подобное тому что может агда.
На С++ не сделать ничего типа:
mult : ∀i , j , k : Nat ⇒ Matrix i j → Matrix j k → Matrix i k

При условии что i, j и k не известны на этапе компиляции.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[25]: Есть ли будущее у Native Code?
От: WolfHound  
Дата: 25.06.09 12:41
Оценка:
Здравствуйте, swined, Вы писали:

S>большинство циклов — foreach. проход по коллекциям, массивам итд. верифицировать такое в разы проще, чем ковырять то, во что оно в итоге развернется. ну и оставшийся один из тысячи обычный цикл, где по логике программы действительно надо перебрать все индексы, будет верифицирован как обычный цикл.

Вопиющая безграмотность.
Пожалуйста больше не рассуждай на тему верификации.
Ссылки для самообразования я уже не раз давал.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[19]: Есть ли будущее у Native Code?
От: Pavel Dvorkin Россия  
Дата: 25.06.09 13:14
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Pavel Dvorkin, Вы писали:


S>>>Но, к примеру, в x86 ассемблере никаких "переменных" нет. Есть регистры и стек; компилятор генерирует исключительно обращения к ним.


PD>>В школу! В первый класс!!!

S>Да, по запарке написал "стек" вместо памяти. В том смысле, что сам по себе стек ничего нового к модели "регистры+память" не добавляет, это просто CISC-шорткат для инструкций косвенной адресации.

То-то, по утверждению Нортона, того, кто исключил стек из архитектуры IBM-360, "сослали во внутрифирменный аналог Сибири". Подумай, добавляет он или нет.

PD>>Обоснуй. Кто мне мешает там кучу завести ?

S>Флаг R/O, надо полагать.

Не помешает. Его снимут, запишут и поставят. Тут другие проблемы есть — во время этой операции страница не R/O. Да, тут не очевидно, но решение ИМХО найти можно. Тем более в вашей .Net. Она же не может туда обратиться по ошибке, она же не может куда попало обращаться по определению. Что же касается C++ — да, возможны проблемы, но это те же проблемы, что и сейчас. И сейчас некорректный указатель может все испортить, и тут тоже сможет.

PD>>И не надо. Его туда (в R/O) должен помещать специальный конструктор или new или вместе

S>А специальный конструктор будет Волей Божьей работать, или как?

Нет, на базе команд процессора x86 или иного

PD>>immutable Type a = new immutable Type(...);

S>Ага. Надо полагать, это будет разворачиваться в псевдокод "снять защиту со страницы; положить данные; вернуть защиту на страницу".
S>В середине этого все остальные объекты в пределах этой же страницы будут точно так же изменчивы. Упс, дыра получилась.

См. выше. Да, это некоторая проблема, я ее вижу. Но не нерешаемая.

S>>>Использование аппаратной защиты для обеспечения иммутабельности на реальной аппаратуре просадит производительность.

PD>>Нет. Я уже тысячу раз объяснял — проверки записи в процессоре аппаратны и делаются всегда при записи.
S>Это-то да, но стоимость переключения флагов страницы при вызовах конструктора/деструктора куда денется?

См. мой тест где-то в прошлой дискуссии, я проверял работу VirtualProtect, получилось примерно миллион в секунду. Да, вызов ядра обычно медленный, но не в данном случае. Тут не задействуется драйвер, просто-напросто в PTE изменяется один (или 2 в x64) бит(а).


PD>>А хочешь, я тебе секрет открою? В С++ есть иммутабельный объект. Защищается именно механизмом страничной защиты. Догадался, о чем речь идет ?

S>Надо полагать, ты про нулевой адрес.

Нет. Этот иммутабельный объект — секция кода . Что не мешает ее менять, но тогда включится автоматом write on copy механизм.

PD>>Мне уровни абстракции нужны в этих рассуждениях , как корове седло. Оставь их для других случаев, там я могу их обсуждать. А здесь я одно утверждаю — что ни делайте, какие средства ни придумывайте, но пока аппаратура нынешняя. все равно вы мимо этого слоя не пройдете. Вот и все.

S>С тем же успехом можно утверждать, что и мимо микрокода пройти нельзя. Тем не менее, ты совершенно спокойно его игнорируешь в своих рассуждениях, несмотря на его принудительное наличие между тобой и кремнием.

Все, что ниже ассемблера — не мое дело, ибо мне не подвластно. Для схемотехника — можно, но я им не являюсь.
With best regards
Pavel Dvorkin
Re[28]: Есть ли будущее у Native Code?
От: thesz Россия http://thesz.livejournal.com
Дата: 25.06.09 13:28
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, thesz, Вы писали:


T>>В Cayenne, Agda и тп нет оператора casetype. Поэтому ты не можешь типы в Cayenne, Agda и тп не могут зависеть от значений времени выполнения.

WH>Тут я немного криво выразился.

Я тоже не подкачал, надо отметить.

T>>И в C++ тоже (хотя и не очень уверен).

WH>Я в свое время изучил все возможные метаизвращения на С++ но не вижу никакой возможности сделать что-то подобное тому что может агда.
WH>На С++ не сделать ничего типа:
WH>
WH>mult : ∀i , j , k : Nat ⇒ Matrix i j → Matrix j k → Matrix i k
WH>

WH>При условии что i, j и k не известны на этапе компиляции.

Хорошо, C++ вычеркиваем.

В моей программе как раз что-то наподобие mult. Правда, i,j и k имеют значения из множества типов, составляемых из data Z и data S n.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[20]: Есть ли будущее у Native Code?
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.06.09 13:46
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>То-то, по утверждению Нортона, того, кто исключил стек из архитектуры IBM-360, "сослали во внутрифирменный аналог Сибири". Подумай, добавляет он или нет.

Не добавляет.

PD>Не помешает. Его снимут, запишут и поставят. Тут другие проблемы есть — во время этой операции страница не R/O.

Именно об этом я и писал.

PD>Да, тут не очевидно, но решение ИМХО найти можно. Тем более в вашей .Net. Она же не может туда обратиться по ошибке, она же не может куда попало обращаться по определению.


Правильно. А зачем тогда взводить R/O, если мы по определению не можем обращаться куда попало?

PD>Что же касается C++ — да, возможны проблемы, но это те же проблемы, что и сейчас. И сейчас некорректный указатель может все испортить, и тут тоже сможет.

Совершенно верно. Именно поэтому аппаратная защита — сакс. Там, где она поможет, она не нужна. А там, где нужна — она не поможет.

PD>См. выше. Да, это некоторая проблема, я ее вижу. Но не нерешаемая.

Решение — в студию. Хотя бы набросок.
PD>См. мой тест где-то в прошлой дискуссии, я проверял работу VirtualProtect, получилось примерно миллион в секунду. Да, вызов ядра обычно медленный, но не в данном случае. Тут не задействуется драйвер, просто-напросто в PTE изменяется один (или 2 в x64) бит(а).
Ок. А скорость вызова конструктора в дотнет не мерил? Каковы будут накладные расходы при вызове VirtualProtect на каждый чих? Хоть при "деструкторе" и не надо будет её вызывать отдельно, но быстродействие кучи всё же снизится.

PD>Нет. Этот иммутабельный объект — секция кода . Что не мешает ее менять, но тогда включится автоматом write on copy механизм.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[21]: Есть ли будущее у Native Code?
От: thesz Россия http://thesz.livejournal.com
Дата: 25.06.09 14:58
Оценка:
S>Правильно. А зачем тогда взводить R/O, если мы по определению не можем обращаться куда попало?

Теория это одно, практика — с кратковременными сбоями аппаратуры, — это другое.

PD>>Что же касается C++ — да, возможны проблемы, но это те же проблемы, что и сейчас. И сейчас некорректный указатель может все испортить, и тут тоже сможет.

S>Совершенно верно. Именно поэтому аппаратная защита — сакс. Там, где она поможет, она не нужна. А там, где нужна — она не поможет.

Чтобы не повторяться: http://rsdn.ru/forum/philosophy/3440056.1.aspx
Автор: thesz
Дата: 23.06.09
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[22]: Есть ли будущее у Native Code?
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.06.09 03:02
Оценка:
Здравствуйте, thesz, Вы писали:

T>Теория это одно, практика — с кратковременными сбоями аппаратуры, — это другое.

Не очень понял про кратковременные сбои.

T>Чтобы не повторяться: http://rsdn.ru/forum/philosophy/3440056.1.aspx
Автор: thesz
Дата: 23.06.09

Не понял, какое отношение кэширование имеет к аппратной изоляции.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[21]: Есть ли будущее у Native Code?
От: Pavel Dvorkin Россия  
Дата: 26.06.09 04:27
Оценка: 6 (1)
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Pavel Dvorkin, Вы писали:


PD>>То-то, по утверждению Нортона, того, кто исключил стек из архитектуры IBM-360, "сослали во внутрифирменный аналог Сибири". Подумай, добавляет он или нет.

S>Не добавляет.

Опять двойка по ассемблеру. Подумай, не может ли состояние стека измениться вообще без выполнения каких бы то ни было команд

PD>>См. выше. Да, это некоторая проблема, я ее вижу. Но не нерешаемая.

S>Решение — в студию. Хотя бы набросок.

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

В общем, все что я сказал про изменение атрибутов страницы с R/O на R/W и обратно, полностью отменяется. Не надо атрибуты вообще менять, никогда. Никаких вызовов VirtualProtect. Страница должна всегда находиться в R/O состоянии. Так что все функции, которые попытаются изменить объект, гарантированно провалятся.

Остается маленький вопрос — а как же конструктор-то сможет в таком случае объект создать или операция newconst его разместить ? Решение чрезвычайно простое и элегантное. Конструктор и newconst (и только они!, ну еще, если надо, деструктор и deleteconst )будут работать с этой страницей по другому виртуальному адресу, с атрибутами R/W. При этом операция newconst будет возвращать R/O адрес в качестве адреса этого объекта, поэтому все функции будут работать с ним по R/O. А конструктор будет преобразовывать R/O адрес в R/W адрес и работать без всяких проблем. Все!!!

Таким образом, остается только иметь механизм , позволяющий для данной страницы с атрибутом R/O и виртуальным адресом pHeapRO, создать новый виртуальный адрес pHeapRW, который через механизм трансляции адреса показывает на ту же физическую страницу, только с атрибутами R/W. Иными словами, завести еще один PTE для некоторой страницы.

Для страниц, выделенных с помощью VirtualAlloc, я способа такое сделать в Win32 не знаю, думаю, что его нет. Но задача элементарно решается с помощью memory-mapped файлов, причем собственно файл и не понадобится, так как делать все можно на swap-файле (первый параметр CreateFileMapping должен быть INVALID_HANDLE_VALUE)

Вот вполне работающий пример


#include "stdafx.h"
#include "windows.h"
int delta; // реально нужен класс HeapManager, который будет хранить в себе эту delta в том числе
const int heapsize = 1024 * 1024;


class A{
    int x;
public:
    void Ctor(int _x) // только имитация. В действительности будет, конечно, несколько сложнее
    { 
        char* pWriteTo = (char*) this + delta;
        *((int*)pWriteTo) = _x;
    }
    void setx(int _x) 
    { 
        x = _x;
    }
    int getx()
    {
        return x;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, heapsize,NULL);
    char* pHeapRW = (char*)MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, heapsize);
    char* pHeapRO = (char*)MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, heapsize);
    delta = pHeapRW - pHeapRO;

        // все вышенаписанное, конечно, в класс HeapManager

    A* pA = (A*) pHeapRO; // прототип выделения памяти в куче, то есть операции newconst. Я просто беру начало кучи
    pA->Ctor(100); // прототип вызова конструктора
    int y = pA->getx(); // эту функцию можно вызывать, она объект не изменяет. Хотя явно const в ней специально не написано
    pA->setx(99); // а эту нельзя, здесь AV

    // очистка и обработка ошибок опущены

    return 0;
}



В C# куча нефрагментирована, поэтому delta будет абсолютной константой. В Win32 если делать эту кучу так же, как и существующие, куча будет фрагментированной, поэтому вместо простого прибавления delta придется устроить чуть-чуть более сложный механизм (список из этих delta для отдельных фрагментов кучи)

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

Плата за решение.

1. Дополнительный PTE на каждую страницу. Это 4(8) байт на 4096 байт, то есть 0.1-0.2%.
2. Сокращается доступный размер адресного пространства. В пределе, если все 2 GB юзеровского пространства будут заняты этой константной кучей, мы будем иметь реально только 1GB. Но это уж слишком нереальная ситуация, в нормальной практике дополнительный расход будет несколько процентов. А уж в Win64 это вообще не будет иметь никакого значения — там сколько ни бери, все равно останется море.
3. Дополнительные расходы по времени — одна операция сложения
With best regards
Pavel Dvorkin
Re[18]: Есть ли будущее у Native Code?
От: Pavel Dvorkin Россия  
Дата: 26.06.09 04:38
Оценка: -2
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Pavel Dvorkin, Вы писали:

PD>>А поподробнее можно ? Вот передаем некоей Win API не тот буфер, не того размера. Насильно передаем. Объясни, что же будет.
S>Странно, что такие простые вещи нужно объяснять. Ищем уязвимость в существующем софте (как правило, она состоит именно в переполнении буфера), при помощи чего вызываем исполнение злонамеренного кода в контексте доверенного процесса.

Если в существующем софте есть ошибка, то все возможно. Но по постингу WolfHound можно понять так, что достаточно переполнить буфер , и мы попадем в страницы, находящиеся под контролем системы. А причина банальная — он не вполне понимает отличие виртуальной памяти от физической, он считает, что если выйти за пределы страницы, то мы попадем на соседнюю страницу физической памяти, которая может принадлежать системе
With best regards
Pavel Dvorkin
Re[22]: Есть ли будущее у Native Code?
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.06.09 05:01
Оценка: 1 (1) +1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Опять двойка по ассемблеру. Подумай, не может ли состояние стека измениться вообще без выполнения каких бы то ни было команд

Конечно же может. Но к модели "память/регистры" это по-прежнему ничего не добавляет.

PD>В общем, все что я сказал про изменение атрибутов страницы с R/O на R/W и обратно, полностью отменяется. Не надо атрибуты вообще менять, никогда. Никаких вызовов VirtualProtect. Страница должна всегда находиться в R/O состоянии. Так что все функции, которые попытаются изменить объект, гарантированно провалятся.


PD>Остается маленький вопрос — а как же конструктор-то сможет в таком случае объект создать или операция newconst его разместить ? Решение чрезвычайно простое и элегантное. Конструктор и newconst (и только они!, ну еще, если надо, деструктор и deleteconst )будут работать с этой страницей по другому виртуальному адресу, с атрибутами R/W. При этом операция newconst будет возвращать R/O адрес в качестве адреса этого объекта, поэтому все функции будут работать с ним по R/O. А конструктор будет преобразовывать R/O адрес в R/W адрес и работать без всяких проблем. Все!!!

Осталось только гарантировать, что никто другой не станет обращаться к этим R/W страницам.

PD>В C# куча нефрагментирована, поэтому delta будет абсолютной константой. В Win32 если делать эту кучу так же, как и существующие, куча будет фрагментированной, поэтому вместо простого прибавления delta придется устроить чуть-чуть более сложный механизм (список из этих delta для отдельных фрагментов кучи)


PD>Константный конструктор может ничем не отличаться от обычного. Впрочем, лучше если он проверит, не делается ли при конструировании константы попытки записать в нее указатели на другие неконстантные объекты.

Толково придумано. Я бы не допёр. (с).

PD>Плата за решение.


PD>1. Дополнительный PTE на каждую страницу. Это 4(8) байт на 4096 байт, то есть 0.1-0.2%.

PD>2. Сокращается доступный размер адресного пространства. В пределе, если все 2 GB юзеровского пространства будут заняты этой константной кучей, мы будем иметь реально только 1GB. Но это уж слишком нереальная ситуация, в нормальной практике дополнительный расход будет несколько процентов. А уж в Win64 это вообще не будет иметь никакого значения — там сколько ни бери, все равно останется море.
PD>3. Дополнительные расходы по времени — одна операция сложения
Ок. А теперь давай посчитаем выгоды, и сравним их с программно-immutable объектами.
Ну и попробуем понять, чем же это всё таки отличается от immutable-типов. Заметь, что ты не собираешься менять статус объекта в течение всего времени его жизни — он рождается константным и остаётся константным. Такие свойства как раз характерны для типов.
Теперь возьмем два объекта одного класса (в терминах С++), которые отличаются только тем, как распределены — один при помощи твоей злой магии, другой нормальным образом.
Чем они отличаются в программе? Тем, что на одном из них вызов части методов будет гарантированно вызывать AV — как у тебя в setx.
Наверное, лучше было бы сделать так, чтобы компилятор не давал делать такие вызовы, не так ли? Зачем компилировать заведомо некорректную программу?

Ок, мы, в принципе, можем попробовать описать эту абстракцию в С++ при помощи механики const, хотя я не уверен, что оператор new имеет право возвращать такой указатель. Но это уже, в некотором смысле, дело техники. По крайней мере, у нас "забесплатно" будет два подтипа для каждого класса — один const, другой mutable. У одного из них часть методов запрещены.

Но это нам по-прежнему ничего не даст. Как я уже объяснял, правила совместимости типов в С++ реализованы крайне неудачно. Если я пишу
void IWantToBenefitFromImmutability(const int& shouldntChange)
{
}

, то никаких обязательств на вызывающего я не накладываю. Как мне потребовать, чтобы в меня передавали исключительно RO объекты?
Получается, что нужен какой-то другой язык. В котором правила совместимости типов жестче. Или не пользоваться зависимыми типами из С++, а вместо этого описывать иммутабл-тип руками для каждого конкретного случая (как и сделано в дотнете).
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[19]: Есть ли будущее у Native Code?
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.06.09 05:01
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Если в существующем софте есть ошибка, то все возможно. Но по постингу WolfHound можно понять так, что достаточно переполнить буфер , и мы попадем в страницы, находящиеся под контролем системы.
Нет. По постингу WolfHound понятно, что переполнение буфера — основная уязвимость, через которую происходит эскалация привилегий.
PD>А причина банальная — он не вполне понимает отличие виртуальной памяти от физической, он считает, что если выйти за пределы страницы, то мы попадем на соседнюю страницу физической памяти, которая может принадлежать системе
Очень сомневаюсь, что WolfHound так считает. И уж тем более, что он незнаком с архитектурой памяти на x86. Не надо заведомо принимать своих собеседников за идиотов.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[20]: Есть ли будущее у Native Code?
От: Pavel Dvorkin Россия  
Дата: 26.06.09 05:09
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Очень сомневаюсь, что WolfHound так считает. И уж тем более, что он незнаком с архитектурой памяти на x86. Не надо заведомо принимать своих собеседников за идиотов.


За идиота я никого не принимаю, но судя по его дискуссии со мной в последние дни, он элементарно не понимает некоторые базовые принципы.
With best regards
Pavel Dvorkin
Re[23]: Есть ли будущее у Native Code?
От: Pavel Dvorkin Россия  
Дата: 26.06.09 05:42
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Pavel Dvorkin, Вы писали:


PD>>Опять двойка по ассемблеру. Подумай, не может ли состояние стека измениться вообще без выполнения каких бы то ни было команд

S>Конечно же может. Но к модели "память/регистры" это по-прежнему ничего не добавляет.

К модели не добавляет. А вот к утверждению "это просто CISC-шорткат для инструкций косвенной адресации" еще как добавляет.

PD>>В общем, все что я сказал про изменение атрибутов страницы с R/O на R/W и обратно, полностью отменяется. Не надо атрибуты вообще менять, никогда. Никаких вызовов VirtualProtect. Страница должна всегда находиться в R/O состоянии. Так что все функции, которые попытаются изменить объект, гарантированно провалятся.


PD>>Остается маленький вопрос — а как же конструктор-то сможет в таком случае объект создать или операция newconst его разместить ? Решение чрезвычайно простое и элегантное. Конструктор и newconst (и только они!, ну еще, если надо, деструктор и deleteconst )будут работать с этой страницей по другому виртуальному адресу, с атрибутами R/W. При этом операция newconst будет возвращать R/O адрес в качестве адреса этого объекта, поэтому все функции будут работать с ним по R/O. А конструктор будет преобразовывать R/O адрес в R/W адрес и работать без всяких проблем. Все!!!

S>Осталось только гарантировать, что никто другой не станет обращаться к этим R/W страницам.

В .Net вы гарантируете, что никто без unsafe не сможет вообще никуда в неположенное место обращаться. Так что уж позаботьтесь о том, чтобы только реализация константных конструкторов могла туда обращаться. В конце концов этих самих адресов я в .Net вообще не вижу. они там внутри где-то. Ну и манипулируйте ими корректно.
Ну а в С++, конечно, никто такой гарантии не даст, но это обычная проблема — никто же не даст гарантии, что кто-то просто левым способом не испортит вполне обычную переменную.

PD>>В C# куча нефрагментирована, поэтому delta будет абсолютной константой. В Win32 если делать эту кучу так же, как и существующие, куча будет фрагментированной, поэтому вместо простого прибавления delta придется устроить чуть-чуть более сложный механизм (список из этих delta для отдельных фрагментов кучи)


PD>>Константный конструктор может ничем не отличаться от обычного. Впрочем, лучше если он проверит, не делается ли при конструировании константы попытки записать в нее указатели на другие неконстантные объекты.

S>Толково придумано. Я бы не допёр. (с).

PD>>Плата за решение.


PD>>1. Дополнительный PTE на каждую страницу. Это 4(8) байт на 4096 байт, то есть 0.1-0.2%.

PD>>2. Сокращается доступный размер адресного пространства. В пределе, если все 2 GB юзеровского пространства будут заняты этой константной кучей, мы будем иметь реально только 1GB. Но это уж слишком нереальная ситуация, в нормальной практике дополнительный расход будет несколько процентов. А уж в Win64 это вообще не будет иметь никакого значения — там сколько ни бери, все равно останется море.
PD>>3. Дополнительные расходы по времени — одна операция сложения
S>Ок. А теперь давай посчитаем выгоды, и сравним их с программно-immutable объектами.
S>Ну и попробуем понять, чем же это всё таки отличается от immutable-типов. Заметь, что ты не собираешься менять статус объекта в течение всего времени его жизни — он рождается константным и остаётся константным. Такие свойства как раз характерны для типов.

Да, конечно. Собственно говоря, имеем 2 одинаково устроенные кучи — для констант и переменных. Перенесение из одной в другую — только через полное клонирование.

S>Теперь возьмем два объекта одного класса (в терминах С++), которые отличаются только тем, как распределены — один при помощи твоей злой магии, другой нормальным образом.

S>Чем они отличаются в программе? Тем, что на одном из них вызов части методов будет гарантированно вызывать AV — как у тебя в setx.

Совершенно верно. Он неизменяем.

S>Наверное, лучше было бы сделать так, чтобы компилятор не давал делать такие вызовы, не так ли? Зачем компилировать заведомо некорректную программу?


Ну мы опять за то же. Нет, не лучше. Я тебе уже говорил — ставя иммутабельность на тип, ты подвергаешься очень серьезным ограничениям. В реальной жизни нужно иметь и переменные этого типа и константы. Со строками у вас так и получилось — string для констант, StringBiulder для переменных. Для строк это сойдет. А для других классов — нет. Вот хочу я неизменяемый ArrayList , например. То есть хочу я следующее — однажды его сконструировать из какого-то источника и никогда больше не менять. И чтобы это сделать на иммутабельных типах, тебе придется еще один класс ImmutableArrayList соорудить (ну как наследника хоть, что ли). Вас и за пару string-StringBuilder то и дело покусывают, а уж если вы все классы начнете дублировать — просто смеяться будут. А я только добавлю константный конструктор и операцию newconst (впрочем, она не к классу вообще относится), и все, но изменить его не удастся. А в конечном счете одно мне нужно — гарантировать, что он не испортится

Кстати, сейчас подумал. В С++ операция new и конструктор — это, в общем, две независимые вещи. Но в C# это по существу тандем, так что если делается newconst Type(...), то среда, распознав, что создается константа, может автоматом заставить конструктор проверять, не делается ли попыток в нем записать ссылку на неконстантный объект ( а это очень просто, как ты понимаешь — по значению адреса). Так что, возможно, даже не понадобится писать специальный константный конструктор. Но это надо додумывать как следует, гарантии, что это утверждение корректно, я не дам.


S>Ок, мы, в принципе, можем попробовать описать эту абстракцию в С++ при помощи механики const, хотя я не уверен, что оператор new имеет право возвращать такой указатель. Но это уже, в некотором смысле, дело техники.


Ну естественно, я не мог написать это на настоящем С++. Мне не годится new, даже если я ее перекрою, так как не могу же я ее двумя способами перекрыть . Мне нужна для этого модификация языка и введение операции newconst


>По крайней мере, у нас "забесплатно" будет два подтипа для каждого класса — один const, другой mutable. У одного из них часть методов запрещены.


S>Но это нам по-прежнему ничего не даст. Как я уже объяснял, правила совместимости типов в С++ реализованы крайне неудачно.


Так, стоп. Я не намерен обсуждать сейчас, что хорошо в С++ и что нет. Я предложил идею создания и размещения константых объектов, она, как ты вполне видишь, от языка не зависит, так как реализована на чисто Win API. Окружи то, что я написал, соответствующим кодом хоть на .Net, хоть на чем угодно еще и используй
With best regards
Pavel Dvorkin
Re[24]: Есть ли будущее у Native Code?
От: Pavel Dvorkin Россия  
Дата: 26.06.09 05:56
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

S>>Ну и попробуем понять, чем же это всё таки отличается от immutable-типов. Заметь, что ты не собираешься менять статус объекта в течение всего времени его жизни — он рождается константным и остаётся константным. Такие свойства как раз характерны для типов.


PD>Да, конечно. Собственно говоря, имеем 2 одинаково устроенные кучи — для констант и переменных. Перенесение из одной в другую — только через полное клонирование.


Смешная и скорее всего бесполезная идея. Можно ввести специальный режим, при входе в который все константы станут изменяемыми, а при выходе из которого — опять неизменяемыми

HeapManager.SetMutable();
// теперь меняй их как хочешь
HeapManager.SetImMutable();
// все, они опять закрыты

А может, и не бесполезная. В .Net куча одна, а в Win32 их много можно создать. Ну вот и создадим кучу констант, которые, если быть честным, не то чтобы уж совсем константы, но 99% времени должны быть неизменяемыми, а изменяться могут только в строго определенных местах, в особых местах, когда, скажем, замораживаются все остальные потоки. А в другой такой куче то же самое, но места другие
With best regards
Pavel Dvorkin
Re[24]: Есть ли будущее у Native Code?
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.06.09 06:26
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>>Опять двойка по ассемблеру. Подумай, не может ли состояние стека измениться вообще без выполнения каких бы то ни было команд
S>>Конечно же может. Но к модели "память/регистры" это по-прежнему ничего не добавляет.
PD>К модели не добавляет. А вот к утверждению "это просто CISC-шорткат для инструкций косвенной адресации" еще как добавляет.
И что именно оно добавляет к этому утверждению? Что там такого происходит со стеком, что невыразимо в терминах inc ESP и mov? Ты блин как прапорщик: "не из дерева, а из того же материала". Я советую тебе научиться отличать знание от понимания.

PD>>>В общем, все что я сказал про изменение атрибутов страницы с R/O на R/W и обратно, полностью отменяется. Не надо атрибуты вообще менять, никогда. Никаких вызовов VirtualProtect. Страница должна всегда находиться в R/O состоянии. Так что все функции, которые попытаются изменить объект, гарантированно провалятся.


PD>>>Остается маленький вопрос — а как же конструктор-то сможет в таком случае объект создать или операция newconst его разместить ? Решение чрезвычайно простое и элегантное. Конструктор и newconst (и только они!, ну еще, если надо, деструктор и deleteconst )будут работать с этой страницей по другому виртуальному адресу, с атрибутами R/W. При этом операция newconst будет возвращать R/O адрес в качестве адреса этого объекта, поэтому все функции будут работать с ним по R/O. А конструктор будет преобразовывать R/O адрес в R/W адрес и работать без всяких проблем. Все!!!

S>>Осталось только гарантировать, что никто другой не станет обращаться к этим R/W страницам.

PD>В .Net вы гарантируете, что никто без unsafe не сможет вообще никуда в неположенное место обращаться. Так что уж позаботьтесь о том, чтобы только реализация константных конструкторов могла туда обращаться. В конце концов этих самих адресов я в .Net вообще не вижу. они там внутри где-то. Ну и манипулируйте ими корректно.

Еще раз, медленно повторяю: поскольку мы уже гарантировали отсутствие обращений в неположенные места, никаких VirtualProtect не надо. Зачем заниматься этим онанизмом?
Это же индусокод:
public int SuperSafeLength(string a)
{
  if (string.IsNullOrEmpty(a)) // return -1 for empty strings
      return -1;
        
    if (a == null)
      return -1;  // return -1 for null strings
        
    try 
    {
      return a.Length;
    }
    catch (NullRefernceException) // we must return -1 for null strings!!!
    {
      return -1;
    }
}

PD>Ну а в С++, конечно, никто такой гарантии не даст, но это обычная проблема — никто же не даст гарантии, что кто-то просто левым способом не испортит вполне обычную переменную.
Я тебе об этом и пишу. В одном мире эта идея бессмысленна, в другом — бесполезна. Что не мешает ей оставаться красивой, как произведение программерского искусства

S>>Наверное, лучше было бы сделать так, чтобы компилятор не давал делать такие вызовы, не так ли? Зачем компилировать заведомо некорректную программу?

PD>Ну мы опять за то же. Нет, не лучше.
А можно пример, в котором компилируемость невалидной программы позволит получить хоть какие-то преимущества?

PD>Я тебе уже говорил — ставя иммутабельность на тип, ты подвергаешься очень серьезным ограничениям. В реальной жизни нужно иметь и переменные этого типа и константы.

Павел, ты просто, похоже, не понимаешь, что такое "тип". Еще раз, медленно пишу, читай не торопясь: у тебя есть экземпляр a, класса A. Но у этого экземпляра запрещено вызывать метод A::setx(). Почему ты так настойчиво хочешь считать, что тип этого экземпляра — такой же, как и у экземпляра b? Ведь у экземпляра b можно вызывать метод setx()! С точки зрения математики, теории типов, да и просто здравого смысла a имеет совсем другой тип, чем b — у них разные контракты.

PD> Со строками у вас так и получилось — string для констант, StringBiulder для переменных. Для строк это сойдет. А для других классов — нет. Вот хочу я неизменяемый ArrayList , например. То есть хочу я следующее — однажды его сконструировать из какого-то источника и никогда больше не менять. И чтобы это сделать на иммутабельных типах, тебе придется еще один класс ImmutableArrayList соорудить (ну как наследника хоть, что ли).

Павел, ты по-прежнему не понимаешь, что такое "иммутабельность". Если ты хочешь "однажды его сконструировать из какого-то источника и никогда больше не менять" — это доступно тебе и так. Конструируй и не меняй, делов-то! В С++ ты даже можешь навесить на указатель/ссылку const, чтобы не забыть свои планы "не менять", и заодно получить дополнительную гарантию "и чтобы никто его не менял".

А вот если я "хочу получить сконструированный кем-то другим объект, который никто не может менять" — упс, облом. А это и есть иммутабельный тип, а вовсе не то убогое подмножество его функциональности, которое ты пытаешься выдать за реализацию.

PD>Кстати, сейчас подумал. В С++ операция new и конструктор — это, в общем, две независимые вещи. Но в C# это по существу тандем,

В С# это по существу две совершенно независимые вещи. К моменту начала инициализации, объект уже размещён (и его VMT сконструирована). То, что в языке нет отдельного оператора new, не влияет на эту семантику.
PD>так что если делается newconst Type(...), то среда, распознав, что создается константа, может автоматом заставить конструктор проверять, не делается ли попыток в нем записать ссылку на неконстантный объект ( а это очень просто, как ты понимаешь — по значению адреса).
Еще раз: поскольку ситуации, когда иммутабельный объект в течение своей жизни внезапно становится мутабельным, не бывает, то никакого смысла откладывать проверку до рантайма нет. Достаточно проверять всё статически.
PD>Ну естественно, я не мог написать это на настоящем С++. Мне не годится new, даже если я ее перекрою, так как не могу же я ее двумя способами перекрыть .
Запросто — сделаешь ему фейк-параметр синглтон-типа PD::ReadOnly и дело в шляпе.
PD>Мне нужна для этого модификация языка и введение операции newconst
Модификация языка потребуется для того, чтобы я мог написать
int SafeStringProcessor(immutable &std::string)
{
  
}

и иметь гарантии того, что никто снаружи не подсунет мне переменную типа string.

PD>Так, стоп. Я не намерен обсуждать сейчас, что хорошо в С++ и что нет. Я предложил идею создания и размещения константых объектов, она, как ты вполне видишь, от языка не зависит, так как реализована на чисто Win API. Окружи то, что я написал, соответствующим кодом хоть на .Net, хоть на чем угодно еще и используй

Павел, твоя идея просто не работает. Вот напиши мне пример функции, которая требует константный объект, сконструированный за её пределами.
На любом языке — С, С#, С++, Pascal.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.