SHH*_*SHH 5 c linux overflow linux-kernel
假设我们有以下代码:
if (timeout > jiffies)
{
/* we did not time out, good ... */
}
else
{
/* we timed out, error ...*
}
Run Code Online (Sandbox Code Playgroud)
当jiffies值不溢出时,此代码工作正常.但是,当jiffies溢出并回绕到零时,此代码无法正常工作.
Linux显然提供了用于处理此溢出问题的宏
#define time_before(unknown, known) ((long)(unkown) - (long)(known) < 0)
Run Code Online (Sandbox Code Playgroud)
当用这个宏替换时,上面的代码应该是安全的溢出:
// SAFE AGAINST OVERFLOW
if (time_before(jiffies, timeout)
{
/* we did not time out, good ... */
}
else
{
/* we timed out, error ...*
}
Run Code Online (Sandbox Code Playgroud)
但是,time_before(和其他时间_宏)背后的理由是什么?
time_before(jiffies,timeout)将扩展为
((long)(jiffies) - (long)(timeout) < 0)
Run Code Online (Sandbox Code Playgroud)
这段代码如何防止溢出问题?
我们实际上试一试:
#define time_before(unknown, known) ((long)(unkown) - (long)(known) < 0)
Run Code Online (Sandbox Code Playgroud)
我会通过说a long
只有两个字节来简化很多事情,所以在十六进制中它可以有一个范围内的值[0, 0xFFFF]
.
现在,它已经签名,因此范围[0,0xFFFF]可以分为两个独立的范围[0,0x7FFF],[0x8000,0xFFFF].那些对应于值[0,32767],[ - 32768,-1].这是一个图表:
[0x0 - - - 0xFFFF]
[0x0 0x7FFF][0x8000 0xFFFF]
[0 32,767][-32,768 -1]
Run Code Online (Sandbox Code Playgroud)
说timeout
是32,000.我们想检查一下我们是否在我们的超时时间内,但实际上我们已经溢出,所以jiffies
是-31,000.所以如果我们天真地试图评估jiffies < timeout
我们会得到的True
.但是,插入值:
time_before(jiffies, offset)
== ((long)(jiffies) - (long)(offset) < 0)
== (-31000 - 32000 < 0) // WTF is this. Clearly NOT -63000
== (-31000 - 1768 - 1 - 30231 < 0) // simply expanded 32000
== (-32768 - 1 - 30232 < 0) // this -1 causes an underflow
== (32767 - 30232 < 0)
== (2535 < 0)
== False
Run Code Online (Sandbox Code Playgroud)
jiffies
是4个字节,而不是2个字节,但同样的原则适用.这些帮助有用?
例如,请参见此处:http://fixunix.com/kernel/266713-%5Bpatch-1-4%5D-fs-autofs-use-time_before-time_before_eq-etc.html
针对某些固定小常量检查溢出的代码已转换为使用 time_before。为什么?
我只是总结与 time_after 等函数的定义相关的评论:
93 /*
94 * These inlines deal with timer wrapping correctly. You are
95 * strongly encouraged to use them
96 * 1. Because people otherwise forget
97 * 2. Because if the timer wrap changes in future you won't have to
98 * alter your driver code.
99 *
100 * time_after(a,b) returns true if the time a is after time b.
101 *
Run Code Online (Sandbox Code Playgroud)
所以,time_before
和time_after
是处理溢出的更好的努力。
您的测试用例更有可能是timeout < jiffles
(无溢出)而不是timeout > jiffles
(有溢出):
unsigned long jiffies = 2147483658;
unsigned long timeout = 10;
Run Code Online (Sandbox Code Playgroud)
如果您将超时更改为
unsigned long timeout = -2146483000;
Run Code Online (Sandbox Code Playgroud)
答案是什么?
或者您可以更改支票
printf("%d",time_before(jiffies,timeout));
Run Code Online (Sandbox Code Playgroud)
到
printf("%d",time_before(jiffies,old_jiffles+timeout));
Run Code Online (Sandbox Code Playgroud)
其中 old_jiffles 是定时器启动时保存的 jiffles 值。
所以,我认为 time_before 的用法可以是这样的:
old_jiffles=jiffles;
timeout=10; // or even 10*HZ for ten-seconds
do_a_long_work_or_wait();
//check is the timeout reached or not
if(time_before(jiffies,old_jiffles+timeout) ) {
do_another_long_work_or_wait();
} else {
printk("ERRROR: the timeout is reached; here is a problem");
panic();
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
7630 次 |
最近记录: |