cmdtable.c (pmon/cmds/)
0307 发现这个数组存放的是列表的首地址,重新调整了部分内容。
这个函数是填充CmdList这个数组的,这个数组中存放的是指针,确切的说是列表指针(指向了另一个数组列表,这个列表才是真正的命令)。
函数的实现是如何将不同的命令列表(头指针)存储到数组中。
const Cmd *CmdList[100];
void
cmdlist_expand(newcmdlist, atend)
const Cmd *newcmdlist;
int atend;
{
int i;
for(i = 0; i < 100; i++) {
if(CmdList[i] == 0) { //找到一个空位
CmdList[i] = newcmdlist;
return;
}
//列表已经存在,跳出循环
if (!strcmp(newcmdlist->name, CmdList[i]->name)) {
break;
}
}
if(atend) { //放在已有列表的后面
while(CmdList[i] && !strcmp(newcmdlist->name,CmdList[i]->name)) {
i++;
}
}
bcopy((void *)&CmdList[i], (void *)&CmdList[i+1], sizeof(Cmd *) *(99 - i)); //向后移动,空出CmdList[i]这个空间
CmdList[i] = newcmdlist; //填充CmdList[i]空间
}
1. for循环,0-99(最多只能存100条命令 个列表)
如果没有重名了的命令列表,而且能够在数组中找到一个空白位置,则填充到该数组的空白位置,然后函数返回(return被调用)。
如果出现了重名,for函数中那个if(cmp)语句,cmp的特点是如果相等则返回0,否则返回非0.加上!号,表示取反,那这个if的意思就很明显,出现重名(表示已经有这样一个命名的列表了)的时候,跳出for循环。
2. 从for循环退出,但是没有return的情况,有两种,一是遇到了重名的命令,二是满了100条for循环,i到了100。
首先看第一种情况。
那就要看if(atend)的情况,这个atend变量由参数传进来,我看了源码中一两条调用的方法,似乎都填了1,(注意,我只看了一两个!!!!)
看if的功能分析,atend(at end??)是要把新加入的命令放在重名命令列表的后面
当命令存在(CmdList[i]指针不为0),并且名称相同(cmp返回值为0,!0就是1)的时候,i会向后加加,就是会跳过相同的命令列表
如果atend为0,if则不会执行,此时i不会加加了,i就会指向同名的那个数组元素,之后的语句就会进行拷贝),即,新加入的同名(pmon)命令列表就会加到已有的前面。
3.如果没有重名,也满了100条命令的情况。
这里似乎就有危险了,i此时等于100,CmdList[i]已经是越界访问了。
越界之后,应该是不会执行这个if中的i++了;
那么i 应该是100.
4. bcopy 这就是个拷贝函数
空出CmdList[i] 这个位置。
第二个参数是目的地址,第一个参数是源地址,第三个参数是拷贝的字节数。
if里面判断了拷贝的方向,和覆盖拷贝的问题,还是可以学习一下。
当目的地址大于源地址,并且目的地址小于源地址加上字节数。这里表示有重叠。
正常的从前向后拷贝时,4,5两个元素就会被(1,2)覆盖掉,因为1,2先拷贝,就把4,5的值覆盖了,后拷贝4,5的时候,其实拷贝的是1,2.这就与原始值有差异,出了问题
有重叠的时候,从后面开始拷贝,两个指针都加上字节数(此时指针的位置都指向了末尾),表示指向了最后的位置。所以解决的办法就是先把5拷贝到后面去,接着拷贝4.然后依次拷贝。
void
bcopy(const char *src, char *dst, size_t bytes)
{
if (dst >= src && dst < src + bytes) {
/* do overlapping copy backwards, slowly! */
src += bytes;
dst += bytes;
while (bytes--)
*--dst = *--src;
}
else {
/* use possibly assembler code memcpy() */
memcpy (dst, src, bytes);
}
}
这里还考虑一个问题,就是前面讲到的i等于100会不会有问题。
bcopy((void *)&CmdList[i], (void *)&CmdList[i+1], sizeof(Cmd *) *(99 - i));
第三个参数是99-i,此时得到-1
那么看一下bcopy的实现。
实参bytes = -1*32(假设是占用32个字节) = -32
此时,if条件不再成立,dst不会小于src+bytes(后面是个负数)。
所以调用memcopy,这里我看得是lib/libc/memcpy.c的实现
void *
memcpy(void *s1, const void *s2, size_t n)
{
const char *f = s2;
char *t = s1;
if (f < t) {
f += n;
t += n;
while (n-- > 0)
*--t = *--f;
} else
while (n-- > 0)
*t++ = *f++;
return s1;
}
好像bcopy是重复了memcpy的实现,而memcpy更健壮一些,我看到它的(while (n-- > 0))判断有大于0,而实际n是赋值,所以一次都不会执行。
memcpy保住了函数的越界问题。!!!
5. 把新的命令赋值给CmdList[i],就结束了。
6. 在命令没有到达100的时候,应该还是正常使用的,如果命令到了100条,再调用这个函数的话,就会出现数组越界的行为危险。
其实bcopy是多余的,memcpy已经实现了它的功能,而且还更完善!!!!
不知道我的分析准确不,请各位大侠多多指教。
分析之前,我并不知道这个函数有问题,没想到一写,反而发现了问题。真不是找茬!!
7.这里再次强调一下,cmdlist里面存储并不是直接的pmon的命令。而是pmon分组命令的列表
比如有以下分组:
7.1shell分组
7.2 boot and load分组
7.3 network分组
7.4 还有很多分组,我这就不一一列举了。