LIST_POISON1和LIST_POISON2

已查看 33 次
跳至第一个未读帖子

Niu Tao

未读,
2008年7月23日 02:54:522008/7/23
收件人 xiyouLinux、Linux论坛、陈老师、helight. xu、李昊
在linux内核中,/linux/include/linux/list.h
21struct list_head {
22 struct list_head *next, *prev;
23};
list_head被用做建立双向循环链表,其中对它的一个操作是删除一个节点:
155static inline void __list_del(struct list_head * prev, struct
list_head * next)
156{
157 next->prev = prev;
158 prev->next = next;
159}

168static inline void list_del(struct list_head *entry)
169{
170 __list_del(entry->prev, entry->next);
171 entry->next = LIST_POISON1;
172 entry->prev = LIST_POISON2;
173}
list_del是删除entry所在的链表的entry节点,在171和172行将
entry->next=LIST_POISON1;
entry->prev=LIST_POISON2;
而LIST_POISON1和LIST_POISON2都被定义在:/linux/include/linux/poison.h中:
10#define LIST_POISON1 ((void *) 0x00100100)
11#define LIST_POISON2 ((void *) 0x00200200)
我的问题是:
1、一般我们在操作双向链表时,删除一个节点的操作是将该节点从链表中删除,之后
要么直接释放该节点,要么将其返回,而此处没有释放也 没有返回,而是赋予了
LIST_POISON1 和LIST_POISON12这两个值,是何用意?
2、这两个位置是什么内容?有什么特殊?将entry->next和entry->prev分别指向这两个
位置,那可不可以指向其他无效的位置?
3、这两个位置是人为规定的?并且对于所有访问它的程序都给予确定的回应(就像访问
0x00000000就会出现断错误这样的回应)?


--
My Bolg: http://niutao.cublog.cn

Niu Tao

未读,
2008年7月23日 03:04:582008/7/23
收件人 xiyouLinux、Linux论坛、陈老师、helight. xu、李昊
2008/7/23 Niu Tao <niuta...@gmail.com>:
还有对于它的初始化:
25#define LIST_HEAD_INIT(name) { &(name), &(name) }

30static inline void INIT_LIST_HEAD(struct list_head *list)
31{
32 list->next = list;
33 list->prev = list;
34}
有什么区别?

SIE

未读,
2008年7月23日 03:26:112008/7/23
收件人 linuxe...@googlegroups.com、xiyouLinux、陈老师、helight. xu、李昊


2008/7/23 Niu Tao <niuta...@gmail.com>:

在linux内核中,/linux/include/linux/list.h
 21struct list_head {
 22        struct list_head *next, *prev;
 23};
list_head被用做建立双向循环链表,其中对它的一个操作是删除一个节点:
 155static inline void __list_del(struct list_head * prev, struct
list_head * next)
 156{
 157        next->prev = prev;
 158        prev->next = next;
 159}

 168static inline void list_del(struct list_head *entry)
 169{
 170        __list_del(entry->prev, entry->next);
 171        entry->next = LIST_POISON1;
 172        entry->prev = LIST_POISON2;
 173}
list_del是删除entry所在的链表的entry节点,在171和172行将
entry->next=LIST_POISON1;
entry->prev=LIST_POISON2;
而LIST_POISON1和LIST_POISON2都被定义在:/linux/include/linux/poison.h中:
 10#define LIST_POISON1  ((void *) 0x00100100)
 11#define LIST_POISON2  ((void *) 0x00200200)

访问这两个位置会引起页错误,详细也不清楚

 

我的问题是:
1、一般我们在操作双向链表时,删除一个节点的操作是将该节点从链表中删除,之后
要么直接释放该节点,要么将其返回,而此处没有释放也 没有返回,而是赋予了
LIST_POISON1 和LIST_POISON12这两个值,是何用意?
2、这两个位置是什么内容?有什么特殊?将entry->next和entry->prev分别指向这两个
位置,那可不可以指向其他无效的位置?
3、这两个位置是人为规定的?并且对于所有访问它的程序都给予确定的回应(就像访问
0x00000000就会出现断错误这样的回应)?


--
My Bolg: http://niutao.cublog.cn





--
#apt-get install wife
The following extra packages will be installed:
wife-house wife-car wife-friends wife-dog wife-mother_in_law wife-kid wife-no_more_tv_sports wife-kidlibs wife-bricomanialibs
The following packages will be upgraded:ego-restrainer freedom-throttler
Estimated installation time: 47 years
Do you want to continue [Y/n]?

WANG Cong

