реклама на сайте
подробности

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> LwIP это потенциально опасное ПО или нет?, или я неправильно понял и не знаю что и как
AleksBak
сообщение Apr 7 2016, 12:59
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 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 как бы "неполноценно" используется и в ней только что-то одно временно берется и потому все безопасно работает? Спасибо.
Go to the top of the page
 
+Quote Post
AleksBak
сообщение Apr 7 2016, 18:22
Сообщение #2


Частый гость
**

Группа: Участник
Сообщений: 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 возвращает фактически указатель на свою локальную переменную?? Это правильно??" Спасибо.
Go to the top of the page
 
+Quote Post
_NB
сообщение Apr 7 2016, 18:55
Сообщение #3


Частый гость
**

Группа: Свой
Сообщений: 92
Регистрация: 22-06-05
Из: Украина, г.Боярка
Пользователь №: 6 238



Цитата(AleksBak @ Apr 7 2016, 20:22) *
Т.е. вопрос такой в итоге (извините, что сложно может написал до этого) - "Почему эта функция netconn_accept() из стека LwIP возвращает фактически указатель на свою локальную переменную?? Это правильно??" Спасибо.

Она возвращает значение этой локальной переменной, а не указатель на нее
Go to the top of the page
 
+Quote Post
AleksBak
сообщение Apr 8 2016, 03:22
Сообщение #4


Частый гость
**

Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364



Цитата(_NB @ Apr 7 2016, 22:55) *
Она возвращает значение этой локальной переменной, а не указатель на нее

Нет не так. В эту функцию передается указатель на указатель - переменная new_conn и вот такое объявление ее как параметра функции:
Код
struct netconn **new_conn

Внутри функции объявляется свой, локальный указатель на структуру newconn (может тут кроется ответ на загадку т.к. при его объявлении выделяется память из какой-то "особой" памяти самого стека LwIP? но это бред все-таки). Далее, под конец, мы видим, что:
Код
*new_conn = newconn;

т.е. все как писал - по переданному указателю на указателю пишется значение своего локального указателя. Тут даже и пояснять мне уже не нужно т.к. может запутываю в итоге и непонятен будет вопрос - все и так видно как на ладони.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Apr 8 2016, 06:23
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(AleksBak @ Apr 8 2016, 06:22) *
...по переданному указателю на указателю пишется значение своего локального указателя.

Так в чем опасность? Сами же написали значение, не указатель.
Go to the top of the page
 
+Quote Post
AleksBak
сообщение Apr 8 2016, 07:08
Сообщение #6


Частый гость
**

Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364



Цитата(aaarrr @ Apr 8 2016, 10:23) *
Так в чем опасность? Сами же написали значение, не указатель.

Возвращается обратно значение указателя. А через это значение указателя далее в коде (в вызвавшей функции) идут обращения к той структуре (см. код). Т.е. где-то в куче она все еще есть пока что! Т.е. обращаемся к ней, а она находится в куче (или же в "бывшей" памяти стека) в это время. Вот так все и выходит. Теперь надеюсь понятно да? Если теперь опять какую-то (любую) функцию вызовем, то она легко может затереть значение той переменной в RAM, а мы по-прежнему будем думать, что то значение валидное внутри вызывающей основной функции. У меня еще есть объяснение, что вот с точки зрения применения ОС (NetConn API только для ОС написано) тут вроде ничего "страшного" нет. Вроде бы! У каждой задачи свой стек и т.д. И поэтому эти стеки задач существуют в раздельности и нерушимы. Но на самом деле - если, как только что написал, снова вызовем какую-то любую функцию то значение структуры все равно покоцается в этом "нерушимом" стеке. Или опять-таки я не прав и все не так? И вообще зачем они так это сделали по-дурацки (так выходит)? Зачем этот LwIP себе еще отдельные порции RAM "отгребает" при инициализации? И не малые причем! Это все отдельные и другие вопросы (их много вообще-то). Но пока хотя бы на этот вопрос в теме кто бы ответил.
Go to the top of the page
 
+Quote Post
des333
сообщение Apr 8 2016, 07:13
Сообщение #7


Профессионал
*****

Группа: Свой
Сообщений: 1 129
Регистрация: 19-07-08
Из: Санкт-Петербург
Пользователь №: 39 079



AleksBak:

Представьте, Вам нужно написать функцию, которая будет внутри использовать malloc для выделения памяти.

Но указатель на выделенную память нужно вернуть не через возвращаемое значение, а через один из аргументов функции.

Подумайте, как бы Вы написали такую функцию -- уверен, это поможет найти ответ на Ваш вопрос sm.gif


--------------------
Go to the top of the page
 
+Quote Post
AleksBak
сообщение Apr 8 2016, 07:36
Сообщение #8


Частый гость
**

Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364



Цитата(des333 @ Apr 8 2016, 11:13) *
...
Представьте, Вам нужно написать функцию, которая будет внутри использовать malloc для выделения памяти.
...

