Pull to refresh
-2
0
Владимир @Evir

User

Send message

Без лишних предисловий перейдём к бэкдору. Сможете его найти?

Да, нашёл. Даже "не отходя от браузера". Но это нужно знать, что здесь точно есть что-то, что можно найти. Заморачиваться такой проверкой на постоянной основе руками никто не будет, естественно.

Firefox, нажимаем F7. "Нажатие клавиши F7 включает или выключает режим активного курсора. В этом режиме, поместив курсор на страницу, вы можете выделять текст с помощью клавиатуры. Включить этот режим?" – "Да".

Ставим курсор в начало исходника и жмём на кнопку [→]. Я ожидал, что после очередного нажатия (раз речь идёт о невидимом символе) курсор останется на месте; но кроме этого, как ни странно, толщина курсора меняется до и после символа.

Как выглядит курсор до и после невидимого символа

После чего смысл сразу стал понятен – и второй раз эта переменная тоже встанет после какой-либо запятой. Нашёл это место без проблем.

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

image
Desktop версия хабра, Linux, Firefox 56, fullhd (1920×1080) монитор 24". Два иероглифа. И если в первом я ещё вижу какие-то отдельные чёрточки и, в теории, частично способен к восприятию символа (хотя я китайский не учу)… то во втором я вижу то ли двух стоящих рядом человечков, то ли (исходя из количества нижних чёрточек-ножек) пару осминожков. Приглядевшись, я вижу, что левая голова взлохмаченная, а на правой вижу что-то вроде французского берета с торчащей «пимпкой». Умудриться разглядеть в этом какой-то символ, имеющий значение – это какая-то фантастика.
Нет, я могу, конечно, через Ctrl+колесо мыши увеличить масштаб. Русско-английский текст станет огромным. Иероглифы станут более читаемыми.
image
Размер картинок в этом комментарии намеренно одинаков (753×43).
Но, если честно, если между первыми иероглифами на этих картинках нет большой разницы (хотя в первом случае потерялись многие детали), я не вижу ничего общего между вторыми иероглифами…
Код на си – это хорошо.
Вот только… я вглядывался в то, что происходит при вызове setFirst. Дошёл до setItem, строка 258. Вот зачем так сложно и неоптимально? Или это следствие того, что стандартные функции тоже написаны на Вашем же творении?
bool const __r3 = f__use2__0__f__4__19_3127_5((*slice_));
if (__r3) {
	struct t0 const __r4 = f__clone0__0__f__4__19_110_5((*slice_));
	struct t0 const __r5 = (*slice_);
	*(slice_) = __r4;
	p__free0__0__f__4__19_293_5(__r5);
}

То есть, вместо detach(*slice_), где void detach(t0& slice); сделает всю нужную работу (copy-on-write, если нужен), мы копируем на стек 56 байтов (вызов use), чтобы затем снова скопировать на стек 56 байтов (вызов clone). Зачем ТАК сильно игнорировать указатели?
Насчёт 56 байтов
Я собирал код по Вашей ссылке, и при добавлении строки:
printf("sizeof(a): %lu\n", sizeof(a_));
Получил 56.

Ну и ещё не могу понять, что за магия с useCounter:
printf("a.useCounter: %ld\n", (size_t)(a_.useCounter));
printf("b.useCounter: %ld\n", (size_t)(b_.useCounter));
printf("c.useCounter: %ld\n", (size_t)(c_.useCounter));
Выходит, что useCounter нулевой (т.е. nullptr) у a_/b_, но почему-то не пустой у c_. В чём принципиальная разница? Видимо, в том, что строки «hello» и «hello 2» являются константами, а «Hello» – «собрана на куче»?
Copy-on-Write происходит только в одном случае — изменение данных располагаемых на куче, если на эту кучу есть несколько указателей


Тогда, наверно, «на куче» будет всё, кроме константых строк? Ну ещё константных массивов, по аналогии с int arr[] = { 0, 2, 4, 6, 8};?

proc main()
    a := createLine(createPoint(0, 0), createPoint(1, 1))
    b := a
    a:mutateLine(createPoint(2, 2), createPoint(3, 3), getRandomFloat(0, 1), getRandomFloat(0, 1))
