PDA

Просмотр полной версии : [Вопрос] sscanf warning: String buffer overflow.



Danny_Marcelo
13.06.2016, 15:49
Всем привет. У меня такой вопрос. Как многие знают, я занимаюсь модом Funny RP. Так вот, как написал Daniel_Cortez:



Сам собой напрашивается вопрос: зачем вообще к моду подключен sscanf2? Ради пары отрывков кода, которые лень переделать?
Кстати, sscanf2 используется в моде всего 5 раз.
Вот самое первое место, где он встречается:
PHP код:
public OnPlayerCommandText(playerid, cmdtext[])
{
new string[256];
new tmp[128],idx;
new cmd[128];
new giveplayerid;
cmd = strtok(cmdtext,idx);
// sscanf
new command[32], params[128];
sscanf(cmdtext, "s[32]s[128]", command, params);
Параметры команды отделяются от названия сразу двумя способами, в лучших быдлокодерских традициях.
И присмотритесь внимательно к форматной строке в sscanf: "s[32]s[128]". В переменную params ничего не запишется, вместо этого и название, и параметры окажутся в command. Мало того, если длина команды и параметров в сумме больше 31 символа, sscanf выплюнет сообщение в лог "sscanf warning: String buffer overflow" - и после этого гадай, откуда берётся такое сообщение.
В остальных 4 случаях с помощью sscanf2 в командах (OnPlayerCommandText) обрабатываются параметры из params, но поскольку в params ничего нет, то команды будут работать не так, как задумано.


Ну вот попробовал наконец добавить команду с использованием sscanf и у меня в консоли выбило:



sscanf warning: String buffer overflow.


Ну как я понял, переполнение буфера. Но Daniel_Cortez сказал, что sscanf подключен к моду не правильно, по этому будут такие ошибки.

Так как же правильно подключить sscanf к моду? Я гуглил, везде одно и тоже и в моде тоже самое. Прошу по этому вашей помощи. Заранее благодарю.

Вот собственно подключение к sscanf.



public OnPlayerCommandText(playerid, cmdtext[])
{
new string[256];
new tmp[128],idx;
new cmd[128];
new giveplayerid;
cmd = strtok(cmdtext,idx);
// sscanf
new command[32], params[128];
sscanf(cmdtext, "s[32]s[128]", command, params);


Ну а вот тестовая команда:



if(strcmp(cmd, "/msg", true) == 0)
{
static const fmt_str[] = "Администратор %s: %s";
new str[sizeof fmt_str + 16 + MAX_PLAYER_NAME + 50];
if(PlayerInfo[playerid][pAdmin] < 4) return true;
if(sscanf(params, "s[50]", params[0])) return SendClientMessage(playerid, COLOR_GREY, "Используйте: /msg [текст]");
format(str, sizeof(str), fmt_str, PlayerInfo[playerid][pName], params[0]);
SendClientMessageToAll(0xFFCC00AA, str);
return true;
}


Если тут написать текст больше 50, то в консоли выбивает про буфер. Я пробовал изменять на 128 и т.д., но все равно, если больше напишешь символов, то будет снова это сообщение. P.S. используется sscanf 2.8.1

Danny_Marcelo
15.06.2016, 17:53
Ну и? Кто нибудь поможет? Где все профессионалы?

Sp1ke
15.06.2016, 18:11
Ну и? Кто нибудь поможет? Где все профессионалы?

Поэтому и надо делать ограничение на кол-во символов, понятное же дело

nikvlad
15.06.2016, 21:59
if(sscanf(params, "?<SSCANF_QUIET=1>s[50]", params[0])) return SendClientMessage(playerid, COLOR_GREY, "Используйте: /msg [текст]");

Daniel_Cortez
16.06.2016, 09:18
Так как же правильно подключить sscanf к моду?

#include <sscanf2>
Худшее, что здесь можно сделать - неправильно написать название инклуда или забыть скопировать сам инклуд в pawno/include. В любом случае компилятор укажет на такую ошибку.



Вот собственно подключение к sscanf.



public OnPlayerCommandText(playerid, cmdtext[])
{
new string[256];
new tmp[128],idx;
new cmd[128];
new giveplayerid;
cmd = strtok(cmdtext,idx);
// sscanf
new command[32], params[128];
sscanf(cmdtext, "s[32]s[128]", command, params);

"Подключение" и "использование" - совершенно разные вещи...



Ну а вот тестовая команда:



if(strcmp(cmd, "/msg", true) == 0)
{
static const fmt_str[] = "Администратор %s: %s";
new str[sizeof fmt_str + 16 + MAX_PLAYER_NAME + 50];
if(PlayerInfo[playerid][pAdmin] < 4) return true;
if(sscanf(params, "s[50]", params[0])) return SendClientMessage(playerid, COLOR_GREY, "Используйте: /msg [текст]");
format(str, sizeof(str), fmt_str, PlayerInfo[playerid][pName], params[0]);
SendClientMessageToAll(0xFFCC00AA, str);
return true;
}


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



Я пробовал изменять на 128 и т.д., но все равно, если больше напишешь символов, то будет снова это сообщение.
Каждая строка должна заканчиваться нуль-символом '\0' (должна же машина как-то знать, где заканчивается последовательность символов), под который нужна ещё одна ячейка в массиве. В итоге в OPCT массивы command и params должны быть оба размером в 129 ячеек.

Есть ещё вариант посложнее, но использующий только один массив в 129 ячеек вместо двух. Вместо того, чтобы использовать sscanf2, можно скопировать всё содержимое cmdtext в массив command, пройтись циклом по массиву, найти первый пробел и записать на его месте '\0', затем пропустить лишние пробелы между командой и параметрами (да, их там может быть больше одного) и записать позицию, где начинаются параметры команды, в переменную params_start_pos. В итоге сама команда будет в массиве command, а вместо params можно будет использовать command[params_start_pos].
А вообще для подобных манипуляций есть командные процессоры, кои я и советую вам использовать.

Battista
16.06.2016, 18:59
new cmd[64],params[64],idx;
cmd = strtok(cmdtext, idx);
sscanf(cmdtext,"s[32]s[64]",cmd,params);

Daniel_Cortez
17.06.2016, 13:07
new cmd[64],params[64],idx;
cmd = strtok(cmdtext, idx);
sscanf(cmdtext,"s[32]s[64]",cmd,params);
Команда может быть длиннее 31 символа, а параметры - длиннее 63 (сразу будет заметно в чатовых командах типа /s, /a, /pm, /sms и т.п.).

Desulaid
17.06.2016, 13:24
Команда может быть длиннее 31 символа, а параметры - длиннее 63 (сразу будет заметно в чатовых командах типа /s, /a, /pm, /sms и т.п.).

Почему 63? Разве длинна строки параметра - это не остаток от лимита ввода в чат (128) минус лимит длины имени функции (31)?

Daniel_Cortez
17.06.2016, 13:37
Почему 63? Разве длинна строки параметра - это не остаток от лимита ввода в чат (128) минус лимит длины имени функции (31)?
Именно.
Кстати, по поводу моего первого поста в этой теме, небольшая поправка: если команда может быть длиной от 2 до 128 символов, то максимальная длина параметров будет равна 129 - 2 - 1 = 126 символов. В итоге под массив params потребуется не 129, а 126 ячеек.

Desulaid
17.06.2016, 13:44
Именно.
Кстати, по поводу моего первого поста в этой теме, небольшая поправка: если команда может быть длиной от 2 до 128 символов, то максимальная длина параметров будет равна 129 - 2 - 1 = 126 символов. В итоге под массив params потребуется не 129, а 126 ячеек.

Учет пробелов и '/' всегда должен быть, если ты об этом.