0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

RT-Smart应用开发笔记:fopen造成文件被清空问题的分析记录

冬至子 来源:张世争 作者:张世争 2023-10-20 16:01 次阅读

前言

RT-Smart 应用(apps)开发环境,ubuntu 20.04 + win10 VS Code

最近在调试一个问题,需要使用 FILE 的 fopen、fread 等去读取处理一个大文件,为了尽快复现验证问题,随手搜了一下 fopen 等几个 API的用法,调试时闹出来一个【笑话】,程序运行所到之处,把处理过的本地文件清空了。

当时初步的目标只是使用 stat 去获取一个文件的大小,现象就是 0

获取文件大小

如何在 用户态获取文件大小,RT-Smart 的应用开发与 Linux 的用户应用开发基本类似,Linux 平台上的应用,可以轻松的移植到 RT-Smart 上。

fopen 可以在RT-Smart内核态使用,也可以在用户态使用,用户态的使用,一般都是借助 libc 与 系统调用,当前 RT-Smart 使用 musl gcc 工具链

获取文件大小,应该与 fopen、fread 系列无关,代码如下:

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;
}

这里使用标准的 POSIX 接口 stat,头文件 #include

测试代码

随手摘抄修改了一个测试代码,想获取到 文件大小,然后分批读取,验证这个过程是否正常,哪想到文件大小获取为0,使用 qemu 调试了多遍,怀疑文件系统BUG,依旧未找到正确的思路

原 BUG 测试代码如下:

