LINUX.ORG.RU

Прошу помощи по типу данных в С

 , ,


0

1

Написал патч для bluez. Используя встроенный плагин autopair при условии что используется capability=noinputnooutput пин-код для паринга устройств берем из файла main.conf

При компиляции получаю предупреждение:

plugins/autopair.c:158:18: предупреждение: при передаче аргумента 2 «memcpy» целое преобразуется в указатель без приведения типа [-Wint-conversion]
   memcpy(pinbuf, main_opts.defaultpin, 4);
                  ^~~~~~~~~
замечание: ожидался тип «const void * restrict», но аргумент имеет тип «gchar {aka char}»
 extern void *memcpy (void *__restrict __dest, const void *__restrict __src,
              ^~~~~~

Собственно вопрос: какой тип правильнее будет выставить для значения в main.conf типа DefaultPin = 5421 я так понимаю что char тип не очень подходит?

# cat ./bluez.patch 
--- ./main.c_old	2018-06-01 16:37:36.000000000 +0800
+++ ./src/main.c	2018-11-28 13:56:32.489196607 +0800
@@ -90,6 +90,7 @@
 	"MultiProfile",
 	"FastConnectable",
 	"Privacy",
+	"DefaultPin",
 	NULL
 };
 
@@ -317,6 +318,16 @@
 		g_free(str);
 	}
 
+	val = g_key_file_get_string(config, "General",
+						"DefaultPin", &err);
+	if (err) {
+		DBG("%s", err->message);
+		g_clear_error(&err);
+	} else {
+		DBG("defaultpin=%d", val);
+		main_opts.defaultpin = val;
+	}
+
 	str = g_key_file_get_string(config, "General", "Name", &err);
 	if (err) {
 		DBG("%s", err->message);
@@ -434,6 +445,7 @@
 	main_opts.reverse_sdp = TRUE;
 	main_opts.name_resolv = TRUE;
 	main_opts.debug_keys = FALSE;
+	main_opts.defaultpin = 0000;
 
 	if (sscanf(VERSION, "%hhu.%hhu", &major, &minor) != 2)
 		return;
--- ./hcid.h_old	2018-06-01 16:37:36.000000000 +0800
+++ ./src/hcid.h	2018-11-28 13:54:29.753199017 +0800
@@ -41,6 +41,7 @@
 	uint32_t	pairto;
 	uint32_t	discovto;
 	uint8_t		privacy;
+	char		defaultpin;
 
 	gboolean	reverse_sdp;
 	gboolean	name_resolv;
--- ./autopair.c_old	2018-11-30 14:32:55.000000000 +0800
+++ ./plugins/autopair.c	2018-12-05 10:10:59.000000000 +0800
@@ -35,12 +35,14 @@
 
 #include "src/plugin.h"
 #include "src/adapter.h"
 #include "src/device.h"
 #include "src/log.h"
 #include "src/storage.h"
+#include "src/agent.h"
 
 /*
  * Plugin to handle automatic pairing of devices with reduced user
@@ -62,6 +64,8 @@
 	char pinstr[7];
 	char name[25];
 	uint32_t class;
+	uint8_t io_cap;
+	struct agent *agent;
 
 	ba2str(device_get_address(device), addr);
 
@@ -143,7 +147,18 @@
 		}
 		break;
 	}
-
+	/*check capability=NOINPUTNOOUTPUT and use DefaultPin=0000 or from main.conf if available*/
+	if (agent)
+	    io_cap = agent_get_io_capability(agent);
+	
+	if (io_cap == 0x03) {
+	    DBG("capability set to NOINPUTNOOUTPUT use defaultpin");
+		if (attempt > 1)
+			return 0;
+		memcpy(pinbuf, main_opts.defaultpin, 4);
+		return 4;
+	}
+	
 	return 0;
 }
★★★★★

Последнее исправление: irton (всего исправлений: 2)
Ответ на: комментарий от anonymous2

Если честно я вобще этот язык не знаю, но патч мне нужен, а разрабы не торопятся реализовать, они mesh пилят.

по сути мой патч сделан на основе подобного же кода в самом bluez. В ./src/hcid.h задается тип для получаемого значения, я подозреваю что char это не подходящий тип.

