Pull to refresh

Comments 39

Язык с указателями + продвинутая оптимизация — всегда гремучая смесь.
Имхо, всё ок, как и во многих языках есть пулинг ресурсов для экономии памяти, просто в Objective-C можно unsafe вещи с памятью делать.

В Java, например, можно всю программу разломать, если рефлекшеном поменять значение какого-нибудь числа из пула констант, математика к чертям полетит.

+ Не знаю, как в Objective-C, но в Java можно ещё дров наломать если синхронизироваться на расшаренном объекте, например, так:
Скрытый текст
    // Integer Pool! Никогда так не делайте
    Integer lock = 1;
    synchronized(lock) { ... }


Я даже статью на эту тему писал: "Story of one dependency injection in Telegram Android App"
Это типа можно в военное время поднять значение пи до четырех, а по особому указанию партии — и до пяти? ;)
Простите, я не в курсе: константы в Java — глобальные?
Можно например сделать 2 + 3 == 4, если через рефлекшн поменять 2 на 1 или 3 на 2.

Пул констант есть для целых чисел [-128, 127], для float/double, насколько я знаю, пула нет.

Так же есть пул строк, поведение такое же, тоже можно патчить через рефлекшн заменить «hello world» на -> «пшел отсюда» без проблем :)

«Константы в Java — глобальные?» немного не понял вопрос, вообще нет, всё должно быть в рамках определенного класса
Переформулирую. Можно ли поменять константу в одном модуле/классе и неожиданно нарваться на изменившееся значение в другом? В моем примере это именно так происходит: функцию bad() можно зарыть в произвольное место проекта.
А, да, конечно, в рамках одного процесса bad() будет работать из любого места
void bad(){
  NSString* a = @"123456789";
  char* aa = (__bridge void *)(a);
  aa[8] = 92;
}


да вы в любом объекте в кишках поковыряйтесь и ему плохо станет

это же не строка char* в понимании С, что можно тупо от начала массива смещениями скакать… афтор сам ничего не понял походу
В том, плохо станет тому объекту, в котором поковыряли, — ничего удивительного, я не подвергаю это сомнению. Неожиданно то, что плохо станет и объектам, существующим в другой области видимости, созданным отдельно и никак формально с подвергшимся вмешательству не связанным.
Да, пожалуй это и нелогичное поведение, но очень справедливое. Вы кастуете объект непонятно к чему, делаете какие-то странные манипуляции, а ожидаете чего-то вменяемого?
Не уверен конечно, но подозреваю что подобное поведение не определено, а потому произойти может что угодно.
Радуйтесь что вас динозавр не унес.
С моей точки зрения ожидаемым поведением было бы то, что все, что я накастовал в пределах локальных переменных какой-то функции какого-то модуля, не окажет глобального влияния на локальные переменные других областей видимости. Ну или пусть меня действительно динозавр унесет: программа вывалится с Segmentation Fault или еще как-то.

Совершенно с вами согласен, что получать по рукам за стремные манипуляции с объектами — справедливо. Предлагаю рассматривать статью как (забавную, на мой вкус) иллюстрацию к этому правилу.
> Ну или пусть меня действительно динозавр унесет: программа вывалится с Segmentation Fault или еще как-то.

В том-то и дело :)
В случае с неопределенным поведением нельзя чего-то ожидать, может произойти что угодно
UFO just landed and posted this here
Если честно, статья не «об одном способе выстрелить себе в ногу», а рассказывает о том, как:
купить дробовик, проверить его, зарядить, тщательно прицелиться и выстрелить в ногу.
Менять значение указателя на объект по смещению в расчете на то, что по этому адресу реально хранится строка
(а не какая-нибудь служебная информация типа той же кодировки) — это очень странно.
Скорее она о том, как вы стреляете себе в ногу, а попутно простреливаете голову, хотя она ну никак не могла на пути пуль оказаться
Отличная метафора, спасибо :)
Я бы уточнил — стреляете себе в правую ногу, а отстреливаете обе, потому что левая — алиас правой.
нет, указатель не должен быть алиасом константы.
Речь об объекте, полученном из литерала (и указателях на этот объект), а не о самом литерале.
О неизменяемом на первый взгляд объекте, который, оказывается, можно испортить из любого места кода
Я думаю, «проблема» тут скорее в том, что люди интуитивно преполагают, что объектов там столько же, сколько и литералов. Т.е. внезапным оказывается не то, что NSString можно изменять через хитрые касты, а то, что при этом изменяется какой-то «другой» NSString (который на самом деле тот же самый). То есть «проблемой» является именно алиасинг, а не нарушение иммутабельности.
>Чтобы разместить строки в heap, где они могут быть изменены, нужно заменить char *a на char a[]
Разве не наоборот?
Вроде бы нет. Там даже по изменению адресов видно, где лежат строки в одном и в другом случае. c-faq.com/decl/strlitinit.html
Я имею в виду
char a[] = «123456789»;
располагает же данные на стеке.
По поводу «где они могут быть изменены» всё правильно. Но куча не участвует в деле в любом случае. Так что не «наоборот», но поправить нужно.
А, понял. Спасибо, поправил.
Аналогичную оптимизацию строковых констант выполняет и gcc при компиляции кода на Си. Например,
#include <stdio.h>
void main(){
char *a = «123456789»;
char *b = «123456789»;
printf("%p %p\n", a, b);
}

Здесь к char * надо добавить const что бы дальнейшие рассуждения были верными
А что сейчас не так в дальнейших рассуждениях? У вас эта программа печатает два разных пойнтера?
Вы правы, затупил.
UFO just landed and posted this here
Очень интересный пример, спасибо.
UFO just landed and posted this here
clang под Ubuntu на LLVM 3.4 действительно создаст три различных объекта
а как вы это делаете? В смысле, Foundation же нет для linux?
UFO just landed and posted this here
ну так можно было бы еще и на Cocotron тогда глянуть. Вполне ожидаемо что у фактически разных фреймворков будут некоторые различия?
Ожидаемо, конечно. Хотя я не уверен, что здесь дело во фреймворке, а не в компиляторе.
То есть, чтобы заменить одну константу на другую, достаточно сделать:

    uint64_t *i = (__bridge void*)@"123";
    uint64_t *j = (__bridge void*)@"2345678";
    i[1] = j[1];


Теперь в любом месте, где встречается @«123» будет выводиться @«2345678»:

    NSLog(@"123"); // 2345678


(во всяком случае для arm64)
UFO just landed and posted this here
Да и так работает, чего уж там.
Sign up to leave a comment.

Articles

Change theme settings