惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
N
Netflix TechBlog - Medium
V
Visual Studio Blog
博客园 - Franky
小众软件
小众软件
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 三生石上(FineUI控件)
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
宝玉的分享
宝玉的分享
量子位
大猫的无限游戏
大猫的无限游戏
人人都是产品经理
人人都是产品经理
V
V2EX
The Cloudflare Blog
月光博客
月光博客
Last Week in AI
Last Week in AI
雷峰网
雷峰网
WordPress大学
WordPress大学
博客园 - 【当耐特】
博客园 - 聂微东
IT之家
IT之家
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

lvbibir's Blog

shell | 磁盘空间分析脚本 Linux cat 和 tee 命令写入文件 python | 使用 uv 管理你的 python 环境 Claude Code 完整配置指南 windows | mihomo 内核独立部署指南 linux | 磁盘扩容 wsl | 释放长久运行占用的磁盘空间 mysql | 线程上限问题处理 麒麟 7.6 安装谷歌 OTP 认证模块 suse 12sp5 升级 openssh 及 openssl suse 12sp5 部署 mysql 5.7 《谁的青春不迷茫》 docker | centos7 部署 docker vim | 基础配置和使用 windows | rime 输入法 & 雾凇方案 shell | sshpass 批量传输文件及执行命令 wsl | 原生 linux 方式安装 docker nodejs | fnm + pnpm 开发环境配置 wsl | 安装配置 miniconda 虚拟环境 wsl | 自动更新系统代理 wsl | bashrc 环境变量不正确加载的处理方法 wsl | win10 安装 wsl2 troubleshooting | ssh 成功但是 scp 失败 linux | 常用命令总结 docker 部署 piclist shell | 检测网站存活并自动钉钉告警 Zabbix | 监控端口连通性并自动追踪 TCP 路由 windows | 自定义开机快速启动项 windows | miniconda 配置 python 虚拟环境 Zabbix | 监控主机到指定 ip 的流量大小
troubleshooting | glibc 的 fread 问题
lvbibir · 2021-09-01 · via lvbibir's Blog

0 前言

有需求需要在 openeuler 的操作系统上测试一个 C 程序,做了一个简化版的程序,程序很简单,循环读取一个文件并打印文件内容,在程序执行过程中使用 echo 手动向文件中追加内容,程序要能读取到,效果如下:

e2796ca3c4850af67b578be9bb0148d

测试程序代码如下:

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>

int main(int argc, char **argv)
{
        FILE *f = fopen("./Syslog.log", "rb");
        if (f == NULL) return 1;
        char buffer[1024] = {0};
        size_t len = 0;
        while(1)
        {
                len = fread(buffer, 1, sizeof(buffer), f);
                if (len > 0)
                {
                        buffer[len] = '\0';
                        printf("read:%s\n",buffer);
                }
                else
                {
                printf("noread\n");
                }
                sleep(2);
        }
        return 0;
}

在 Rhel-7.5 上测试一切正常,开始在 openeuler 上进行测试,结果发现后续追加的内容没有输出:

dfaaeee2427fbc2fb21f825c9350cf9

1 故障排查

考虑到影响程序执行结果的几个因素:程序本身,内核版本,gcc 版本,glibc 版本。

程序本身应该是没问题的,内核版本一般对 C 语言程序的影响也不会很大,还是优先看 gcc 版本和 glibc 版本。

按照思路进行了一些测试,测试结果:

  • 可行:
  • centos7.5(gcc-4.8.5,kernel-3.10,glibc<=2.28)
  • centos7.5(gcc-7.3.0,kernel-3.10,glibc<=2.28)
  • centos7.5(gcc-7.3.0,kernel-5.12,glibc<=2.28)
  • 不可行:
  • isoft-server-6.0(gcc-7.3.0,4.19.90,glibc>=2.28)
  • centos8(gcc-8.4.0,kernel-4.18.0,glibc>=2.28)
  • openeuler-20.03-LTS-SP1(gcc-7.3.0,kernel-4.19.90,glibc>=2.28)

按照测试结果,似乎 gcc 版本和内核版本对程序没什么影响,大概率应该是 glibc 版本导致的。由于程序很简单,只是以 rb 方式 fopen 打开文件循环读取文件内容,求证 (google) 起来也比较轻松,很快就找到了问题在哪:glibc 2.28 修复了 fread 的行为

这个 glibc 的 bug 是 05 年提的,到 18 年才修复,也是担心 break 之前大量的代码。https://sourceware.org/bugzilla/show_bug.cgi?id=1190

现在再修改一下代码:

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>

int main(int argc, char **argv)
{
        FILE *f = fopen("./Syslog.log", "rb");
        if (f == NULL) return 1;
        char buffer[1024] = {0};
        size_t len = 0;
        while(1)
        {
                len = fread(buffer, 1, sizeof(buffer), f);
                if (len > 0)
                {
                        buffer[len] = '\0';
                        printf("read:%s\n",buffer);
                }
                else
                {
                if (feof (f)) {
                        printf("Read error, clear error flag to retry...\n");
                        clearerr (f);
                }
                }
                sleep(2);
        }
        return 0;
}

1adf1e265c52983b9d4fb3dadd27199

添加了一块清除标记的片段,在 glibc>=2.28 的系统上程序也可以正常运行了

image-20210910151213242

以上