malloc-ом я память выделяю и сразу же дальше использую внутри функции. А тут в одной функции выделена память, создана переменная в этой памяти и возвращается указатель на эту созданную переменную. А в вызвавшей функции мы продолжаем обращаться к той переменной несмотря на то, что она когда-то была простой локальной переменной в той функции, а не у нас и не здесь. Так теперь понятно? Это же разные вещи тут. Еще вот объяснение у меня есть - может в этом LwIP не настолько все просто сделано и этот указатель, который возвращается указывает на какую-то особую "LwIP"-овскую суперпамять внутри RAM? Но что-то по коду такого не видно тут такого абсолютно. Надо бы отладчиком посмотреть, что и как когда будет возможность.
Go to the top of the page
 
+Quote Post
des333
сообщение Apr 8 2016, 07:50
Сообщение #9


Профессионал
*****

Группа: Свой
Сообщений: 1 129
Регистрация: 19-07-08
Из: Санкт-Петербург
Пользователь №: 39 079



Цитата(AleksBak @ Apr 8 2016, 10:36) *
...Так теперь понятно?...

Мне точно понятно, что Вы прочитали не всё моё сообщение sm.gif

Цитата
Но указатель на выделенную память нужно вернуть не через возвращаемое значение, а через один из аргументов функции.

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

Всё-таки советую Вам написать такую функцию sm.gif
А уже потом, если вопросы всё-таки останутся, то обсудить их.


--------------------
Go to the top of the page
 
+Quote Post
AleksBak
сообщение Apr 8 2016, 08:12
Сообщение #10


Частый гость
**

Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364



Цитата(des333 @ Apr 8 2016, 11:50) *
...написать функцию-обёртку для malloc, которая будет не просто использовать память, а возвращать её наружу (и именно через аргумент).
Всё-таки советую Вам написать такую функцию sm.gif....

Да я Вам сразу отвечу как бы все это было бы. Что тут размышлять как и чего. Выделил память, ничего бы с ней не делал дальше и тут же вернул бы на нее указатель. И Все. А тут - выделяется память, в ней создается переменная, что-то с ней делается, а потом возвращается указатель на ту переменную, а далее мы у себя опять обращаемся к этой переменной откуда-то в куче (в мусорке), а если еще какую-то функцию вызовем по дороге вдруг неожиданно, то ничего не останется от той переменной в мусорке, но будем все равно к ней обращаться т.к. так учат нас.

Еще добавлю - где-то даже кажется есть строгое указание в рекомендациях, что так делать категорически не рекомендуется. Вот только не помню где это и кто бы подсказал бы тут.
Go to the top of the page
 
+Quote Post
des333
сообщение Apr 8 2016, 08:13
Сообщение #11


Профессионал
*****

Группа: Свой
Сообщений: 1 129
Регистрация: 19-07-08
Из: Санкт-Петербург
Пользователь №: 39 079



Цитата(AleksBak @ Apr 8 2016, 11:12) *
Да я Вам сразу отвечу как бы все это было бы. Что тут размышлять как и чего.


Это Ваш выбор sm.gif

Вы просили помощи, я пытался Вам помочь sm.gif


--------------------
Go to the top of the page
 
+Quote Post
AleksBak
сообщение Apr 8 2016, 08:27
Сообщение #12


Частый гость
**

Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364



Цитата(des333 @ Apr 8 2016, 12:13) *
Это Ваш выбор sm.gif

Вы просили помощи, я пытался Вам помочь sm.gif

Ну да - спасибо и на этом. Кстати тут вообще-то ничего не выделяется - в смысле это не какая-то ненужная обертка для функции mallocc как Вы пишите с самого начала, а я пытаюсь Вам отвечать согласно такой теории и в итоге не прав оказываюсь. Здесь просто: 1. создается локальная переменная; 2. что-то делается; 3. и возвращается потом указатель на эту локальную переменную. Вот так правильное описание, что тут происходит.
Go to the top of the page
 
+Quote Post
gosha-z
сообщение Apr 8 2016, 08:39
Сообщение #13


Местный
***

Группа: Свой
Сообщений: 327
Регистрация: 30-10-05
Пользователь №: 10 288



Я правильно понимаю, что newconn во втором сообщении обретает значение при вызове sys_arch_mbox_fetch? Если да - то что говорит дока на эту функцию по поводу способа выделения памяти для этой структуры и последующего ее освобождения?
Go to the top of the page
 
+Quote Post
AleksBak
сообщение Apr 8 2016, 08:56
Сообщение #14


Частый гость
**

Группа: Участник
Сообщений: 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) *
...Если да - то что говорит дока на эту функцию по поводу способа выделения памяти для этой структуры и последующего ее освобождения?

Не знаю. Я новичок тут и поэтому спросил как оно работает и почему так сделано.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 8 2016, 08:58
Сообщение #15


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Reply to this topicStart new topic
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 24th June 2025 - 17:12
Рейтинг@Mail.ru


Страница сгенерированна за 0.01505 секунд с 7
ELECTRONIX ©2004-2016