в /plugins/autopair.c я значение из main_opts.defaultpin передаю для паринга устройств, предварительно проверив что capability в нужном значении.

Вроде как все логично, для передачи фиксированного значения пинкода, они используют

memcpy(pinbuf, "0000", 4);

irton ★★★★★
() автор топика
Ответ на: комментарий от irton

По патчу у тебя литерал 0000 (int? short?) присваивается к char defaultpin получается?

Может ты хотел сделать

+	main_opts.defaultpin = "0000";
+	const char*		defaultpin;

?

EXL ★★★★★
()
Ответ на: комментарий от EXL

По патчу у тебя литерал 0000 (int? short?) присваивается к char defaultpin получается?

да. но я незнаю какой тип сделать. Если допустим int будет, то 0000 не запишутся ли как просто 0 ? тут же надо чтобы и 0001 и 0010 тоже были допустимыми значениями и первые нули не отбрасывались.

Задача брать значение из конфига main.conf и присваивать его main_opts.defaultpin потом это значение использовать при автопаринге.

irton ★★★★★
() автор топика
Ответ на: комментарий от EXL

main_opts.defaultpin = «0000»;

Я так понял, это я задаю значение, если в main.conf конфиге DefaultPin вобще не задан.

irton ★★★★★
() автор топика
Ответ на: комментарий от EXL

По патчу не видно, но main_opts это массив, в который складываются значения полученные из main.conf, потом они используются в разных частях кода.

irton ★★★★★
() автор топика
Ответ на: комментарий от irton

Я так понял, это я задаю значение, если в main.conf конфиге DefaultPin вобще не задан.

Просто вот эта вот конструкция memcpy(pinbuf, main_opts.defaultpin, 4); копирует в pinbuf четыре байта начиная с адреса 0x0000, если defaultpin у тебя 0000.

Мне не видно всю картину и с bluez я не знаком. Но по идее этот DefaultPin должен храниться как массив char[4], то бишь строкой. Тогда эта проблема вообще исчезает:

тут же надо чтобы и 0001 и 0010 тоже были допустимыми значениями и первые нули не отбрасывались.

И да, с этими 0-ями в литералах осторожнее. Так как 0100 это будет восьмеричное число, а не десятериное.

ИМХО тебе нужно подробнее рассказать об этой фиче кому-нибудь заинтересованному в bluez, чтобы он помог тебе с написанием патча и не троллил тебя на незнание C, а реально давал советы. Надеюсь, на этом форуме найдётся такой человек.

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

