在编写休闲代码时持续做出错误的决策

这是关于 Philip Kaludercic 的网站及他编写的一个用 C 语言编写的小程序“Trip”的介绍。

  • 网站信息:网站链接包括StartIndexAbout⚛ FeedContact,他正将此站点迁移到https://sdf.org/~pkal/,此链接会过期。
  • Trip 程序

    • 目的是自动拦截特定的 Libc 函数并模拟其失败,背景是作者在大学的系统编程课程中担任助教,强调代码的健壮性和可移植性,此工具有助于引发特定错误。
    • 例如,当fork(2)系统调用失败时,通常很难遇到,因为只有系统上的进程数过高时才会失败,而此程序可模拟fork失败,如trip fork:0.5 bashbash可能会立即放弃(设置errnoENOMEM),也可能尝试几次(设置errnoEAGAIN),最后还可能等待一段时间再尝试。
    • 核心机制是使用LD_PRELOAD黑客技术,通过设置环境变量,让动态链接器/加载器在检查通常位置之前先查找某些符号的定义,而 Trip 编译了一个常规的位置独立可执行文件,通过编辑 GCC 生成的 ELF 文件来绕过限制,使其可被ld.so预加载。
    • 预加载自身时,LD_PRELOAD需要共享对象文件的绝对路径,可通过/proc/self目录获取当前执行程序的文件路径,用execvpe(2)执行新程序时传递环境变量。
    • 为了保存 Trip“可执行文件”和 Trip“库”之间的状态,使用了conf环境变量,通过宏定义GSRS来编码函数、失败概率和errno值等信息。
    • ____trip_should_fail函数中,通过检查配置和掷骰子来决定是否模拟函数失败,为避免并发初始化内部状态,使用atomic_flag进行非阻塞同步。
    • 解析errno时,不使用关联数组,而是通过popen(3)cpperrno的符号表示转换为十六进制数字,避免使用sprintf两次,通过$sprintf宏来动态分配内存。
    • 确定函数可能设置的errno值是瓶颈,手动将这些信息写在自定义文件格式中,用 AWK 转换为 C 文件,通过#include将数据注入到数组中。
  • 作者感受:作者认为“polishing”这个词很适合描述他对这个程序的修改,与其他编程任务相比,他可以专注于代码的一小部分进行无意义的重写,尝试一些想法,从手册和标准中获取灵感,虽然不是每个人都觉得这是有趣的周末活动,但对他来说有一定意义。
  • 更新与备注:在 Hacker News 上有人指出可用strace复制其功能;不同操作系统对LD_PRELOAD的文件格式要求不同;GCC 接受$但 ISO C 不要求;大多数编译器的--version标志更详细,可用于COMPILER宏定义。
阅读 4
0 条评论