You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自制ls -l工具触发段错误,请求问题排查

自定义ls -l段错误排查与修复

核心问题与修复点

  • 未初始化的stat结构体引发非法访问
    函数开头声明的struct stat stat完全未初始化,直接用它的st_uid调用getpwuid,得到的pw和grp大概率是NULL,后续访问grp->gr_name直接触发段错误。而且每个文件的属性需要单独通过stat系统调用获取,不能复用垃圾值结构体。

  • 未校验opendir返回值
    如果当前目录打开失败(比如权限不足),opendir会返回NULL,后续readdir(NULL)直接崩溃,必须先检查dir是否有效。

  • 缺少每个文件的stat调用
    循环里直接用未初始化的stat数据,根本没获取当前文件的实际属性,所有属性值都是内存垃圾,访问这些值必然导致未定义行为。必须在循环内对每个entry->d_name调用stat获取属性。

  • printf格式符类型不匹配
    stat.st_nlink和stat.st_size是整数,却用%s输出——这会把整数当作字符串指针解析,访问非法内存地址触发段错误,要用%d/%ld输出整数。

  • 错误访问dirent的无效成员
    entry->d_name_name是不存在的字段,你应该是想输出文件所有者的用户名,也就是pw->pw_name。

  • 用户/组信息调用时机错误
    getpwuid和getgrgid要在获取到当前文件的有效stat数据之后调用,不能一开始就用垃圾值调用。

修复后的完整代码

#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <string.h>

// 假设你已经实现了这两个自定义函数
void mini_printf(const char *fmt, ...);
void my_putchar(char c);

void get_time(char *str)
{
    if (!str) return;
    // ctime返回格式为"Wed Jun 30 21:49:08 1993\n",截取到第16位截断
    if (strlen(str) >= 16) {
        str[16] = '\0';
        str += 4;
        mini_printf("%s", str);
    }
}

void get_permission(const struct stat *stat_buf)
{
    if (!stat_buf) return;

    my_putchar((S_ISDIR(stat_buf->st_mode)) ? 'd' :
             (S_ISBLK(stat_buf->st_mode) ? 'b' :
             (S_ISCHR(stat_buf->st_mode) ? 'c' : '-')));
    my_putchar((stat_buf->st_mode & S_IRUSR) ? 'r' : '-');
    my_putchar((stat_buf->st_mode & S_IWUSR) ? 'w' : '-');
    my_putchar((stat_buf->st_mode & S_IXUSR) ? 'x' : '-');
    my_putchar((stat_buf->st_mode & S_IRGRP) ? 'r' : '-');
    my_putchar((stat_buf->st_mode & S_IWGRP) ? 'w' : '-');
    my_putchar((stat_buf->st_mode & S_IXGRP) ? 'x' : '-');
    my_putchar((stat_buf->st_mode & S_IROTH) ? 'r' : '-');
    my_putchar((stat_buf->st_mode & S_IWOTH) ? 'w' : '-');
    my_putchar((stat_buf->st_mode & S_IXOTH) ? 'x' :
    (stat_buf->st_mode & S_ISVTX) ? 'T' : '-');
}

int my_ls_l(void)
{
    struct dirent *entry;
    DIR *dir;
    struct stat stat_buf;
    struct passwd *pw;
    struct group *grp;

    dir = opendir("./");
    if (!dir) {
        mini_printf("opendir failed\n");
        return -1;
    }

    while ((entry = readdir(dir)) != NULL) {
        // 跳过隐藏文件
        if (entry->d_name[0] == '.') {
            continue;
        }

        // 获取当前文件的属性信息
        if (stat(entry->d_name, &stat_buf) == -1) {
            mini_printf("stat failed for %s\n", entry->d_name);
            continue;
        }

        // 获取用户和组信息
        pw = getpwuid(stat_buf.st_uid);
        grp = getgrgid(stat_buf.st_gid);

        // 输出权限位
        get_permission(&stat_buf);
        mini_printf(" ");

        // 输出链接数
        mini_printf("%d ", stat_buf.st_nlink);

        // 输出用户名(如果获取失败则输出UID)
        if (pw) {
            mini_printf("%s ", pw->pw_name);
        } else {
            mini_printf("%d ", stat_buf.st_uid);
        }

        // 输出组名(如果获取失败则输出GID)
        if (grp) {
            mini_printf("%s ", grp->gr_name);
        } else {
            mini_printf("%d ", stat_buf.st_gid);
        }

        // 输出文件大小
        mini_printf("%ld ", (long)stat_buf.st_size);

        // 输出修改时间
        get_time(ctime(&stat_buf.st_mtime));
        mini_printf(" ");

        // 输出文件名
        mini_printf("%s\n", entry->d_name);
    }

    closedir(dir);
    return 0;
}

int main(void) {
    my_ls_l();
    return 0;
}

内容的提问来源于stack exchange,提问作者owen.H

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 11:31:14