EXL ★★★★★
()
val = g_key_file_get_string(...

вроде как намекает, что val есть

char*
(указатель на строку).

соответственно, далее

main_opts.defaultpin
тоже должен быть
char*
, ну и дефолт присваивание
main_opts.defaultpin = "0000"
тоже выглядит логично.

как и

memcpy(pinbuf, main_opts.defaultpin, 4);

DBG(«defaultpin=%d», val); в таком случае нужно поправить на DBG(«defaultpin=%s», val);

conalex ★★★
()
Последнее исправление: conalex (всего исправлений: 1)
Ответ на: комментарий от irton

Совсем не знаю что такое bluez и что такое пин.

Но из голого Си - у вас тут

val = g_key_file_get_string
и потом
main_opts.defaultpin = val
. Если посмотреть в определение функции g_key_file_get_string, то оно возвращает gchar*, которое объявлено как char*.
Но даже если вы объявите свой defaultpin как gchar* (что формально будет правильно с точки зрения типов) - это будет наверняка неправильно с точки зрения логики. Надо смотреть внутрь реализации g_key_file_get_string чтобы точно знать указатель на что именно оно возвращает (не общий ли там буфер библиотеки, в частности), или, если лень разбираться - сразу делать memcpy из возвращаемого буфера в свое собственное место для него в defaultpin (который должен быть char[4], если я правильно понимаю что пин это нечто из 4х символов).

Ну и по этому поводу очень хочется ввернуть что-нибудь едкое для ненавистников венгерской нотации. Была бы тут венгерка - не было бы этого вопроса. Мне так кажется.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от conalex

вроде как намекает, что val есть char*

нет, это я подбирал по образу параметра Name= , об чем и вопрос у меня, какой правильный тип выбрать для 0000 или 0001 или 0010 чтобы их потом в этом виде и передать, а не как 0 или 1 или 10

irton ★★★★★
() автор топика
Последнее исправление: irton (всего исправлений: 1)
Ответ на: комментарий от Deleted

g_key_file_get_string еще вижу в коде бывает g_key_file_get_integer, g_key_file_get_boolean

g_key_file_get_boolean мне точно не подходит.

Здесь ввернуть едкое можно что угодно, я не оценю.

irton ★★★★★
() автор топика
Последнее исправление: irton (всего исправлений: 1)

Кхмм...

Начнём с того, что g_key_file_get_string это из GLib, эта функция должна читать из файла конфига строку. Таким образом, у Вас должно быть определение (где-то в исходниках, в структуре main_opts) gchar* defaultpin, либо gchar defaultpin[4]. Как-то так, мне самому лень сейчас в код тупить.

предупреждение: при передаче > аргумента 2 «memcpy» целое
преобразуется в указатель без > приведения типа [-Wint-conversion]
memcpy(pinbuf, main_opts.defaultpin, 4);

main_opts.defaultpin должен из конфига читаться не как 0x0000, а чисто как массив символов (в С строк в чистом виде нет, под строкой понимается массив символов), т.е., как «0000». Нули в строке отброшены не будут. Попробуйте для начала в конфигурации, в параметре который читаете, прописать не 0000, а именно «0000». Странно, но по опыту g_key_file_get_string работает как правило исправно.

Moisha_Liberman ★★
()
Ответ на: комментарий от irton

Да.

Я так понял, это я задаю значение, если в main.conf конфиге DefaultPin вобще не задан.

Это дефолтное значение которое захардкодили на случай, если в конфиге этот параметр не определён.

Moisha_Liberman ★★
()
Ответ на: Кхмм... от Moisha_Liberman

Блин.

Кавычки имеются в виду не «ёлочки», а знак дюйма.

Moisha_Liberman ★★
()
Ответ на: Кхмм... от Moisha_Liberman

Таким образом, у Вас должно быть определение (где-то в исходниках, в структуре main_opts) gchar* defaultpin

оно есть в виде char defaultpin; в файле hcid.h исправить на gchar?

Странно, но по опыту g_key_file_get_string работает как правило исправно.

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

irton ★★★★★
() автор топика
Ответ на: Да. от Moisha_Liberman

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

кавычки конечно обычные, это без проблем

irton ★★★★★
() автор топика
Ответ на: комментарий от conalex

Хорошо, определились с видом пин-кода в принципе сейчас char у меня это тоже самое что gchar, осталось согласовать тип при передаче:

memcpy(pinbuf, main_opts.defaultpin, 4);

компилятор выдает замечание: ожидался тип «const void * restrict»

irton ★★★★★
() автор топика
Ответ на: комментарий от irton

делай по аналогии с name.

char* defaultpin

конфиге пиши DefaultPin = 12345

или что там у тебя, без кавычек.

для чтения этого парметра из конфига применяй g_key_file_get_string

передачу можно делать двумя способами: либо просто присвоить значение указателя, либо полностью скопировать содержимое с помощью memcpy.

если ты делаешь по аналогии, то memcpy(pinbuf, main_opts.defaultpin, 4); вполне подойдет.

conalex ★★★
()
Последнее исправление: conalex (всего исправлений: 1)
Ответ на: комментарий от irton

Не. Ненадо.

исправить на gchar?

Ненадо править. Пусть так будет. char и gchar это в принципе одно и то же, только char это стандартное типа «обще сишное», а gchar это специфично для GLib. Местный такой тип данных.

Moisha_Liberman ★★
()
Ответ на: Ну да. Понял. от Moisha_Liberman

я не до конца предупреждения в заглавном сообщении темы написал, исправил. про замечание: ожидался тип «const void * restrict» у меня не было написано.

irton ★★★★★
() автор топика
Ответ на: комментарий от conalex

если ты делаешь по аналогии, то memcpy(pinbuf, main_opts.defaultpin, 4); вполне подойдет.

ну оно в принципе подходит (компиляция выполняется), но предупреждение компилятора лучше бы убрать, я же хочу в апстрим этот патч отправить.

irton ★★★★★
() автор топика
Ответ на: комментарий от irton

А тут я по ходу дела проморгал.

компилятор выдает замечание: ожидался тип «const void * restrict»

Надо бы кофейном мозг прогреть. По ходу дела, ожидается что-то вида memcpy(pinbuf, *(char *)&main_opts.defaultpin, 4);

Moisha_Liberman ★★
()
Ответ на: комментарий от irton

Да.

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

Moisha_Liberman ★★
()
Ответ на: комментарий от conalex

после проверки конечно.

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

irton ★★★★★
() автор топика
Ответ на: Да. от Moisha_Liberman

ну так собственно char to void делать видимо надо... но я пока не знаю как.

irton ★★★★★
() автор топика
Ответ на: комментарий от irton

Это следует из сигнатуры ф-ии.

Тут и так ясно. Второй аргумент. Откуда читаем. Это хрестоматийно. =)

