|
LwIP это потенциально опасное ПО или нет?, или я неправильно понял и не знаю что и как |
|
|
|
Apr 7 2016, 12:59
|
Частый гость
 
Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364

|
Вот если я скажем делаю так (использую NetConn API): Код struct netconn *conn, *newconn; err_t err, accept_err;
conn = netconn_new(NETCONN_TCP);
while (1) { if (conn != NULL) { err = netconn_bind(conn, NULL, 7000);
if (err == ERR_OK) { netconn_listen(conn);
while (1) { accept_err = netconn_accept(conn, &newconn);
/* Process the new connection. */ if (accept_err == ERR_OK) { ... } } } else { netconn_delete(conn); } } } Т.е. все "по мануалу" и вопросов тут нет. Но вот вопрос такой тут - в функцию netconn_accept(conn, &newconn); я передал указатель на newconn, а эта функция в ответ обновила его значением указателя на свою локальную переменную (как я понял). Т.е. др. словами говоря - она создала внутри у себя какую-то локальную переменную, а потом второй параметр этой самой функции обновила уже новым значением указателя на эту переменную. И как теперь это понимать - ведь та локальная переменная существует в куче, но может же в любой момент времени быть затерта. Т.е. все работает как бы "до поры - до времени" так получается? Пока не "затрется случайно" та локальная переменная другим чем-то в ОЗУ. Или я не так понял? Или тут эта переменная newconn как бы "неполноценно" используется и в ней только что-то одно временно берется и потому все безопасно работает? Спасибо.
|
|
|
|
|
Apr 7 2016, 18:22
|
Частый гость
 
Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364

|
Я после того как написал свой вопрос все переживал, что не привел код самой функции netconn_accept() из стека LwIP и думал "вот люди будут меня ругать, что не показал ее код тоже", а оказывается никто не ответил даже еще. Вот сама функция netconn_accept из стека (в ней я убрал все некомпилирующиеся куски кода из-за условной компиляции чтобы не загромождать лишним кодом, а также добавил комментарий в том месте где ожидается получение семафора - см. код): Код err_t netconn_accept(struct netconn *conn, struct netconn **new_conn) { struct netconn *newconn; err_t err;
LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;); *new_conn = NULL; LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_accept: invalid acceptmbox", sys_mbox_valid(&conn->acceptmbox), return ERR_ARG;);
err = conn->last_err; if (ERR_IS_FATAL(err)) { /* don't recv on fatal errors: this might block the application task waiting on acceptmbox forever! */ return err; }
/* т.к. 3-й параметр тут - timeout равен 0, то ждем бесконечно долго прихода message (так сделано в этой функции): */ sys_arch_mbox_fetch(&conn->acceptmbox, (void **) &newconn, 0);
/* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
if (newconn == NULL) { /* connection has been aborted */ NETCONN_SET_SAFE_ERR(conn, ERR_ABRT); return ERR_ABRT; }
*new_conn = newconn; /* don't set conn->last_err: it's only ERR_OK, anyway */ return ERR_OK; } Обратите внимание на строку №< последняя строка - 3> тут - вот это и есть, то о чем я писал: Код *new_conn = newconn; т.е. приравнивается значение указателя из 2-го параметра значению указателя на локальную переменную структуры! Т.е. вопрос такой в итоге (извините, что сложно может написал до этого) - "Почему эта функция netconn_accept() из стека LwIP возвращает фактически указатель на свою локальную переменную?? Это правильно??" Спасибо.
|
|
|
|
|
Apr 7 2016, 18:55
|
Частый гость
 
Группа: Свой
Сообщений: 92
Регистрация: 22-06-05
Из: Украина, г.Боярка
Пользователь №: 6 238

|
Цитата(AleksBak @ Apr 7 2016, 20:22)  Т.е. вопрос такой в итоге (извините, что сложно может написал до этого) - "Почему эта функция netconn_accept() из стека LwIP возвращает фактически указатель на свою локальную переменную?? Это правильно??" Спасибо. Она возвращает значение этой локальной переменной, а не указатель на нее
|
|
|
|
|
Apr 8 2016, 03:22
|
Частый гость
 
Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364