未读,
2008年7月23日 04:39:472008/7/23
收件人 Niu Tao、xiyou...@googlegroups.com、helig...@gmail.com

/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized list entries.
*/

--
The opposite of love is not hate, but indifference.
--Elie Wiesel

Niu Tao

未读,
2008年7月23日 04:52:082008/7/23
收件人 WANG Cong、xiyou...@googlegroups.com、helig...@gmail.com
2008/7/23 WANG Cong <xiyou.w...@gmail.com>:
你给的我看过,是在/linux/include/linux/poison.h对LIST_POISON1和LIST_POISON2的简单解释,
但也给的是访问这两个位置的结果会怎样,而我的问题是为什么会是解释说的访问会导致断错误,它
的实现?

cliff

未读,
2008年7月23日 04:57:142008/7/23
收件人 西邮Linux兴趣小组


>
> 还有对于它的初始化:
> 25#define LIST_HEAD_INIT(name) { &(name), &(name) }
> 和
> 30static inline void INIT_LIST_HEAD(struct list_head *list)
> 31{
> 32 list->next = list;
> 33 list->prev = list;
> 34}
> 有什么区别?
>

看了一下调用,第一个宏都是在下面类似的情况使用
*lp = ((struct iss_net_private) {
.device_list = LIST_HEAD_INIT(lp->device_list),
.opened_list = LIST_HEAD_INIT(lp->opened_list),
.lock = SPIN_LOCK_UNLOCKED,
.dev = dev,
.index = index,
//.fd = -1,
.mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 },
.have_mac = 0,
});
而实际上初始化list-head的代码是第二个。

cliff

未读,
2008年7月23日 05:07:032008/7/23
收件人 西邮Linux兴趣小组

>
> 你给的我看过,是在/linux/include/linux/poison.h对LIST_POISON1和LIST_POISON2的简单解释,
> 但也给的是访问这两个位置的结果会怎样,而我的问题是为什么会是解释说的访问会导致断错误,它
> 的实现?
>
访问不可访问的地址当然就是断错误了,还用什么实现么?
他的地址应该在代码段

Niu Tao

未读,
2008年7月23日 05:10:212008/7/23
收件人 cliff、西邮Linux兴趣小组
2008/7/23 cliff <zpmai...@gmail.com>:
有的解释说INIT_LIST_HEAD是在运行时初始化。那对应的是不是还有编译时初始化
这样的概念?

Niu Tao

未读,
2008年7月23日 05:12:312008/7/23
收件人 cliff、西邮Linux兴趣小组
2008/7/23 cliff <zpmai...@gmail.com>:

>
>>
>> 你给的我看过,是在/linux/include/linux/poison.h对LIST_POISON1和LIST_POISON2的简单解释,
>> 但也给的是访问这两个位置的结果会怎样,而我的问题是为什么会是解释说的访问会导致断错误,它
不好意思,刚才是打错了,把"会导致断错误"改为"会导致页错误"。
>> 的实现?
>>
> 访问不可访问的地址当然就是断错误了,还用什么实现么?
> 他的地址应该在代码段

WANG Cong

未读,
2008年7月23日 05:16:362008/7/23
收件人 Niu Tao、xiyou...@googlegroups.com、helig...@gmail.com

内核的虚拟内存是从PAGE_OFFSET开始的,所以那两个地址显然不在这个
范围内。所以会产生段错误吧。

WANG Cong

未读,
2008年7月23日 05:18:452008/7/23
收件人 Niu Tao、cliff、Xi You Linux Group

显然。上面不就是个好例子么?

helight.xu

未读,
2008年7月23日 07:34:032008/7/23
收件人 WANG Cong、Niu Tao、xiyou...@googlegroups.com
关于这个地址的处理内核处理的很简单,要么打印日志信息报错,要么直接不处理.
我的linux下的source insight不能用了,这是我用cacope查出来的一个对此种地址
作处理的函数..
690 net/rxrpc/af_rxrpc.c <<rxrpc_release_sock>>
ASSERTCMP(rx->listen_link.next, !=, LIST_POISON1);
这是一种:
#define ASSERTCMP(X, OP, Y) \
do { \
if (unlikely(!((X) OP (Y)))) { \
printk(KERN_ERR "\n"); \
printk(KERN_ERR "RxRPC: Assertion failed\n"); \
printk(KERN_ERR "%lu " #OP " %lu is false\n", \
(unsigned long)(X), (unsigned long)(Y)); \
printk(KERN_ERR "0x%lx " #OP " 0x%lx is false\n", \
(unsigned long)(X), (unsigned long)(Y)); \
BUG(); \
} \
} while(0)
另外一种:
#define ASSERTCMP(X, OP, Y) \
do { \
} while(0)


