native SubString takes string source, integer start, integer end returns string
  1. вот пример исполнения кода:
код - результат
SubString("123456789",0,99) - 123456789
SubString("123456789",-1,99) - o123456789
SubString("123456789",-2,99) - mo123456789
SubString("123456789",-3,99) - mo123456789
SubString("123456789",-4,99) - mo123456789
SubString("123456789",-5,99) - (null)
зачем этот префикс "mo" при старте с "-1" по "-4" ?



  1. в одной из карт есть такой код:
if SubString("|",-1,0)!="o" and GetUnitTypeId(BackGroundUnits[i])!='hspt' then
	call SetUnitScale(BackGroundUnits[i],4,4,4)
endif
в чём смысл проверять подстроку на наличие "o" в -1 позиции?

Менеджер памяти варкрафта размещает перед каждой выделеной единицей памяти служебные данные. Непосредственно перед строкой находятся 16 байт, содержащие старшие два байта адреса текущего региона памяти, за которыми следует константа 0x6F6D ("mo"), которая, вероятно, является маркером, нужным для проверок блока на правильность во время освобождения.
Нативка SubString позволяет читать память перед строкой с минимальным рабочим индексом равным -32768. Если дотянуться до незанятой памяти, то должно быть возможно и крашнуть игру.
Проверка, что символ перед строкой не равен букве "o" всегда будет возвращать false, если только кто-нибудь не сделает мод, который заменит стандартный менеджер памяти на альтернативный, что может привести к изменению содержимого служебной памяти перед строкой.
Загруженные файлы
`
ОЖИДАНИЕ РЕКЛАМЫ...
19
Менеджер памяти варкрафта размещает перед каждой выделеной единицей памяти служебные данные. Непосредственно перед строкой находятся 16 байт, содержащие старшие два байта адреса текущего региона памяти, за которыми следует константа 0x6F6D ("mo"), которая, вероятно, является маркером, нужным для проверок блока на правильность во время освобождения.
Нативка SubString позволяет читать память перед строкой с минимальным рабочим индексом равным -32768. Если дотянуться до незанятой памяти, то должно быть возможно и крашнуть игру.
Проверка, что символ перед строкой не равен букве "o" всегда будет возвращать false, если только кто-нибудь не сделает мод, который заменит стандартный менеджер памяти на альтернативный, что может привести к изменению содержимого служебной памяти перед строкой.
Загруженные файлы
Принятый ответ
14
прикреп из поста выше в виде превью:
Загруженные файлы
14
вот ещё тест версии варика в одной из карт:
if SubString("|",-1,0)!="o" then
call DisplayTimedTextToForce(bj_FORCE_ALL_PLAYERS,10.,"※ 워크래프트3 1.28기준으로 만든 맵이기 때문에, 다른 버전으로 이용하면 약간의 버그가 있을 수 있습니다.")
call DisplayTimedTextToForce(bj_FORCE_ALL_PLAYERS,10.,"※ 리포지드로 플레이할 경우 클래식 그래픽으로 설정하셔야 원할한 플레이가 가능합니다.")
endif

if SubString("|",-1,0)!="o" then
call DisplayTimedTextToForce(bj_FORCE_ALL_PLAYERS,10.,"※ Since this map was created based on Warcraft 3 1.28, there may be some bugs if used with a different version.")
call DisplayTimedTextToForce(bj_FORCE_ALL_PLAYERS,10.,"※ When playing with Reforged, you must set it to classic graphics to play smoothly.")
endif
14
как отметил IceFog
SubString позволяет по памяти ковыряться
если через чат вводить значения отступа XX от -20 и условно до -20000 (и дальше)
выдаваемые значения обычно разные, даже если одну и ту же карту перезапустить
	call BJDebugMsg(SubString("0123456789",0-S2I(XX),50))
Загруженные файлы
14
ещё по теме отсюда :
IceFog:
Если копирование функцией SubString происходит начиная с первого байта, а хэши входной строки и результата совпадают, то может быть возвращена изначально переданая строка, вместо ожидаемой подстроки.
Разработчик функции решил не создавать копию подстроки в памяти, а вместо этого временно поставить нуль-терминатор посреди оригинальной строки, передать указатель на неё в конструктор нового объекта-строки, после чего вернуть буфер в исходный вид.
Но память, которую он временно модифицировал, принадлежала менеджеру строк и её нельзя было трогать
Проблема усугубляется тем, что StringHash обрабатывает только первые 1023 байта, так что любые две строки, учитываемый регион которых совпадает, имеют одинаковый хэш, что увеличивает вероятность бага на больших строках.
SubString
RCString *__thiscall RCString::create_slice(RCString *this, RCString *result, __int16 start, __int16 end)
{
  const char *chars; // eax MAPDST
  size_t chars_length; // eax
  __int16 end_validated; // cx
  char original_char; // bl
  char *p_slice_nt_position; // esi
  RCString temp; // [esp+14h] [ebp-18h] BYREF
  int _try_level; // [esp+28h] [ebp-4h]

  chars = RCString::c_str(this);
  if ( chars && (chars_length = Storm_506_SStrLen(chars)) != 0 && start <= (__int16)chars_length )
  {
    end_validated = end;
    if ( end >= (__int16)chars_length )
      end_validated = chars_length;
    original_char = chars[end_validated];
    p_slice_nt_position = (char *)&chars[end_validated];
    *p_slice_nt_position = 0;
    RCString::ctor(&temp, &chars[start]);
    *p_slice_nt_position = original_char;
    _try_level = 1;
    RCString::from(result, &temp);
    LOBYTE(_try_level) = 0;
    RCString::dtor(&temp);
  }
  else
  {
    RCString::from(result, &RCString::null);
  }
  return result;
}

int __cdecl Jass::Common::SubString(JassString *source, int start, int end)
{
  const char *chars; // eax
  int id; // esi
  RCString slice; // [esp+8h] [ebp-18h] BYREF
  int _try_level; // [esp+1Ch] [ebp-4h]

  RCString::create_slice(&source->string, &slice, start, end);
  _try_level = 0;
  chars = RCString::c_str(&slice);
  id = GetJassStringId(chars);
  _try_level = -1;
  RCString::dtor(&slice);
  return id;
}
Чтобы оставить комментарий, пожалуйста, войдите на сайт.