Переменная a – «на стеке» или «на куче»? Так-то на стеке будет лежать только структура, а сами данные будут в куче? Соответственно, в методе mutateLine счётчик на линии будет равен двум, и в случае, если мы будем писать последовательно в line:a и line:b – получим Copy-on-Write при записи в line:a? Но...
В указанном вами примере line хранится на стеке и его изменение никогда не вызовет Copy-on-Write, как бы line не изменялся.
Всё равно не понимаю.
P.S. Баг?
Строки 266-269 – use(newItem) есть, а free(oldItem) – нет.
В случае с b:field = value «отделится» сдесь может только field, а b храниться на стеке и если ему присвоить какое то d, то на уровне программы содержимое d полностью скопируется (это не затратно) в b, но если например в field есть указатель на массив, то массив не будет скопирован, а просто для этого массива счетчик увеличится на 1.
Ох, сложно. Документации более подробной ещё нет? Или пример собранного C-кода, который получается с подобного блока?
Вот если по Вашим примерам – есть точки, есть линии. Причём точка – tuple двух координат, а линия – tuple двух точек. Я вызываю функцию, передаю туда линию, две точки и два float (t1/t2). Функция должна сделать два Lerp между двумя переданными точками (используя t1/t2), и результаты Lerp'ов записать в line:a и line:b.
Линия, которая передаётся в функцию, не проходит же Copy-on-Write заранее? Вдруг в функции есть условие, которое приведёт к тому, что записи в переменную не будет (например, if(t1>t2) return). Но переданная линия может иметь счётчик как равный единице, так и с большим значением.
Не совсем понимаю, что значит «хранится на стеке», и как может при Вашем подходе на стеке храниться что-то кроме value type variables и указателей на объекты (с счётчиком ссылок).
Допустим элементы массива являются структурой хранящей два члена, один число (UInt64), а второй массив. При получении элемента из массива значения числа и указатели на память массива копируются на стэк, при этом счётчик у массива внутри элемента увеличивается на 1.
Но структура же тоже объект? Или это два разных типа сущностей? Не помню такого в статье; возможно, просто уже прошло слишком много времени.
Похоже, правильно говорят, что будут проблемы даже набросать какой-то несложный GUI.
Возможно, но я вижу несколько возможных и адекватных решений проблемы.
Я тоже вижу; например, IMGUI-подход, когда нет постоянных сущностей/объектов, представляющих элементы интерфейса, а есть только функция, которая умеет обрабатывать события. Но у этого подхода есть свои минусы и трудности.
Он возможен (поскольку функции являются объектом первого класса и по этому можно делать аналоги интерфейсов из других языков)
Да, но в этом случае есть большая проблема с тем, что объект не может хранить своё состояние в себе; каждый раз, меняя элемент интерфейса (надпись на кнопке, например), нужно устраивать пляски с бубном, чтобы в контейнере осталась ссылка на обновлённый вариант кнопки, в контейнере-уровнем-выше осталась ссылка на обновлённый вариант контейнера, и так далее, выше, до самого interface root element/container.
Ну или нужно иметь где-то аналог статичного массива (какой-то менеджер), сводящемуся к хешмапу id → состояние объекта, а на каждом элементе держать уникальный id. Думаю, это как-то можно сделать не очень неудобным… Но зачем?..
У меня ещё такой вопрос по fei. Логично, что после первого изменения (пусть будет «b:call(someArg)», или «b:field = value») «отделение» переменной b уже сработало (т.е. прошёл Copy-on-Write, если на экземпляр были отдельные ссылки). Соответственно, при следующем «изменяющем» вызове на этой переменной уже не стоит делать проверку значения счётчика ссылок… кроме, конечно, одного исключения, о нём чуть ниже.
Ваш компилятор (точнее будет, наверно, всё-таки транспайлер) как-то это учитывает? Как бы я согласен, что мой пример на C++/Qt может быть чуть менее производительным, потому что аналог Вашего примера кода (чуть ниже вставлю), в теории, может меньше раз дёргать проверку счётчика ссылок, что может быть не очень незначительным, если над одной переменной делать много «записывающих действий». Соотвественно, Ваш пример:
result:x = x
result:y = y // мы точно уверены, что usage_count(result) == 1