|
Цитата(_NB @ Apr 7 2016, 22:55)  Она возвращает значение этой локальной переменной, а не указатель на нее Нет не так. В эту функцию передается указатель на указатель - переменная new_conn и вот такое объявление ее как параметра функции: Код struct netconn **new_conn Внутри функции объявляется свой, локальный указатель на структуру newconn (может тут кроется ответ на загадку т.к. при его объявлении выделяется память из какой-то "особой" памяти самого стека LwIP? но это бред все-таки). Далее, под конец, мы видим, что: Код *new_conn = newconn; т.е. все как писал - по переданному указателю на указателю пишется значение своего локального указателя. Тут даже и пояснять мне уже не нужно т.к. может запутываю в итоге и непонятен будет вопрос - все и так видно как на ладони.
|
|
|
|
|
Apr 8 2016, 07:08
|
Частый гость
 
Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364

|
Цитата(aaarrr @ Apr 8 2016, 10:23)  Так в чем опасность? Сами же написали значение, не указатель. Возвращается обратно значение указателя. А через это значение указателя далее в коде (в вызвавшей функции) идут обращения к той структуре (см. код). Т.е. где-то в куче она все еще есть пока что! Т.е. обращаемся к ней, а она находится в куче (или же в "бывшей" памяти стека) в это время. Вот так все и выходит. Теперь надеюсь понятно да? Если теперь опять какую-то (любую) функцию вызовем, то она легко может затереть значение той переменной в RAM, а мы по-прежнему будем думать, что то значение валидное внутри вызывающей основной функции. У меня еще есть объяснение, что вот с точки зрения применения ОС (NetConn API только для ОС написано) тут вроде ничего "страшного" нет. Вроде бы! У каждой задачи свой стек и т.д. И поэтому эти стеки задач существуют в раздельности и нерушимы. Но на самом деле - если, как только что написал, снова вызовем какую-то любую функцию то значение структуры все равно покоцается в этом "нерушимом" стеке. Или опять-таки я не прав и все не так? И вообще зачем они так это сделали по-дурацки (так выходит)? Зачем этот LwIP себе еще отдельные порции RAM "отгребает" при инициализации? И не малые причем! Это все отдельные и другие вопросы (их много вообще-то). Но пока хотя бы на этот вопрос в теме кто бы ответил.
|
|
|
|
|
Apr 8 2016, 07:36
|
Частый гость
 
Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364

|
Цитата(des333 @ Apr 8 2016, 11:13)  ... Представьте, Вам нужно написать функцию, которая будет внутри использовать malloc для выделения памяти. ... malloc-ом я память выделяю и сразу же дальше использую внутри функции. А тут в одной функции выделена память, создана переменная в этой памяти и возвращается указатель на эту созданную переменную. А в вызвавшей функции мы продолжаем обращаться к той переменной несмотря на то, что она когда-то была простой локальной переменной в той функции, а не у нас и не здесь. Так теперь понятно? Это же разные вещи тут. Еще вот объяснение у меня есть - может в этом LwIP не настолько все просто сделано и этот указатель, который возвращается указывает на какую-то особую "LwIP"-овскую суперпамять внутри RAM? Но что-то по коду такого не видно тут такого абсолютно. Надо бы отладчиком посмотреть, что и как когда будет возможность.
|
|
|
|
|
Apr 8 2016, 07:50
|
Профессионал
    
Группа: Свой
Сообщений: 1 129
Регистрация: 19-07-08
Из: Санкт-Петербург
Пользователь №: 39 079

|
Цитата(AleksBak @ Apr 8 2016, 10:36)  ...Так теперь понятно?... Мне точно понятно, что Вы прочитали не всё моё сообщение  Цитата Но указатель на выделенную память нужно вернуть не через возвращаемое значение, а через один из аргументов функции. Т.е. цель -- написать функцию-обёртку для malloc, которая будет не просто использовать память, а возвращать её наружу (и именно через аргумент). Всё-таки советую Вам написать такую функцию  А уже потом, если вопросы всё-таки останутся, то обсудить их.
--------------------
|
|
|
|
|
Apr 8 2016, 08:12
|
Частый гость
 
Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364

