2012-06-18 28 views
8

私はlwipと呼ばれるTCP/IPスタックを使用しています。データパケットを受信する同様のコールバック関数からインスピレーションを得てデータパケットを送信する関数を以下に実装しました。LightWeight IP:バッファが解放されない

パケットを受信するたびに、pbuf_alloc機能を使用してバッファを作成します。それから私はudp_sendtoを使ってパケットを送ります。最後に、pbuf_freeを使用してバッファを解放します。 (下のコードを参照してください)

何らかの理由により、pbuf_freeはバッファを解放していません。 (私はnプールサイズでnパケットの後にバッファオーバーフローを得る)The lwip wikiその警告:

をネットワークドライバはまた、pbuf_freeを呼び出すときPBUFメモリは が実際に解放されることを前提としなくてもよいです。

pbuf_freeでバッファを解放するにはどうすればよいですか?バッファオーバーフローはどのように回避されますか?

(以下マイ実装。)

static err_t IAP_tftp_send_data_packet(struct udp_pcb *upcb, struct ip_addr *to, int to_port, int block) 
{ 
    err_t err; 
    struct pbuf *pkt_buf; 
    char packet[TFTP_DATA_PKT_LEN_MAX]; 
    int bytesRead; 
    int bytesToSend; 

    /* Specify that we are sending data. */ 
    IAP_tftp_set_opcode(packet, TFTP_DATA); 

    /* Specify the block number that we are sending. */ 
    IAP_tftp_set_block(packet, block); 

    bytesRead = IAP_tftp_set_data(packet, block); 

    if(bytesRead != 0) { 
    bytesToSend = TFTP_DATA_PKT_LEN_MAX - (512 - bytesRead + 1); 
    } else { 
    bytesToSend = TFTP_DATA_PKT_LEN_MAX - 512; 
    } 

    pkt_buf = pbuf_alloc(PBUF_TRANSPORT, bytesToSend, PBUF_POOL); 

    if (!pkt_buf) 
    { 
    print("(TFTP) Buffer overflow!\r\n"); 
    } 

    /* Copy the file data onto pkt_buf. */ 
    memcpy(pkt_buf->payload, packet, bytesToSend); 

    err = udp_sendto(upcb, pkt_buf, to, to_port); 

    /* free the buffer pbuf */ 
    printf("%d\n\r", pbuf_free(pkt_buf)); 

    return err; 
} 
+0

バッファへの参照カウントを確認しましたか?私は参照カウントが1の場合にのみ解放されるのではないかと心配しています。 – Fred

+0

おそらく 'udp_sendto'は参照を取り、それを非同期的に解放します(タイマー?)。たぶん、あなたはそれをしばらく置く必要がありますか? – ugoren

+0

@ugoren:バッファオーバーフローが発生している間に待機しようとしましたが、バッファオーバーフローが残ります。 – Randomblue

答えて

7

あなたはどのバージョンのlwIPを使用していますか? 異なるバージョンによって、回答が大きく異なります。

pbuf_alloc()内で呼び出されたmemp_malloc()割り当て関数が失敗したか、pbufsの連鎖が失敗したため、NULLを返します。

pbuf_alloc()は、渡された引数にもNULLが含まれているとNULLを返します(NULL引き数のチェックのため)。

新しいバージョンでは、MEMP_OVERFLOW_CHECKマクロに含まれる値を表示できますか? lwIPは、マクロ値> = 2のときに別の動作を示します。

また、マルチスレッドを使用している場合、pbuf_alloc()内のロック機構が失敗し、NULLを返す可能性があります。

一部のバージョンでは、pbuf_alloc()を呼び出す前にpbuf_init()を呼び出す必要があります。

あなたはこれを試すことができます。

pkt_buf = NULL;//Use NULL, just incase the NULL is not 0 as per your compiler. 
pkt_buf = pbuf_alloc(PBUF_TRANSPORT, bytesToSend, PBUF_REF); 
if(pkt_buf == NULL) 
{ 
    printf("pbuf_alloc failed.\n"); 
} 
else 
{ 
    /* Do something with the allocated pbufs and free it. */ 
} 

PBUF_REFはPBUFのために何のバッファメモリを割り当てません。 pbufは単一のスレッドでのみ使用され、pbufがキューに入れられた場合は、バッファをコピーするためにpbuf_takeを呼び出す必要があります。

RAMにバッファを割り当てるPBUF_RAMを試すこともできます。

more informtaionでは、使用しているlwIPのバージョンのソースファイルを参照することもできます。

+0

この回答が依然としてあなたの質問に答えなかったかどうか教えてください。 – askmish

+0

あなたの答えは最も有望なので、私はあなたに賞金をあげました。私は調査する時間があるので、詳細を尋ねなければならないかもしれません。ありがとう。 – Randomblue

+0

快適で十分な時間があれば、wikiではなくあなたのバージョンのソースコードを調べることをお勧めします。 wikiの保守が不十分です。 – askmish

6

最も簡単な解決策は、各呼び出しで同じバッファーを再使用すなわち、バッファstaticを作ることのようだ:

static struct pbuf *pkt_buf = NULL; 

if(pkt_buf == NULL) 
    pkt_buf = pbuf_alloc(PBUF_TRANSPORT, bytesToSend, PBUF_POOL); 
if(pkt_buf == NULL) 
{ 
    print("(TFTP) Buffer overflow!\r\n"); 
} 

シナリオ場合ドライバをアンロード/リロードすると、メモリがリークします。これを修正するには、バッファをIAP_tftp_send_data_packet()関数の外側で静的にし、ドライバがアンロードするときにpbuf_free()を呼び出します(lwipがあなたに指示すると仮定します)。

+0

ハム、動作しません。しかし、良いアイデア。 – Randomblue

0

ちょうど考えて、おそらく完全に無意味です。このコードでは: - TFTP_DATA_PKT_LEN_MAX

if(bytesRead != 0) { 
    bytesToSend = TFTP_DATA_PKT_LEN_MAX - (512 - bytesRead + 1); 
} else { 
    bytesToSend = TFTP_DATA_PKT_LEN_MAX - 512; 
} 
pkt_buf = pbuf_alloc(PBUF_TRANSPORT, bytesToSend, PBUF_POOL); 

...それは、bytesReadは値513を仮定することは可能でしょうか?

もし起これば、0バイトの割り当て要求は失敗しないでしょうか? (これは、バッファオーバーフロー時にbytesToSendの値を出力し、ゼロ以外であるかどうかを調べることでテストできます)。

0

struct pbufは、メモリの連続領域を表していません。それはむしろ記憶場所の連鎖である。したがって、これは一般的なケースでは機能しません。

memcpy(pkt_buf->payload, packet, bytesToSend); 

データを分散コピーする必要があります。コードスニペットのmemcpy()がペイロードバッファをオーバーフローさせ、pbufチェーンをきれいに解放できないなど、あらゆる種類の副作用を引き起こす可能性があります。

関連する問題