void* memcpy(void* dest, const void* src, size_t count);

Moisha_Liberman ★★
()
Ответ на: Это следует из сигнатуры ф-ии. от Moisha_Liberman

size_t count

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

irton ★★★★★
() автор топика
Ответ на: комментарий от irton

Нет.

Не защитит. Это просто размер (длина пинкода в символах).

Защита здесь сразу и встроенная. Ф-я, применяемая для чтения значения из конфига по умолчанию возвращает не число, а строку символов. Т.е., нуль будет не нуль как число, а символ нуля (как просто цифровой символ).

Moisha_Liberman ★★
()
Ответ на: А тут я по ходу дела проморгал. от Moisha_Liberman

Да скомпилировалось, но в виде

memcpy(pinbuf, (char *)&main_opts.defaultpin, 4);
т.е. убрал * перед (char *)

Но возможно надо вот это предупреждение пофиксить еще:

src/main.c:321:6: предупреждение: в присваивании указатель преобразуется в целое без приведения типа [-Wint-conversion]
  val = g_key_file_get_string(config, "General",
						"DefaultPin", &err);

irton ★★★★★
() автор топика
Последнее исправление: irton (всего исправлений: 1)
Ответ на: А тут я по ходу дела проморгал. от Moisha_Liberman

может преобразование делать сразу после считывания val = g_key_file_get_string и хранить уже сразу в нормальном виде.

irton ★★★★★
() автор топика
Ответ на: комментарий от irton

Вы простите меня. Возможно я что-то не понимаю.
Такое ощущение, что вы подгоняете решение под ответ.
Вот это: (char *) - это команда компилятору, что вы точно понимаете что делаете. Конечно он не будет ругаться, поскольку вы ему приказали. Но если вы на самом деле так явно приводите к типу обычный char (вы ведь всё ещё char defaultpin в структуре?) - это абсолютная катастрофа будет в итоге. Или я упустил место, где вы все-таки изменили тип.

Deleted
()
Ответ на: комментарий от irton

Ясно.

т.е. убрал * перед (char *)

Да, это я тупанул. Мы кастуем в (char *) то, что лежит по адресу (&)имя_структуры.элемент_структуры, всё верно.

Здесь должно быть:

val = g_key_file_get_string(config, "General", "какой-то_параметр", NULL);
Параметр, который Вы читаете, Вы должны сами указать. А вот последний аргумент NULL говорит о том, что у Вас нет обработчика ошибок. Функции типа GError, которая вызывается в случае, если что-то пошло не так.

Можно в принципе просто проверить на возвращаемый NULL типа так:

if(NULL == val) {
    val = "0000";
}

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

Moisha_Liberman ★★
()
Ответ на: комментарий от Deleted

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

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

irton ★★★★★
() автор топика
Ответ на: комментарий от Deleted

Откуда катастрофа?

В GLib gchar это typedef к char. Так что, всё в пределах правил. Проверять считанное значение на валидность надо, но не здесь.

Moisha_Liberman ★★
()
Ответ на: комментарий от Deleted

Или я упустил место, где вы все-таки изменили тип.

