| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1391 人关注过本帖
标题:这个函数不用goto怎么改
只看楼主 加入收藏
皮天佑
Rank: 1
等 级:新手上路
帖 子:7
专家分:0
注 册:2015-7-4
收藏
得分:0 
代码作者当时的建议是每个标签做成函数。整个代码都是基于非阻塞的,再加上C_STOP处理起来比较麻烦,作者是说获取输入重复计算接收长度,反正没收到数据,再算一次无所谓,这里最好加上sleep函数让出cpu
2015-07-05 10:07
beyondyf
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
注 册:2008-1-21
收藏
得分:20 
改掉goto是件小事,暂且不提。不妨先探讨一下原代码的正确性和存在的隐患。

一开头除去变量的初始,直接就goto lab_skip_get_header。也就是说在调用mysh_recv_data前已经接收过C_DATAB了。由于你只展示了这么一个函数,其外的操作我无从得知,关于这点你能确定就好。

在lab_skip_get_header部分,通过recv不断接收数据。问题来了。

从recv的调用方式推测它从数据源中读取不超过缓存need数量的数据到p,并返回实际读取的数据长度。当读取不成功时则返回0。

进一步推测recv(p, 0)必然返回0。

由于recv是以函数指针的方式传入mysh_recv_data的,所以推测这么做的原因是你的数据源不止一个,根据不同的源采用不同的读取方式。这类似C++中的多态思想。

由于数据长度是不定的,你确定MYSH_EN_DATA_BLOCK_SIZE的尺寸足够用么?

一旦数据达到或超过MYSH_EN_DATA_BLOCK_SIZE,lab_skip_get_header部分中need将等于0,并由recv(p, 0)返回0,将导致这段代码陷入死循环。

以上问题的防范措施在mysh_recv_data外有么?通过协议避免的?

同样,在lab_try_find_data_end部分中c = *p一语的位置也存在风险。它可能读取EN_DATA_BLOCK外的字段而导致内存访问错误使程序崩溃。单这一句的问题可以通过调换和它下一句的顺序来避免。


再说说读到数据后的处理过程。你在3楼的解释中说到转出来的本地数据有误也会重新接收。但lab_finded_data部分的代码中我没看到相关逻辑。

mysh_data_decode即是解码函数对吧,解码成功则返回解码后的数据长度,否则返回0是吧?

这里你只对加密数据的长度做了判断,解码后不管结果对错直接发送C_OK指令后退出了mysh_recv_data。

当然,对解码后数据的判断可以在mysh_recv_data外做(通过size可以判断),也希望你们是这么做的。

lab_finded_data部分中if (n < 1) continue这句的位置也很混乱。它应该放在解码函数调用之前。如果原数据本就是错的还解它干什么?

以上分析仅供参考。还是那句话,你只展示了这一个函数的代码,它之外你们做了什么我不得而知,无法全面评估你们代码中的漏洞。相比之下去掉goto则是小事一桩。

重剑无锋,大巧不工
2015-07-05 10:36
皮天佑
Rank: 1
等 级:新手上路
帖 子:7
专家分:0
注 册:2015-7-4
收藏
得分:0 
多谢beyoundyf的提醒,确实有2个bug.在接收头的时候应该让len为0,接收完应让把if(n<1)改为sz
2015-07-05 11:00
皮天佑
Rank: 1
等 级:新手上路
帖 子:7
专家分:0
注 册:2015-7-4
收藏
得分:0 
我整理的下程序,

程序代码:
static char
mysh_recv_data(char data[], char endata[], unsigned *size,
           unsigned (*recv)(void *, unsigned),
           unsigned (*send)(const void *, unsigned))
{
    unsigned sz, len, n;
    unsigned need, max_size;
    char *p, *e, *begin, c;

    len = sz = 0;
    begin = endata;
    max_size = MYSH_EN_DATA_BLOCK_SIZE;
    goto lab_input_data;

    while(1)
    {
    /* lab_get_header: */
        begin = endata;
        len = 0; /* discard all data*/

        c = mysh_send_cmd(C_RETRY, send);
        if (c != C_RETRY) break;
        c = mysh_recv_cmd(C_DATAB, recv);
        if (c == C_STOP) break;
        if (c != C_DATAB) continue;

    lab_input_data:
        /* 接收端不发C_RETRY,发送端不会直接重传。但是接收端要加个超时重传。
           如果传输过程中突然硬件突然不通然后再通再不通,可能连续出现C_END丢失和C_DATAB丢失,这样会出现溢出 */
        if (len >= max_size)
            continue;
        need = max_size - len;
        p = endata + len;
        n = recv(p, need);
        if (n < 1)
        {
            /* if (超时) continue; */
            mysh_sleep(100);
            goto lab_input_data;
        }
        len = len + n;
        e = p + n;

    lab_try_find_data_end:
        /* 有预留的空间,程序不会出现访问违例,但这样该最好 */
        while(p < e && mysh_is_endata_char((c = *p)))
            ++p;
        if (p >= e) goto lab_input_data;
        if (c == C_END) goto lab_finded_data;
        if (c == C_STOP) goto lab_return_value;

        while(p < e)
        {
            c = *p++;
            if (c == C_STOP) goto lab_return_value;
            if (c != C_DATAB) continue;
            begin = p;
            goto lab_try_find_data_end;
        }
        /* we re-need a C_DATAB header */
        continue;

    lab_finded_data:
        n = (p - begin);
        sz = mysh_data_decode(data, begin, n);
        /* 应该是判断解码后的数据长度 */
        /* we re-need a C_DATAB header */
        if (sz < 1) continue;
        c = mysh_send_cmd(C_OK, send);
        if (c == C_OK)
           c = C_DATAB;
        break;
    }

lab_return_value:
    *size = sz;
    return c;
}


[ 本帖最后由 皮天佑 于 2015-7-5 12:49 编辑 ]
2015-07-05 11:40
快速回复:这个函数不用goto怎么改
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.057044 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved