0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

RT-Smart應(yīng)用開(kāi)發(fā)筆記:fopen造成文件被清空問(wèn)題的分析記錄

冬至子 ? 來(lái)源:張世爭(zhēng) ? 作者:張世爭(zhēng) ? 2023-10-20 16:01 ? 次閱讀

前言

RT-Smart 應(yīng)用(apps)開(kāi)發(fā)環(huán)境,ubuntu 20.04 + win10 VS Code

最近在調(diào)試一個(gè)問(wèn)題,需要使用 FILE 的 fopen、fread 等去讀取處理一個(gè)大文件,為了盡快復(fù)現(xiàn)驗(yàn)證問(wèn)題,隨手搜了一下 fopen 等幾個(gè) API的用法,調(diào)試時(shí)鬧出來(lái)一個(gè)【笑話】,程序運(yùn)行所到之處,把處理過(guò)的本地文件清空了。

當(dāng)時(shí)初步的目標(biāo)只是使用 stat 去獲取一個(gè)文件的大小,現(xiàn)象就是 0

獲取文件大小

如何在 用戶態(tài)獲取文件大小,RT-Smart 的應(yīng)用開(kāi)發(fā)與 Linux 的用戶應(yīng)用開(kāi)發(fā)基本類似,Linux 平臺(tái)上的應(yīng)用,可以輕松的移植到 RT-Smart 上。

fopen 可以在RT-Smart內(nèi)核態(tài)使用,也可以在用戶態(tài)使用,用戶態(tài)的使用,一般都是借助 libc 與 系統(tǒng)調(diào)用,當(dāng)前 RT-Smart 使用 musl gcc 工具鏈

獲取文件大小,應(yīng)該與 fopen、fread 系列無(wú)關(guān),代碼如下:

unsigned long get_file_size(const char *path)
{
unsigned long filesize = -1;
struct stat statbuff;
if (stat(path, &statbuff) < 0)
{
return filesize;
}
else
{
filesize = statbuff.st_size;
}
return filesize;
}

這里使用標(biāo)準(zhǔn)的 POSIX 接口 stat,頭文件 #include

測(cè)試代碼

隨手摘抄修改了一個(gè)測(cè)試代碼,想獲取到 文件大小,然后分批讀取,驗(yàn)證這個(gè)過(guò)程是否正常,哪想到文件大小獲取為0,使用 qemu 調(diào)試了多遍,懷疑文件系統(tǒng)BUG,依舊未找到正確的思路

原 BUG 測(cè)試代碼如下:

/* read big file : > 300MB */
#include
#include
#include
#include
#include
#include
#include
#define BUFFER_SIZE (8 * 1024 * 1024)
unsigned long get_file_size(const char *path)
{
unsigned long filesize = -1;
struct stat statbuff;
if (lstat(path, &statbuff) < 0)
{
return filesize;
}
else
{
filesize = statbuff.st_size;
}
return filesize;
}
int main(int argc, char **argv)
{
//int errno;
FILE *fp = NULL;
unsigned long so_far, signed_len;
const char *path = "/lib/libc.so";
char *buffer = NULL;
size_t size;
size_t file_size;
size_t rd_len;
if (argc > 1)
{
path = argv[1];
}
printf("filename path : %sn", path);
fp = fopen(path, "w+");
if (!fp)
{
printf("fopen failedn");
return -1;
}
buffer = malloc(BUFFER_SIZE);
if (!buffer)
{
printf("buffer alloc failedn");
return -1;
}
file_size = get_file_size(path);
printf("file size %ldn", file_size);
signed_len = file_size;
so_far = 0;
while (so_far < signed_len)
{
size = BUFFER_SIZE;
printf("so far is %lu, signed_len is %lu, size is %lun", so_far, signed_len, size);
if (signed_len - so_far < size)
size = signed_len - so_far;
printf("new size is %lun", size);
rd_len = fread(buffer, 1, size, fp);
printf("fread rd_len = %ldn", rd_len);
if ((rd_len != 0) && (rd_len != size))
{
printf("fread failed, rd_len = %ld, size = %ldn", rd_len, size);
fclose(fp);
free(buffer);
return -2;
}
so_far += size;
printf("fread so_far = %ldn", so_far);
}
fclose(fp);
free(buffer);
printf("fread big file test end!n");
return 0;
}

測(cè)試結(jié)果

文件大小 讀取 為 0

1.jpg

由于可以使用 qemu 來(lái)調(diào)試,我看看到底為何 大小為0,難道 打印的不對(duì)?

1.jpg

2.jpg

3.jpg

內(nèi)核部分的 sys_stat 后面的調(diào)試就不放上來(lái)了,說(shuō)明一個(gè)問(wèn)題:文件獲取大小就是 0