>
>

Niu Tao

未读,
2008年7月23日 08:51:142008/7/23
收件人 helight.xu、WANG Cong、xiyou...@googlegroups.com
2008/7/23 helight.xu <helig...@gmail.com>:
这才是我想要的答案,谢谢学长。

WANG Cong

未读,
2008年7月23日 11:53:112008/7/23
收件人 helight.xu、Niu Tao、xiyou...@googlegroups.com

你不需要source insight那种工具,你只要grep就足够了。

而且,你也知道,遇到函数指针时cscope是无法跟踪的,这时你只能用grep。
(source insight是window$的工具,我从来不用,不过我猜它也很难跟踪到)


> 作处理的函数..
> 690 net/rxrpc/af_rxrpc.c <<rxrpc_release_sock>>
> ASSERTCMP(rx->listen_link.next, !=, LIST_POISON1);


很明显这是在net/rxrpc下。照你这样说,如果每个使用list的都这么处理的话,
那么这种宏应该在一个高层的目录中,比如最理想的include/linux,而不会出现
在net/rxrpc这种底层的子目录中。


> 这是一种:
> #define ASSERTCMP(X, OP, Y) \
> do { \
> if (unlikely(!((X) OP (Y)))) { \
> printk(KERN_ERR "\n"); \
> printk(KERN_ERR "RxRPC: Assertion failed\n"); \
> printk(KERN_ERR "%lu " #OP " %lu is false\n", \
> (unsigned long)(X), (unsigned long)(Y)); \
> printk(KERN_ERR "0x%lx " #OP " 0x%lx is false\n", \
> (unsigned long)(X), (unsigned long)(Y)); \
> BUG(); \
> } \
> } while(0)
> 另外一种:
> #define ASSERTCMP(X, OP, Y) \
> do { \
> } while(0)


Are you sure?

你注意到#ifdef 1了么?

P.S.
如果你的逻辑正确,我至少应该能在kernel/,arch/x86,mm/等地方找到这种宏,
很不幸,我grep不到。

WANG Cong

未读,
2008年7月23日 12:01:422008/7/23
收件人 Niu Tao、helight.xu、xiyou...@googlegroups.com
On Wed, Jul 23, 2008 at 08:51:14PM +0800, Niu Tao wrote:

<snip>

>> 关于这个地址的处理内核处理的很简单,要么打印日志信息报错,要么直接不处理. 我的linux下的source
>> insight不能用了,这是我用cacope查出来的一个对此种地址 作处理的函数..
>> 690 net/rxrpc/af_rxrpc.c <<rxrpc_release_sock>>
>> ASSERTCMP(rx->listen_link.next, !=, LIST_POISON1);
>> 这是一种:
>> #define ASSERTCMP(X, OP, Y) \
>> do { \
>> if (unlikely(!((X) OP (Y)))) { \
>> printk(KERN_ERR "\n"); \
>> printk(KERN_ERR "RxRPC: Assertion failed\n"); \
>> printk(KERN_ERR "%lu " #OP " %lu is false\n", \
>> (unsigned long)(X), (unsigned long)(Y)); \
>> printk(KERN_ERR "0x%lx " #OP " 0x%lx is false\n", \
>> (unsigned long)(X), (unsigned long)(Y)); \
>> BUG(); \
>> } \
>> } while(0)
>> 另外一种:
>> #define ASSERTCMP(X, OP, Y) \
>> do { \
>> } while(0)
>>
>这才是我想要的答案,谢谢学长。

为什么这么容易盲从别人呢??你稍微grep一下LIST_POISION1你就会发现:

