linux 线程 fopen,linux线程和fopen()fclose()fgets()

描述的代码如何出错

stdio库缓冲数据,分配内存以存储缓冲的数据 . GNU C库动态分配文件结构(某些库,特别是在Solaris上,使用指向静态分配的文件结构的指针,但缓冲区仍然是动态分配的,除非你设置缓冲否则) .

如果您的线程使用指向全局文件指针的指针的副本(因为您将文件指针作为参数传递给函数),那么可以想象代码将继续访问已经分配的数据结构(甚至虽然它被关闭释放了,但是会从已经存在的缓冲区中读取数据 . 只有当您退出函数或读取超出缓冲区内容时才会出现问题 - 或者先前分配给文件结构的空间将重新分配以供新用途使用 .

FILE *global_fp;

void somefunc(FILE *fp, ...)

{

...

while (fgets(buffer, sizeof(buffer), fp) != 0)

...

}

void another_function(...)

{

...

/* Pass global file pointer by value */

somefunc(global_fp, ...);

...

}

概念证明代码

使用GCC 4.0.1在MacOS X 10.5.8(Leopard)上测试:

#include

#include

FILE *global_fp;

const char etc_passwd[] = "/etc/passwd";

static void error(const char *fmt, const char *str)

{

fprintf(stderr, fmt, str);

exit(1);

}

static void abuse(FILE *fp, const char *filename)

{

char buffer1[1024];

char buffer2[1024];

if (fgets(buffer1, sizeof(buffer1), fp) == 0)

error("Failed to read buffer1 from %s\n", filename);

printf("buffer1: %s", buffer1);

/* Dangerous!!! */

fclose(global_fp);

if ((global_fp = fopen(etc_passwd, "r")) == 0)

error("Failed to open file %s\n", etc_passwd);

if (fgets(buffer2, sizeof(buffer2), fp) == 0)

error("Failed to read buffer2 from %s\n", filename);

printf("buffer2: %s", buffer2);

}

int main(int argc, char **argv)

{

if (argc != 2)

error("Usage: %s file\n", argv[0]);

if ((global_fp = fopen(argv[1], "r")) == 0)

error("Failed to open file %s\n", argv[1]);

abuse(global_fp, argv[1]);

return(0);

}

在自己的源代码上运行时,输出为:

Osiris JL: ./xx xx.c

buffer1: #include

buffer2: ##

Osiris JL:

因此,经验证明在某些系统上,我概述的情景可能会发生 .

如何修复代码

在其他答案中很好地讨论了对代码的修复 . 如果你避免我说明的问题(例如,通过避免全局文件指针),这是最简单的 . 假设这是不可能的,用适当的标志进行编译就足够了(在许多类Unix系统上,编译器标志' -D_REENTRANT '完成了这项工作),你将最终使用基本标准的线程安全版本I / O功能 . 如果做不到这一点,您可能需要围绕对文件指针的访问放置明确的线程安全管理策略;一个互斥体或类似的东西(并修改代码以确保线程在使用相应的文件指针之前使用互斥锁) .

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值