C 使用此netbsd代码是否可重入
我正在通过阅读NetBSD源代码来学习“阅读代码”。C 使用此netbsd代码是否可重入,c,multithreading,static,reentrancy,netbsd,C,Multithreading,Static,Reentrancy,Netbsd,我正在通过阅读NetBSD源代码来学习“阅读代码”。 (对于任何感兴趣的人来说,这是我正在阅读的) 我发现这个函数: /* convert IP address to a string, but not into a single buffer */ char * naddr_ntoa(naddr a) { #define NUM_BUFS 4 static int bufno; static struct { char str[16]; /* xxx.xxx.xxx
(对于任何感兴趣的人来说,这是我正在阅读的<代码阅读:开源透视图>) 我发现这个函数:
/* convert IP address to a string, but not into a single buffer
*/
char *
naddr_ntoa(naddr a)
{
#define NUM_BUFS 4
static int bufno;
static struct {
char str[16]; /* xxx.xxx.xxx.xxx\0 */
} bufs[NUM_BUFS];
char *s;
struct in_addr addr;
addr.s_addr = a;
strlcpy(bufs[bufno].str, inet_ntoa(addr), sizeof(bufs[bufno].str));
s = bufs[bufno].str;
bufno = (bufno+1) % NUM_BUFS;
return s;
#undef NUM_BUFS
}
它引入了4种不同的临时缓冲区来包装inet_ntoa函数,因为inet_ntoa不是可重入的。
但在我看来,naddr_ntoa函数也不是可重入函数:
静态bufno变量可由其他变量操作,因此临时缓冲区似乎无法按预期工作
那么这是一个潜在的bug吗?是的,这是一个潜在的bug。如果您想要一个类似的函数,很可能是可重入的,您可以使用它,例如(顺便说一下,它也可以处理IPv6)。该代码来自
src/sbin/routed/trace.c
,它不是一个通用的库例程,只是一个仅在路由程序中使用的自定义hack。同一文件中的addrname()
函数出于相同的原因使用了相同的技巧。它本身甚至不是NetBSD代码,而是最初来自SGI,由Vernon Schryver维护(请参阅)
允许在同一个表达式中使用多个调用只是一种快速的技巧,例如在一个printf()调用中使用结果:例如:
printf("addr1->%s, addr2->%s, addr3->%s, addr4->%s\n",
naddr_ntoa(addr1), naddr_ntoa(addr2), naddr_ntoa(addr3), naddr_ntoa(addr4));
路由源文件(if.c、input.c、rdisc.c)中有几个类似的用法示例
这段代码中没有bug。路由程序不是多线程的。在这次黑客攻击中,可重入性根本没有得到解决。这个技巧是为一个与重入无关的特定目的而设计的。代码读取作者将此技巧与重入关联是错误的
这只是一种隐藏在静态变量数组中保存多个结果的方法,而不是在单个表达式需要多个结果时,将这些结果从一个静态变量单独复制到调用函数中的单独存储中
请记住,除了标识符的有限范围外,静态变量具有全局变量的所有属性。当然,在函数中不受保护地使用全局(或静态)变量会使该函数不可重入,但这不是全局变量引起的唯一问题。在routed中使用完全可重入函数是不合适的,因为它实际上会使代码变得比必要的更复杂,而这种黑客行为使调用代码保持干净和简单。不过,最好对黑客行为进行适当的记录,以便未来的维护人员更容易发现何时需要调整
NUM_BUFS
。事实上,在我看来,他们这样写似乎是为了避免malloc
,而不是为了重新进入inet_ntoa
,根据我读到的至少一个手册页,它只使用一个静态缓冲区(这可能被NetBSD开发人员认为是不可接受的)。你能为它的可重入性添加一个引用吗?@nnoneo好吧,如果在某个地方隐藏了一个全局/静态缓冲区,那么你可以提供自己的缓冲区,因为它是可重入的(当然,除非它是以不可重入的方式调用的)。在这里扮演魔鬼代言人,但它可以有其他内部状态使其不可重入。(我认为不是这样。)printf
不是可重入的,但您的逻辑会表明它是可重入的。如果inet\u ntop
调用sprintf
(这不能保证是可重入的)?@nneonneo你是对的。我看的每一个地方,每个人都说它是可重入的,但阅读手册页面(包括我答案中链接的POSIX页面)却没有提到可重入或线程安全。我将重新表述我的答案。:)