回頭看下測(cè)試結(jié)果

好吧,我發(fā)現(xiàn)了文件系統(tǒng)BUG?讀取一下?tīng)顟B(tài),文件大小就變?yōu)?0 了?

我多試讀取了幾個(gè)文件,文件大小真的變?yōu)榱?,包括 /lib/libc.so 這個(gè)默認(rèn)文件

我在板子上試了一下,讀取了一下文件系統(tǒng)中的核心文件: rtthread.bin,哪想到,板子啟動(dòng)不了,看了固件被【真正】清零0

1.jpg

趕快看看神奇的代碼

發(fā)現(xiàn) BUG 了,原來(lái)在 獲取文件狀態(tài)前,有個(gè) fopen 操作,并且使用了 "w+",就是這個(gè)問(wèn)題

1.jpg

2.jpg

都是C 語(yǔ)言基礎(chǔ)薄弱惹的禍,記錄一下,以后得好好學(xué)習(xí),正確理解,才能致用。

fopen 的 參數(shù)

當(dāng)前發(fā)現(xiàn) fopen 使用 “a+” 也不能獲取文件大小,二進(jìn)制的文件,需要使用 “rb”

1.jpg

正常使用了 fopen 后,文件大小就正常獲取了

1.jpg

看來(lái)測(cè)試代碼,也需要認(rèn)真寫(xiě),測(cè)試過(guò)程中【看似無(wú)關(guān)緊要】的代碼,也許就是個(gè)【地雷】

小結(jié)