/* 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;
}

测试结果

文件大小 读取 为 0

1.jpg

由于可以使用 qemu 来调试,我看看到底为何 大小为0,难道 打印的不对?

1.jpg

2.jpg

3.jpg

内核部分的 sys_stat 后面的调试就不放上来了,说明一个问题:文件获取大小就是 0

回头看下测试结果

好吧,我发现了文件系统BUG?读取一下状态,文件大小就变为 0 了?

我多试读取了几个文件,文件大小真的变为了0,包括 /lib/libc.so 这个默认文件

我在板子上试了一下,读取了一下文件系统中的核心文件: rtthread.bin,哪想到,板子启动不了,看了固件被【真正】清零0

1.jpg

赶快看看神奇的代码

发现 BUG 了,原来在 获取文件状态前,有个 fopen 操作,并且使用了 "w+",就是这个问题

1.jpg

2.jpg

都是C 语言基础薄弱惹的祸,记录一下,以后得好好学习,正确理解,才能致用。

fopen 的 参数

当前发现 fopen 使用 “a+” 也不能获取文件大小,二进制的文件,需要使用 “rb”

1.jpg

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

1.jpg

看来测试代码,也需要认真写,测试过程中【看似无关紧要】的代码,也许就是个【地雷】

小结

以上记录,其实就是 fopen 参数的使用方法的一个记录,写这么多,就是增加【印象】,得到【教训】,防止编写此类BUG 的事情不再重复犯。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 二进制
    +关注

    关注

    2

    文章

    792

    浏览量

    41593
  • C语言
    +关注

    关注

    180

    文章

    7597

    浏览量

    136121
  • RT-Thread
    +关注

    关注

    31

    文章

    1271

    浏览量

    39905
  • Ubuntu系统
    +关注

    关注

    0

    文章

    85

    浏览量

    3906
  • gcc编译器
    +关注

    关注

    0

    文章

    78

    浏览量

    3356
收藏 人收藏

    评论

    相关推荐

    通过Uboot TFTP启动rt-smart内核

    介绍Windows下通过 Uboot  TFTP 方式下载和启动rt-smart 内核
    的头像 发表于 06-30 12:34 3629次阅读
    通过Uboot TFTP启动<b class='flag-5'>rt-smart</b>内核

    RT-Smart开发笔记:int类型数值溢出造成的奇怪问题的分析与排查记录

    最近在调试 RT-Smart 上的用户态 mq(消息队列)时,遇到一个奇怪的问题,这个例程打印了一下获取的时间,就可以正常的工作(超时退出),否则,就一直卡住(无法超时)
    的头像 发表于 10-31 16:16 755次阅读
    <b class='flag-5'>RT-Smart</b><b class='flag-5'>开发笔记</b>:int类型数值溢出<b class='flag-5'>造成</b>的奇怪问题的<b class='flag-5'>分析</b>与排查<b class='flag-5'>记录</b>

    RT-Smart的资料合集

    基础,讲解 RT-Smart 的启动过程。内核地址空间RT-SmartRT-Thread 的一大区别是用户态和内核态的地址空间隔离开来。内核运行在内核地址空间,用户进程运行在用
    发表于 03-22 15:06

    rt-smart中断阻塞问题是怎么引起的

    跟踪发现,阻塞原因是lwp_console.c文件里,打印消息前,中断关闭了。然而rt_device_write()恰恰是一个阻塞型的发送,这就造成了中断的长时间延误,影响了OS整体
    发表于 03-25 09:56

    请问rt-smart gdbserver是闭源的吗?

    编译“RT-Smart”,启用RT_USING_GDBSERVER时,发现许多文件都找不到,请问这部分代码不公开吗?比如#include #include
    发表于 04-19 09:37

    请问rt-smart gdbserver是闭源的吗?

    编译“RT-Smart”,启用RT_USING_GDBSERVER时,发现许多文件都找不到,请问这部分代码不公开吗?比如#include #include
    发表于 04-26 10:01

    D1哪吒开发rt-smart内核固件的烧写与运行步骤

    的windows的烧写工具:PhoenixSuit.exe,选择 打包好的rt-smart镜像文件:PhoenixSuit.exe哪吒开发板断电, 按住 按键【FEL】,USB 插入 【OTG】的 USB
    发表于 06-17 11:06

    开机体验rt-smart:webserver网关

    软件代码交叉编译成目标系统平台可以运行的库或二进制文件,作为 rt-smart 的一个用户 APP,并在 ART-Pi Smart 开发板上运行。用户也可以根据 文档下面的章节 “用
    发表于 06-30 11:17

    树莓派上rt-smart的应用编程入门

    我们从现在开始会逐步连载RT-Thread Smart(简称rt-smart,甚至有时会称为smart os)的介绍文章,旨在让大家认识,接触到sm
    的头像 发表于 05-13 14:10 3108次阅读
    树莓派上<b class='flag-5'>rt-smart</b>的应用编程入门

    rt-smart移植分析:从树莓派3b入手

    移植rt-smart到最新的板子上具体需要注意哪些细节,哪些才是移植rt-smart的关键点?本文从树莓派3b上移植rt-smart的角度,从头分析
    发表于 01-25 18:48 0次下载
    <b class='flag-5'>rt-smart</b>移植<b class='flag-5'>分析</b>:从树莓派3b入手

    优雅的在D1S上运行RT-Smart

    前言 最近在学习 RT-Smart ,正巧有在全志开发者论坛看到这么一篇帖子【惊】在麻雀上运行国产rt-smart系统,看到很多人都在关注 D1S 在 Smart 上的运行情况。如今该
    的头像 发表于 11-16 20:15 2791次阅读

    丝滑的在RT-Smart用户态运行LVGL

    开发流程 1、RT-Smart 环境搭建 下载 RT-Smart 用户态应用代码: 1 git clone https: //github.com/RT-Thread/userapps
    的头像 发表于 11-22 20:20 1214次阅读

    RT-Smart riscv64汇编注释

    rt-smart在全志D1上的代码为例,主要注释了rt-smart在riscv64上的系统初始化和异常处理的代码仓库地址https://gitee.com/rtthread/rt
    的头像 发表于 02-08 21:40 1104次阅读

    零基础上手rt-smart适配bsp

    RT-Thread Smart(简称rt-smart)是基于RT-Thread操作系统衍生,面向带MMU(Memory Management Unit),中高端应用的芯片,例如ARM
    的头像 发表于 08-08 10:34 1007次阅读
    零基础上手<b class='flag-5'>rt-smart</b>适配bsp

    RT-Smart riscv64汇编注释

    rt-smart在全志D1上的代码为例,主要注释了rt-smart在riscv64上的系统初始化和异常处理的代码
    的头像 发表于 10-12 17:26 575次阅读
    <b class='flag-5'>RT-Smart</b> riscv64汇编注释