|
Цитата(des333 @ Apr 8 2016, 11:50)  ...написать функцию-обёртку для malloc, которая будет не просто использовать память, а возвращать её наружу (и именно через аргумент). Всё-таки советую Вам написать такую функцию  .... Да я Вам сразу отвечу как бы все это было бы. Что тут размышлять как и чего. Выделил память, ничего бы с ней не делал дальше и тут же вернул бы на нее указатель. И Все. А тут - выделяется память, в ней создается переменная, что-то с ней делается, а потом возвращается указатель на ту переменную, а далее мы у себя опять обращаемся к этой переменной откуда-то в куче (в мусорке), а если еще какую-то функцию вызовем по дороге вдруг неожиданно, то ничего не останется от той переменной в мусорке, но будем все равно к ней обращаться т.к. так учат нас. Еще добавлю - где-то даже кажется есть строгое указание в рекомендациях, что так делать категорически не рекомендуется. Вот только не помню где это и кто бы подсказал бы тут.
|
|
|
|
|
Apr 8 2016, 08:27
|
Частый гость
 
Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364

|
Цитата(des333 @ Apr 8 2016, 12:13)  Это Ваш выбор  Вы просили помощи, я пытался Вам помочь  Ну да - спасибо и на этом. Кстати тут вообще-то ничего не выделяется - в смысле это не какая-то ненужная обертка для функции mallocc как Вы пишите с самого начала, а я пытаюсь Вам отвечать согласно такой теории и в итоге не прав оказываюсь. Здесь просто: 1. создается локальная переменная; 2. что-то делается; 3. и возвращается потом указатель на эту локальную переменную. Вот так правильное описание, что тут происходит.
|
|
|
|
|
Apr 8 2016, 08:56
|
Частый гость
 
Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364

|
Цитата(gosha-z @ Apr 8 2016, 12:39)  Я правильно понимаю, что newconn во втором сообщении обретает значение при вызове sys_arch_mbox_fetch?... Эта структура newconn вот такая - см. ее объявление ниже и на выходе из функции в ней должны появится готовые уже заполненные поля. А в вызвавшей, основной функции мы уже пользуемся этим "готовым" набором (см. коммент в 1-м куске кода: "Process the new connection."): CODE /** A netconn descriptor */ struct netconn { /** type of the netconn (TCP, UDP or RAW) */ enum netconn_type type; /** current state of the netconn */ enum netconn_state state; /** the lwIP internal protocol control block */ union { struct ip_pcb *ip; struct tcp_pcb *tcp; struct udp_pcb *udp; struct raw_pcb *raw; } pcb; /** the last error this netconn had */ err_t last_err; /** sem that is used to synchroneously execute functions in the core context */ sys_sem_t op_completed; /** mbox where received packets are stored until they are fetched by the netconn application thread (can grow quite big) Это QueueHandle_t. */ sys_mbox_t recvmbox; #if LWIP_TCP /** mbox where new connections are stored until processed by the application thread Это QueueHandle_t. */ sys_mbox_t acceptmbox; #endif /* LWIP_TCP */ /** only used for socket layer */ #if LWIP_SOCKET int socket; #endif /* LWIP_SOCKET */ #if LWIP_SO_SNDTIMEO /** timeout to wait for sending data (which means enqueueing data for sending in internal buffers) */ s32_t send_timeout; #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVTIMEO /** timeout to wait for new data to be received (or connections to arrive for listening netconns) */ int recv_timeout; #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF /** maximum amount of bytes queued in recvmbox not used for TCP: adjust TCP_WND instead! */ int recv_bufsize; /** number of bytes currently in recvmbox to be received, tested against recv_bufsize to limit bytes on recvmbox for UDP and RAW, used for FIONREAD */ s16_t recv_avail; #endif /* LWIP_SO_RCVBUF */ /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */ u8_t flags; #if LWIP_TCP /** TCP: when data passed to netconn_write doesn't fit into the send buffer, this temporarily stores how much is already sent. */ size_t write_offset; /** TCP: when data passed to netconn_write doesn't fit into the send buffer, this temporarily stores the message. Also used during connect and close. */ struct api_msg_msg *current_msg; #endif /* LWIP_TCP */ /** A callback function that is informed about events for this netconn */ netconn_callback callback; }; Цитата(gosha-z @ Apr 8 2016, 12:39)  ...Если да - то что говорит дока на эту функцию по поводу способа выделения памяти для этой структуры и последующего ее освобождения? Не знаю. Я новичок тут и поэтому спросил как оно работает и почему так сделано.
|
|
|
|
|
Apr 8 2016, 08:58
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (AleksBak @ Apr 8 2016, 10:27)  3. и возвращается потом указатель на эту локальную переменную. Где? Я вижу, что в процессе "2. что-то делается" в эту локальную переменную заносится указатель на созданный в куче объект. Потом этот указатель записывается в то место, которое было указано входным параметром. Что до вас и пытался донести des333.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|