нет не меняли, пока пришли к выводу что char , но сейчас видно что еще есть предупреждение (раньше я его не видел т.к. компиляцию прерывал)

 src/main.c:321:6: предупреждение: в присваивании указатель преобразуется в целое без приведения типа [-Wint-conversion]
 val = g_key_file_get_string(config, "General",
						"DefaultPin", &err);

irton ★★★★★
() автор топика
Последнее исправление: irton (всего исправлений: 1)
Ответ на: комментарий от irton

Ага.

Написано. Я уже сам запутался! =)))

GError *err; это не функция, это переменная, содержащая код ошибки.

Хорошо, вопрос снят. Тогда я не понял откуда там

предупреждение: в присваивании указатель преобразуется в целое без приведения типа [-Wint-conversion]

Moisha_Liberman ★★
()
Ответ на: комментарий от irton

смотри на объявления же.

https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/src/main.c#n273

int val;

и ты в нее счтываешь указатель на строку, возвращаемый

g_key_file_get_string(). оно и ругается.

в то же время рядышком https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/src/main.c#n272

char *str;

и считывание строкового параметра https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/src/main.c#n333

str = g_key_file_get_string(config, «General», «DeviceID», &err);

conalex ★★★
()
Последнее исправление: conalex (всего исправлений: 1)
Ответ на: Ага. от Moisha_Liberman

В общем, проверяем.

Должно быть:

gchar *val;
GError *err;
GKeyFile *config;

val = g_key_file_get_string(config, "General", "DefaultPin", &err);

Moisha_Liberman ★★
()
Ответ на: Откуда катастрофа? от Moisha_Liberman

Катастрофа - когда memcpy получит исходным адресом, адрес char (один байт) и будет читать оттуда 4 байта мусора.

char = gchar
char* = gchar* (= void* для memcpy).

Конечно же надо сменить тип на char*.

Другое дело, что надо отдельно понимать, что там внутри у GLib будет выделение памяти при g_key_file_get_string - и тут надо думать когда и где её обратно освобождать. Или вместо char* делать char[], переносить в него, освобождать GLib'овскую память и дальше уже работать со своим собственным статическим массивом (буфером).

Deleted
()
Ответ на: комментарий от Deleted

Ненене...

А вот этого:

и тут надо думать когда и где её обратно освобождать

Тут лучше и не делать и даже не думать об этом. Это вообще ни чего не даст.

что надо отдельно понимать, что там внутри у GLib будет выделение памяти при g_key_file_get_string

Там всё хорошо при выделении памяти. Можно не искать себе проблем на ровном месте. Просто помним о совместимости типов, да и всё.

Moisha_Liberman ★★
()
Ответ на: комментарий от conalex

Спасибо, сам как раз это заметил, сделал так:

str = g_key_file_get_string(config, "General","DefaultPin", &err);
if (err) {
	DBG("%s", err->message);
        g_clear_error(&err);
} else {
	DBG("defaultpin=%d", str);
	main_opts.defaultpin = str;
}

Предыдущее предупреждение ушло, но появилось в другой строке:

src/main.c:327:24: предупреждение: в присваивании указатель преобразуется в целое без приведения типа [-Wint-conversion]
   main_opts.defaultpin = str;
main_opts.defaultpin прописан как элемент char вроде нормально же.

irton ★★★★★
() автор топика
Ответ на: комментарий от Deleted

Нет.

memcpy получит исходным адресом, адрес char (один байт) и будет читать оттуда 4 байта мусора.

В современном нам мире этого не произойдёт.

Moisha_Liberman ★★
()
Ответ на: комментарий от Deleted

Или вместо char* делать char[], переносить в него, освобождать GLib'овскую память и дальше уже работать со своим собственным статическим массивом (буфером).

Так оно вроде так и сделано, передается в массив main_opts, вот только освобождения (g_free да?) я не вижу и не делал сам.

irton ★★★★★
() автор топика
Ответ на: комментарий от irton

Бллллин...

main_opts.defaultpin = str;

Прошу прощения, вот этого я уже не осилю объяснить. Без мата. =)))

Из дискуссии позволю себе откланяться. =)))

Moisha_Liberman ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.