./include/linux/poison.h:10:#define LIST_POISON1 ((void *) 0x00100100)
./include/linux/list.h:110: entry->next = LIST_POISON1;
./include/linux/list.h:514: n->next = LIST_POISON1;
./Documentation/scsi/ChangeLog.lpfc:516: removed (100100 is a
LIST_POISON1 value from the next pointer
./lib/list_debug.c:75: entry->next = LIST_POISON1;
./net/rxrpc/af_rxrpc.c:690: ASSERTCMP(rx->listen_link.next, !=,
LIST_POISON1);

如果他说的是对的,怎么可能只有net/rxrpc中那样使用??应该有很多使用
list地方都用到才对!所以那只是个例。

记住,不要轻易相信别人的观点,包括我的!

helight.xu

未读,
2008年7月23日 21:37:392008/7/23
收件人 WANG Cong、Niu Tao、xiyou...@googlegroups.com
WANG Cong wrote:
> On Wed, Jul 23, 2008 at 07:34:03PM +0800, helight.xu wrote:
>
>> WANG Cong wrote:
>>
>>> On Wed, Jul 23, 2008 at 04:52:08PM +0800, Niu Tao wrote:
>>>
>>>
>>>> 2008/7/23 WANG Cong <xiyou.w...@gmail.com>:
>>>>
>>>>
>>>>> On Wed, Jul 23, 2008 at 02:54:52PM +0800, Niu Tao wrote:
>>>>>
>>>>>
>>>>>> 在linux内核中,/linux/include/linux/list.h
>>>>>> 21struct list_head {
>>>>>> 22 struct list_head *next, *prev;
>>>>>> 23};
>>>>>> list_head被用做建立双向循环链表,其中对它的一个操作是删除一个节点:
>>>>>>
>
<snip>
很明显只有在内核debug时才会打印信息,.其余时候应该是什么都不做,
我是在以下文件中找到这中宏的.至于这个宏在LIST_POISON上的应用我
只在这一个文件中找到:

690 net/rxrpc/af_rxrpc.c <<rxrpc_release_sock>>
ASSERTCMP(rx->listen_link.next, !=, LIST_POISON1);

宏的定义文件:
1 813 fs/afs/internal.h <<ASSERTCMP>>
#define ASSERTCMP(X, OP, Y) \
2 869 fs/afs/internal.h <<ASSERTCMP>>
#define ASSERTCMP(X, OP, Y) \
3 695 net/rxrpc/ar-internal.h <<ASSERTCMP>>
#define ASSERTCMP(X, OP, Y) \
4 736 net/rxrpc/ar-internal.h <<ASSERTCMP>>
#define ASSERTCMP(X, OP, Y) \
在内核中确实我现在还没有找到其它有关这个LIST_POISON处理的函数.

SIE

未读,
2008年7月23日 22:02:172008/7/23
收件人 helight.xu、WANG Cong、Niu Tao、xiyou...@googlegroups.com


2008/7/23 helight.xu <helig...@gmail.com>:

我觉得这个只是对指针值是不是POSITION1进行了断言,但是还是没有回答,如果访问了POSITION1会出现什么情况。因为断言如果失败的话,就不访问了。这个原因可能得深入到体系结构?

 

>



helight.xu

未读,
2008年7月23日 23:06:002008/7/23
收件人 SIE、WANG Cong、Niu Tao、xiyou...@googlegroups.com

如果访问了POSITION1会出现什么情况?
这里不是已经回答了么?

SIE

未读,
2008年7月23日 23:11:042008/7/23
收件人 helight.xu、WANG Cong、Niu Tao、xiyou...@googlegroups.com


2008/7/24 helight.xu <helig...@gmail.com>:

这里只是一个位置的操作,它为了判断指针是否有效,而进行了ASSERT的判断。
并不是在所有的指针访问操作都会进行一次ASSERT的,我也不认为编译器和内核会自动为我们做这件事。
如果我在内核某个地方写了个代码,让指针p=POSITION1,
然后直接*p,
我并不进行ASSERTCMP的操作,那这个操作会是怎么进行的呢?

 


/*
 * These are non-NULL pointers that will result in page faults
 * under normal circumstances, used to verify that nobody uses
 * non-initialized list entries.
 */

>
>
>
>> >>
>>
>>
>
>
>

helight.xu

未读,
2008年7月23日 23:49:122008/7/23
收件人 SIE、WANG Cong、Niu Tao、xiyou...@googlegroups.com
这应该和处理NULL的结果一样,但不知操作系统是怎么处理的.

Niu Tao

未读,
2008年7月23日 23:55:322008/7/23
收件人 SIE、helight. xu、WANG Cong、xiyou...@googlegroups.com
2008/7/24 SIE <kensou....@gmail.com>:
我些了一个模块测试:
char *p;
p=LIST_POISON1;
printk("*p=%s\n",p);
结果插入时在终端下显示段错误,dmesg查看:
[ 480.538450] BUG: unable to handle kernel paging request at virtual
address 00100100
[ 480.538454] printing eip: c02159f6 *pde = 00000000
[ 480.538458] Oops: 0000 [#1] SMP
[ 480.538461] Modules linked in: hello binfmt_misc rfcomm l2cap
bluetooth ppdev vboxdrv container sbs sbshc video output dock
cpufreq_ondemand cpufreq_stats cpufreq_conservative cpufreq_userspace
freq_table cpufreq_powersave battery af_packet ppp_generic slhc
iptable_filter ip_tables x_tables vfat fat ac lp parport_pc parport
nvidia(P) pcspkr agpgart evdev k8temp shpchp pci_hotplug snd_hda_intel
snd_pcm_oss snd_mixer_oss snd_pcm snd_page_alloc snd_hwdep snd_seq_oss
snd_seq_midi_event snd_seq snd_timer snd_seq_device snd soundcore
button i2c_nforce2 i2c_core ext3 jbd mbcache sg sd_mod sr_mod cdrom
ata_generic sata_nv usbhid hid floppy pata_acpi pata_amd forcedeth
ehci_hcd ohci_hcd libata scsi_mod usbcore thermal processor fan fbcon
tileblit font bitblit softcursor fuse
[ 480.538505]
[ 480.538508] Pid: 6696, comm: insmod Tainted: P (2.6.24-16-generic #1)
[ 480.538511] EIP: 0060:[<c02159f6>] EFLAGS: 00210097 CPU: 0
[ 480.538518] EIP is at strnlen+0x6/0x20
[ 480.538520] EAX: 00100100 EBX: c0487923 ECX: 00100100 EDX: fffffffe
[ 480.538523] ESI: 00100100 EDI: 00000000 EBP: ffffffff ESP: df9fbddc
[ 480.538526] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
[ 480.538529] Process insmod (pid: 6696, ti=df9fa000 task=c7023680
task.ti=df9fa000)
[ 480.538531] Stack: c0214f99 c0140b84 00000000 f76c7f38 c012188b
00000000 00000001 00000400
[ 480.538537] c0487920 00000000 c0487d20 00100100 ffffffff
ffffffff f8bec09f 00000400
[ 480.538543] f8bec480 00000009 00000000 c0215214 df9fbebc
f8bec480 c012cb3c df9fbeb8
[ 480.538548] Call Trace:
[ 480.538550] [<c0214f99>] vsnprintf+0x459/0x610
[ 480.538555] [<c0140b84>] autoremove_wake_function+0x14/0x40
[ 480.538563] [<c012188b>] __wake_up_common+0x4b/0x80
[ 480.538577] [<c0215214>] vscnprintf+0x14/0x20
[ 480.538583] [<c012cb3c>] vprintk+0x5c/0x380
[ 480.538597] [<c0128003>] __cond_resched+0x13/0x40
[ 480.538601] [<c0315fc7>] cond_resched+0x27/0x30
[ 480.538605] [<c0315fec>] wait_for_common+0x1c/0x130
[ 480.538611] [<c014f0e0>] __link_module+0x0/0x20
[ 480.538620] [<c012ce7b>] printk+0x1b/0x20
[ 480.538625] [<f8bec043>] hello_init+0x23/0x2c [hello]
[ 480.538631] [<c01506b6>] sys_init_module+0x126/0x19c0
[ 480.538661] [<c020fa47>] _atomic_dec_and_lock+0x47/0x70
[ 480.538672] [<c012ce60>] printk+0x0/0x20
[ 480.538685] [<c01043c2>] sysenter_past_esp+0x6b/0xa9
[ 480.538701] =======================
[ 480.538702] Code: 90 8d 74 26 00 85 c9 57 89 c7 89 d0 74 05 f2 ae
75 01 4f 89 f8 5f c3 8d b4 26 00 00 00 00 8d bc 27 00 00 00 00 89 c1
89 c8 eb 06 <80> 38 00 74 07 40 4a 83 fa ff 75 f4 29 c8 c3 90 90 90 90
90 90
[ 480.538726] EIP: [<c02159f6>] strnlen+0x6/0x20 SS:ESP 0068:df9fbddc
[ 480.538732] ---[ end trace 8c608d4db5d8d61d ]---
我也不懂,你们看看到底是怎么回事?

WANG Cong

未读,
2008年7月24日 04:07:592008/7/24
收件人 helight.xu、Niu Tao、xiyou...@googlegroups.com


#ifdef 1告诉我,它永远都会打印信息。。。。


> 我是在以下文件中找到这中宏的.至于这个宏在LIST_POISON上的应用我
> 只在这一个文件中找到:
>
> 690 net/rxrpc/af_rxrpc.c <<rxrpc_release_sock>>
> ASSERTCMP(rx->listen_link.next, !=, LIST_POISON1);


我们这的话题是LIST_POISON,很明显我只在乎它,ASSERTCMP是什么是次要。

既然你只在一个net/rxrpc/文件中找到,那就是个例,并不是处理LIST_POISON
的通用方法,因此你的解释不恰当。

Over.

回复全部
回复作者
转发
0 个新帖子