zoukankan      html  css  js  c++  java
  • AUPE 输出致标准错误的出错函数分析与实现 err_sys, err_quit, err_doit etc.

    1. 出错函数汇总

    AUPE 输出至标准错误的出错函数, 分为以下几个:

    函数名 何时调用 功能
    err_ret 系统调用相关的非致命错误 打印消息并且返回
    err_sys 系统调用相关的非致命错误 打印消息并且终止程序
    err_cont 不与系统调用相关的非致命错误 错误码通过显式参数error传递, 打印消息并返回
    err_exit 不与系统调用相关的致命错误 错误码通过显式参数error传递, 打印消息并返回
    err_dump 系统调用相关的致命错误 打印消息, 核心转储, 并且终止程序
    err_msg 不与系统调用相关的非致命错误 打印消息, 并且返回
    err_quit 不与系统调用相关的致命错误 打印消息, 并且终止程序

    2. 简要分析

    1. 详细错误开关
      通过一个标志errnorflag, 控制错误详细信息的打印.

    2. 错误号
      如果要打印除传入错误信息外, 更加详细错误信息:
      除了要打开errnorflag, 另外,
      ① 对于系统调用相关错误, 可以不用调用者传递错误号(参数error), 可直接利用全局变量errno, 检查对象要求调用出错时会设置errno;
      ② 对于非系统调用相关错误, 如果要打印错误号对应的详细信息, 就需要调用者传递错误号. 常见多线程环境, 或者其他不会设置errno, 但会返回错误号的调用, i.g. pthread_create;

    3. 是否终止程序
      只有致命错误, 不论系统调用, 还是非系统调用, 才会终止程序. 非必要情况, 不用终止程序. 终止程序用exit().

    4. 核心转储(core dump)
      调用abort异常终止当前进程, 触发核心转储. 输出core文件的前提是, Core file size > 0, 可以用ulimit -c命令设置, ulimit -a命令查看, 单位如下图.

    $ ulimit -a
    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 30702
    max locked memory       (kbytes, -l) 65536
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 1024
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 8192
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 30702
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited
    
    $ ulimit -c
    0
    $ ulimit -c 1024
    $ ulimit -c
    1024
    
    1. 可变参数及如何实现打印
      对于可变参数"...", 可以将其转换为va_list, 然后利用vsnprintf, 将要打印的内容写至缓冲区中. 最后将打印内容输出到stderr.

    3. 实现源码

    先来看公共的, 可变参数、错误号及提示信息打印函数err_doit
    errnoflag : 打印错误详细信息开关;
    error: 错误号, 通过strerror将其转化为字符串;
    fmt: 格式化字符串, 可由用户传入, 包含了用户错误提示信息;
    ap: 可变参数列表, 由用户跟fmt一起传入;

    err_doit的主要任务是:

    1. 根据参数设置, 先将用户设置错误提示信息fmt & 参数列表ap转存到缓冲区buf中;
    2. 判断是否要打印错误号error对应的错误消息, 如果要打印, 就用strerror将error转化成字符串信息, 并追加填入缓冲区;
    3. 缓冲区字符串末尾追加 , 因为调用库IO函数时, 会自动冲刷库缓存;
    4. 冲刷IO库缓存, 然后将缓冲区字符串, 通过fputs输出至IO库缓存, 这样就打印了错误信息;
    /**
     * 打印消息, 并且返回调用者
     * 调用者指定参数errnoflag
     * @param errnoflag 错误标识, 值非0时, 才打印错误号转化成的错误详细信息. 值为0时, 不打印错误号对应错误详细信息.
     * @param error 错误号. 系统调用相关错误, 不用传错误号, 直接用errno作为错误号; 非系统调用错误(不设置errno的), 手动传入错误号
     * @param fmt 格式化字符串
     * @param ap 变参列表, fmt中有多少个转义字符, ap就需要提供同样个数参数值
     */
    static void err_doit(int errnoflag, int error, const char *fmt, va_list ap)
    {
    	int		errno_save;
    	char	buf[MAXLINE];
    
    	errno_save = error;		/* value caller might want printed */
    	vsprintf(buf, fmt, ap); /* format string fmt write out to buf */
    	if (errnoflag)
    		sprintf(buf+strlen(buf), ": %s", strerror(errno_save)); /* append strerror(error) to buf */
    	strcat(buf, "
    "); /* append "
    " to buf */
    	fflush(stdout);		/* in case stdout and stderr are the same */
    	fputs(buf, stderr); /* write out buf to stderr */
    	fflush(stderr);		/* SunOS 4.1.* doesn't grok NULL argument */
    }
    

    出错函数的用户接口实现:
    主要需要注意区分 是否为系统调用相关, 是否需要用户输入错误号, 是否打印详细错误信息, 是否终止进程, 是否需要core file

    #include <errno.h>		/* for definition of errno */
    #include <stdarg.h>		/* ANSI C header file */
    #include <stdlib.h>
    
    #include "ourhdr.h"
    
    static void	err_doit(int, int, const char *, va_list);
    
    /*
     * 系统调用相关的非致命错误
     * 打印消息并且返回
     */
    void err_ret(const char *fmt, ...)
    {
    	va_list		ap;
    
    	va_start(ap, fmt);
    	err_doit(1, errno, fmt, ap);
    	va_end(ap);
    	return;
    }
    
    /*
     * 系统调用相关的非致命错误
     * 打印消息并且终止程序
     */
    void err_sys(const char *fmt, ...)
    {
    	va_list		ap;
    
    	va_start(ap, fmt);
    	err_doit(1, errno, fmt, ap);
    	va_end(ap);
    	exit(1);
    }
    
    /**
     * 不与系统调用相关的非致命错误
     * 错误码通过显式参数error传递
     * 打印消息并返回
     */
    void err_cont(int error, const char *fmt, ...)
    {
        va_list ap;
    
        va_start(ap, fmt);
        err_doit(1, error, fmt, ap);
        va_end(ap);
    }
    
    /**
     * 不与系统调用相关的致命错误
     * 错误码通过显式参数error传递
     * 打印消息并终止程序
     */
    void err_exit(int error, const char *fmt, ...)
    {
        va_list ap;
    
        va_start(ap, fmt);
        err_doit(1, error, fmt, ap);
        va_end(ap);
        exit(1);
    }
    
    /*
     * 系统调用相关的致命错误
     * 打印消息, 核心转储, 并且终止程序
     */
    void err_dump(const char *fmt, ...)
    {
    	va_list		ap;
    
    	va_start(ap, fmt);
    	err_doit(1, errno, fmt, ap);
    	va_end(ap);
    	abort();		    /* dump core and terminate */
    	exit(1);		/* shouldn't get here */
    }
    
    /*
     * 不与系统调用相关的非致命错误
     * 打印消息, 并且返回
     */
    void err_msg(const char *fmt, ...)
    {
    	va_list		ap;
    
    	va_start(ap, fmt);
    	err_doit(0, 0, fmt, ap);
    	va_end(ap);
    }
    
    /*
     * 不与系统调用相关的致命错误
     * 打印消息, 并且终止程序
     */
    void err_quit(const char *fmt, ...)
    {
    	va_list		ap;
    
    	va_start(ap, fmt);
    	err_doit(0, 0, fmt, ap);
    	va_end(ap);
    	exit(1);
    }
    
  • 相关阅读:
    Win10创意者更新秋季版激活秘籍
    将刷了Android的Lumia恢复为WP系统
    给Lumia 520/521/525/526/720刷Android系统
    DNS解析
    遍历对象目录
    PE注入
    利用NtCreateThreadEx注入
    利用CreateRemoteThread注入
    APC注入
    SetWindowHookEx()注入
  • 原文地址:https://www.cnblogs.com/fortunely/p/14875690.html
Copyright © 2011-2022 走看看