深度探秘assert---(已放弃,核心已转储)

深度探秘assert---(已放弃,核心已转储)

前言

前边一直再看内核的slab缓存,真是累如狗,但是它的体系是在是太复杂了,看来需要进一步总结,在这个过程中经常看到assert 断言这个东西,所以今天轻松一下,看看这个的底层实现。

__start

我使用的是glibc-2.18 还是挺新的,首先看一个例子,如果之前接触过C 的同学应该知道assert 名叫“断言”就是判断一个表达式的真伪。若果是错的就报出错误信息,中断程序。如果是真的就继续执行。

[c]

#include<stdio.h>
#include<assert.h>

int main(){
int a = 0;
assert(a != 0);
printf("hello world\n");
}

[/c]

程序很简单,看结果。

2015-11-16 16:13:53 的屏幕截图

果然,“已放弃,(核心已转储)”。

所以今天就来看看assert 如何实现 “已放弃(核心已转储)” 。

 

[c]

#ifdef NDEBUG     /*一个控制BUG 开关的宏*/

#define assert(expr) (__ASSERT_VOID_CAST (0))     /*如果关闭了强制转换成 “0”,这个宏的使用就是一个强转为0*/

[/c]

[c]

# define assert(expr) \                                  /*判断表达式的真假*/
((expr) \
? __ASSERT_VOID_CAST (0) \
: __assert_fail (__STRING(expr), __FILE__, __LINE__, __ASSERT_FUNCTION))

/*重点在这里如果在这里判断条件为假,就失败然后调转__assert_fail 函数,这里是一个函数实现*/

[/c]

__assert_fail  函数

[c]

void
__assert_fail (const char *assertion, const char *file, unsigned int line,const char *function)
{
__assert_fail_base (_("%s%s%s:%u: %s%sAssertion `%s' failed.\n%n"),assertion, file, line, function);

/*将assertion 修改成格式化的状态*/
}
hidden_def(__assert_fail)

[/c]

__assert_fail_base( ) 函数

[c]

参数说明   @fmt  :格式化

@assertion :错误信息

@file : 文件名

@line : 错误行数

@function :错误函数

void
__assert_fail_base (const char *fmt, const char *assertion, const char *file,unsigned int line, const char *function)
{
char *str;

int total;
if (__asprintf (&str, fmt,__progname, __progname[0] ? ": " : "",file, line,function ? function : "", function ? ": " : "",
assertion, &total) >= 0)   /*错误信息存在,且格式化存储*/
{
/* Print the message. */
(void) __fxprintf (NULL, "%s", str);   /*输出错误信息*/
(void) fflush (stderr);

total = (total + 1 + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1);  /*对齐错误输出长度*/
struct abort_msg_s *buf = __mmap (NULL, total, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);  /*申请一片空间来存储错误信息*/
if (__builtin_expect (buf != MAP_FAILED, 1))   /*空间申请成功*/
{
buf->size = total;      /*得到错误信息长度*/
strcpy (buf->msg, str);    /*拷贝错误信息进缓冲区*/

/* We have to free the old buffer since the application might catch the SIGABRT signal. */
struct abort_msg_s *old = atomic_exchange_acq (&__abort_msg, buf);

/*应用程序有可能没有收到SIGABRT 信号,所以我们以必须识放空间。

SIGABRT是中止一个程序,它可以被捕捉,但不能被阻塞。处理函数返回后,所有打开的文件描述符将会被关闭,流也会被flush。程序会结束,有可能的话还会core dump。 当程序调用abort(3)时,该进程会向自己发送SIGABRT信号。所以,SIGABRT一般用于信号中一些关键的处理,assert失败时也会使用它。你不应该去捕捉SIGSEGV和SIGABRT信号,如果收到这种信号,说明进程处于一个不确定的状态,很可能会直接挂起。      */

if (old != NULL)
__munmap (old, old->size);
}

free (str);

}else{
/* At least print a minimal message. */

/*输出最小规模的错误信息*/
static const char errstr[] = "Unexpected error.\n";
__libc_write (STDERR_FILENO, errstr, sizeof (errstr) - 1);
}

abort (); /*thread结束*/
}

[/c]

查看原文:http://zmrlinux.com/2015/11/16/%e6%b7%b1%e5%ba%a6%e6%8e%a2%e7%a7%98assert-%e5%b7%b2%e6%94%be%e5%bc%83%ef%bc%8c%e6%a0%b8%e5%bf%83%e5%b7%b2%e8%bd%ac%e5%82%a8%ef%bc%89/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值