А теперь об исключении, которое может ломать подобную оптимизацию.
Если один из «записывающих» («изменяющих»?) методов будет куда-то сохранять ссылку на this (в поле одного из аргументов, например), то после вызова метода значение счётчика ссылок, естественно, не будет равно единице. Причём не важно, будет ли метод изменять значение полей на this или вызывать другие методы, которые могут это делать – важен именно факт, что ссылка на this может куда-то «утечь». В общем, я пока не понял, есть ли возможность указать, что метод запрещает копировать ссылку на this (что-нибудь вроде «method (.Some) ...»; ведь, как я понимаю, двоеточие обозначает запись, а точка – неизменяемость).
Ну хорошо, мне аж тоже стало интересно. Тоже взял mandelbrot; python3-реализацию из ссылки выше по ветке, и C++-реализацию из общего списка самую нижнюю (mandelbrot C++ g++ #3) из таблицы, т.е. самую медленную.
И, извините, я не понимаю, можно ли считать достижением, что python3-реализация в несколько потоков (извините, не знаток python, так что не могу по коду понять, во сколько потоков пул там по умолчанию «молотит»; а лезть в документацию мне лень) работает в четыре разницы медленнее, чем практически в лоб (не вижу здесь никаких обфускаций или волшебных оптимизаций, кроме разве что одного manually inlining «norm» results in a 5x-7x speedup on gcc) реализованный алгоритм, работающий в один поток даже без всяких openmp.
Результаты
C++
time bash -c "./mandelbrot.gpp-3.gpp_run 16000 > ./mand_output"

real 1m5.565s
user 1m5.488s
sys 0m0.048s

Python3
time bash -c «python3 -OO mandelbrot.python3-7.py 16000 > ./mand_output_py»

real 4m23.843s
user 25m45.748s
sys 0m0.988s

sha256sum ./*output*
609262469ee6a0262ccd03932e557f745c9e7b997ad17835a02a0232a64807be ./mand_output
609262469ee6a0262ccd03932e557f745c9e7b997ad17835a02a0232a64807be ./mand_output_py

UPD: очень грубо (без долей секунд и учёта sys) поделил для python3-реализации, вышло user/real ≈ 5.87; похоже, python3 использовал все шесть ядер моего процессора.
раз уж фигурные скобки
Похоже, до конца Вы не осилили; автор потом бросил фигурные скобки, так что сравнивать скорее нужно с Python.
является изолированной вещью-в-себе
Очень на то похоже.
Не то, чтобы я поддерживал такой подход… но сейчас частенько используют webkit. Всякие там месседжеры, лаунчеры чего-либо, или для встроенной помощи/документации. В общем, я про подход а-ля Electron.
И что, получается, что долой системные библиотеки, пусть каждое приложения тянет исходники всего, что использует? Думаю, webkit будет ну очень долго собираться. Ну ок, давайте забудем про тот же Slack (который на Electron) – судя по википедии, Skype и Telegram используют Qt (который тоже долго собирается). Не думаю, что предкомпиляция в один большой C-файл заметно упростит и ускорит сборку на компьютере пользователя.
В общем, теперь уже и мне становится интересно, какую нишу, на Ваш взгляд, может занять cine/fei, и разработка каких приложений на нём не будет проблемой.
Мне кажется, или при таком подходе проблемы с написанием кода будут на каждом шагу?
Например, есть массив/коллекция/хешмап (в общем, какой-то контейнер) с объектами. Получается, что если нужно поменять состояние одного из объектов – нужно достать объект (по факту – ссылку на него) из контейнера, затем отредактировать объект, после чего придётся заменить значение в контейнере на новое. Правильно?
Причём получаем следующую ситуацию – в момент редактирования срабатывает Copy-on-Write, потому что ссылок на объект минимум две (в контейнере и изменяемая). То есть, правильно делать в следующем порядке container.getItem → containter.removeItem → редактирование экземпляра → container.addItem? Тогда на момент изменения будет одна ссылка (если, конечно, копия объекта не хранится где-то ещё), и лишнего копирования не будет…
Похоже, правильно говорят, что будут проблемы даже набросать какой-то несложный GUI. Возможно, не будет проблем с IMGUI-подходом; но стандартный вариант, когда есть в том или ином виде контейнер с виджетами, некоторые из которых тоже являются виджетами – явно не для Вашего языка, как я понимаю?
Или есть какой-то подход, который позволяет решать эти проблемы по-другому?
Но в стандартной библиотеке есть, например, обычные сильные и слабые указатели.
Посмотрите ссылки в моём комменте, пожалуйста.
Я имел в виду, что в самом C++, на уровне языка, этого нет. Никто же не заставляет использовать стандартную библиотеку; можно использовать boost, ну или вообще написать свою реализацию. Мало у кого какой подход, или какая любовь к костылям, например. )
А вот тут неожиданно, честно говоря. Конечно, мой английский недостаточно хорош (читаю/понимаю документацию), но я ожидал или «сайн», или прям «сине» (как в cinema), ну или на немецкий манер «цайн». Хотя насчёт немецкого варианта я, судя по озвучке через google translate, тоже ошибаюсь.
Естественно, в самом C++ такой функциональности нет. Но в стандартной библиотеке есть, например, обычные сильные и слабые указатели.
А Qt – отдельная платформа поверх С++, там насчёт указателей и сокрытия реализации (и для повышения удобства использования) вообще много чего есть.
Кроме Implicit Sharing:
  • Explicit Sharing;
  • QSharedPointer и QWeakPointer (своя реализация сильных и слабых указателей);
  • QScopedPointer (RAII-обёртка над указателем для гарантированного удаления объекта, созданного на куче, после потери выхода ссылки на него из зоны видимости без явных delete и/или try/catch);
  • QPointer (что-то вроде отдельного вида слабых ссылок на экземпляры классов, наследующихся от QObject);
  • Что такое Pimpl по версии Qt, и с чем его едят! (своё решение проблемы сохранения бинарной совместимости для библиотек).
А ещё есть своя система плагинов, сигналы-слоты и так далее.

Ну и как бы всё это нужно для того, чтобы код вроде того, что я копировал из документации Qt:
Employee e1(1001, "Albrecht Durer");
Employee e2 = e1;
e1.setName("Hans Holbein");

Было удобно и легко писать, чтобы он «красиво выглядел», чтобы был понятным. Ну и чтобы работал быстро; а уж что там внутри – совсем другой вопрос. Цена вопроса – необходимо писать два класса (кроме qpointer, scoped и слабых/сильных ссылок) вместо одного.

Ну и:
Я не знал, что в C++ есть счётчик ссылок.
Тут скорее основная магия в возможности переопределения operator * и operator ->.
Если он не со слишком сложного языка да ещё и неоптимизирующий?
Так он же «компилирует» в C. Уже компиляция получившегося C с большой вероятностью оптимизирует всё, что нужно.
Вот только во всех трёх случаях тот факт, что его нужно ставить создавал, в какой-то момент, очень серьёзную проблему: люди не хотели ничего ставить.
А тут ещё всё сложнее; нужно для установки иметь установленный тулкит автора, компилятор, наверняка какой-то набор lib* и *-dev. Не претендую на истинность, но опыт сборки отдельно взятого десктопного Qt-приложения показывает, что на Linux (и, думаю, так же будет BSD) всё будет достаточно просто; на Mac возможны отдельные проблемы (в том числе с brew); на Windows будут боль и мучения даже если приложению нужны несложные вещи вроде libxml, libssl,…
Зацикливание двух объектов на друг друге не возможно из-за особенностей языка.
А можно поподробнее?
Что мешает сделать класс Tree (Вы писали тут где-то в комментариях пример), а потом собрать дерево A → B → A? Тогда потом даже после «выпадения из зоны видимости» нод A и B получаем утечку памяти, разве нет?
Или получается, что за счёт Copy-on-Write мы автоматически получаем C → B → A? Т.е. корень перед добавлением B → A копируется в C? А если это нежелаемое поведение, и где-то нужно сохранить ссылку на уровень выше?
Вообще, складывается ощущение, что сейчас (12 назад этого ещё не было в достаточном виде) можно было бы реализовать cine/fei как надстройку над Nim.
Сборка в C – есть (см. compileToC/compileToCpp), возможность сделать собственные кастомные операторы – есть (":", ":=", ".=" и собственную вариацию "."); есть куча вариантов макросов во всех вариациях, в том числе и уровня работы с AST, когда можно в compile-time блок кода как угодно с ног на голову переворачивать. Опять же, есть условная компиляция через when, так что если устанавливать через пакет Nim-кода вместо C-кода – можно так же избежать попадания ненужного кода в итоговый бинарник.
Еще такой момент, я правильно понимаю, что в собранном exe будет присутствовать исходник сконвертированный в С?
Нет, как я понял (и выше получил подтверждение от автора) – в Вашей терминологии правильнее было бы сказать, что исходный код программы на C будет в setup.exe.
Вы не думаете, что таким образом сложно защитить свой код от взлома или исследования, если это требуется?
Скорее невозможно; если, конечно, не удастся как-то мощно обфусцировать тот C-код, который будет сгенерирован для установки.
Это единственный вариант?
Не то, чтобы я стремился попробовать, но просто звучит очень странно… Может, это потому, что у меня больше опыта по вебу, но у меня с моими «домашними поделками» до этапа установки никогда не доходило; на этапе экспериментов и дебага гораздо удобнее всё вызывать через ./, без задействования /usr/bin, /opt и прочих стандартных папок.
Придется постоянно контролировать и заставлять, чтобы делал то, что нужно, а не то, что хочет.
Ну не знаю. Вроде автору почти всё время приходилось работать, чтобы иметь возможность заниматься своим pet-проектом. Не думаю, что для него будет проблемой, если на основной работе он будет программистом, а не грузчиком или контролёром на КПП.

Information

Rating
Does not participate
Location
Россия
Date of birth
Registered
Activity