以上記錄,其實(shí)就是 fopen 參數(shù)的使用方法的一個(gè)記錄,寫(xiě)這么多,就是增加【印象】,得到【教訓(xùn)】,防止編寫(xiě)此類BUG 的事情不再重復(fù)犯。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 二進(jìn)制
    +關(guān)注

    關(guān)注

    2

    文章

    761

    瀏覽量

    41476
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7575

    瀏覽量

    134092
  • RT-Thread
    +關(guān)注

    關(guān)注

    31

    文章

    1239

    瀏覽量

    39435
  • Ubuntu系統(tǒng)
    +關(guān)注

    關(guān)注

    0

    文章

    85

    瀏覽量

    3859
  • gcc編譯器
    +關(guān)注

    關(guān)注

    0

    文章

    78

    瀏覽量

    3297
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    通過(guò)Uboot?TFTP啟動(dòng)rt-smart內(nèi)核

    介紹Windows下通過(guò) Uboot??TFTP 方式下載和啟動(dòng)rt-smart 內(nèi)核
    的頭像 發(fā)表于 06-30 12:34 ?3503次閱讀
    通過(guò)Uboot?TFTP啟動(dòng)<b class='flag-5'>rt-smart</b>內(nèi)核

    RT-Smart開(kāi)發(fā)筆記:int類型數(shù)值溢出造成的奇怪問(wèn)題的分析與排查記錄

    最近在調(diào)試 RT-Smart 上的用戶態(tài) mq(消息隊(duì)列)時(shí),遇到一個(gè)奇怪的問(wèn)題,這個(gè)例程打印了一下獲取的時(shí)間,就可以正常的工作(超時(shí)退出),否則,就一直卡?。o(wú)法超時(shí))
    的頭像 發(fā)表于 10-31 16:16 ?626次閱讀
    <b class='flag-5'>RT-Smart</b><b class='flag-5'>開(kāi)發(fā)筆記</b>:int類型數(shù)值溢出<b class='flag-5'>造成</b>的奇怪問(wèn)題的<b class='flag-5'>分析</b>與排查<b class='flag-5'>記錄</b>

    RT-Smart的資料合集

    基礎(chǔ),講解 RT-Smart 的啟動(dòng)過(guò)程。內(nèi)核地址空間RT-SmartRT-Thread 的一大區(qū)別是用戶態(tài)和內(nèi)核態(tài)的地址空間隔離開(kāi)來(lái)。內(nèi)核運(yùn)行在內(nèi)核地址空間,用戶進(jìn)程運(yùn)行在用
    發(fā)表于 03-22 15:06

    rt-smart中斷阻塞問(wèn)題是怎么引起的

    跟蹤發(fā)現(xiàn),阻塞原因是lwp_console.c文件里,打印消息前,中斷關(guān)閉了。然而rt_device_write()恰恰是一個(gè)阻塞型的發(fā)送,這就造成了中斷的長(zhǎng)時(shí)間延誤,影響了OS整體
    發(fā)表于 03-25 09:56

    請(qǐng)問(wèn)rt-smart gdbserver是閉源的嗎?

    編譯“RT-Smart”,啟用RT_USING_GDBSERVER時(shí),發(fā)現(xiàn)許多文件都找不到,請(qǐng)問(wèn)這部分代碼不公開(kāi)嗎?比如#include #include
    發(fā)表于 04-19 09:37

    請(qǐng)問(wèn)rt-smart gdbserver是閉源的嗎?

    編譯“RT-Smart”,啟用RT_USING_GDBSERVER時(shí),發(fā)現(xiàn)許多文件都找不到,請(qǐng)問(wèn)這部分代碼不公開(kāi)嗎?比如#include #include
    發(fā)表于 04-26 10:01

    D1哪吒開(kāi)發(fā)rt-smart內(nèi)核固件的燒寫(xiě)與運(yùn)行步驟

    的windows的燒寫(xiě)工具:PhoenixSuit.exe,選擇 打包好的rt-smart鏡像文件:PhoenixSuit.exe哪吒開(kāi)發(fā)板斷電, 按住 按鍵【FEL】,USB 插入 【OTG】的 USB
    發(fā)表于 06-17 11:06

    開(kāi)機(jī)體驗(yàn)rt-smart:webserver網(wǎng)關(guān)

    軟件代碼交叉編譯成目標(biāo)系統(tǒng)平臺(tái)可以運(yùn)行的庫(kù)或二進(jìn)制文件,作為 rt-smart 的一個(gè)用戶 APP,并在 ART-Pi Smart 開(kāi)發(fā)板上運(yùn)行。用戶也可以根據(jù) 文檔下面的章節(jié) “用
    發(fā)表于 06-30 11:17

    樹(shù)莓派上rt-smart的應(yīng)用編程入門(mén)

    我們從現(xiàn)在開(kāi)始會(huì)逐步連載RT-Thread Smart(簡(jiǎn)稱rt-smart,甚至有時(shí)會(huì)稱為smart os)的介紹文章,旨在讓大家認(rèn)識(shí),接觸到sm
    的頭像 發(fā)表于 05-13 14:10 ?2980次閱讀
    樹(shù)莓派上<b class='flag-5'>rt-smart</b>的應(yīng)用編程入門(mén)

    rt-smart移植分析:從樹(shù)莓派3b入手

    移植rt-smart到最新的板子上具體需要注意哪些細(xì)節(jié),哪些才是移植rt-smart的關(guān)鍵點(diǎn)?本文從樹(shù)莓派3b上移植rt-smart的角度,從頭分析
    發(fā)表于 01-25 18:48 ?0次下載
    <b class='flag-5'>rt-smart</b>移植<b class='flag-5'>分析</b>:從樹(shù)莓派3b入手

    優(yōu)雅的在D1S上運(yùn)行RT-Smart

    前言 最近在學(xué)習(xí) RT-Smart ,正巧有在全志開(kāi)發(fā)者論壇看到這么一篇帖子【驚】在麻雀上運(yùn)行國(guó)產(chǎn)rt-smart系統(tǒng),看到很多人都在關(guān)注 D1S 在 Smart 上的運(yùn)行情況。如今該
    的頭像 發(fā)表于 11-16 20:15 ?2584次閱讀

    絲滑的在RT-Smart用戶態(tài)運(yùn)行LVGL

    開(kāi)發(fā)流程 1、RT-Smart 環(huán)境搭建 下載 RT-Smart 用戶態(tài)應(yīng)用代碼: 1 git?clone?https: //github.com/RT-Thread/userapps
    的頭像 發(fā)表于 11-22 20:20 ?1115次閱讀

    RT-Smart riscv64匯編注釋

    rt-smart在全志D1上的代碼為例,主要注釋了rt-smart在riscv64上的系統(tǒng)初始化和異常處理的代碼倉(cāng)庫(kù)地址https://gitee.com/rtthread/rt
    的頭像 發(fā)表于 02-08 21:40 ?1023次閱讀

    零基礎(chǔ)上手rt-smart適配bsp

    RT-Thread Smart(簡(jiǎn)稱rt-smart)是基于RT-Thread操作系統(tǒng)衍生,面向帶MMU(Memory Management Unit),中高端應(yīng)用的芯片,例如ARM
    的頭像 發(fā)表于 08-08 10:34 ?795次閱讀
    零基礎(chǔ)上手<b class='flag-5'>rt-smart</b>適配bsp

    RT-Smart riscv64匯編注釋

    rt-smart在全志D1上的代碼為例,主要注釋了rt-smart在riscv64上的系統(tǒng)初始化和異常處理的代碼
    的頭像 發(fā)表于 10-12 17:26 ?507次閱讀
    <b class='flag-5'>RT-Smart</b> riscv64匯編注釋