Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 01 Dec 2004 15:35:39 +0900
From:      JINMEI Tatuya / =?ISO-2022-JP?B?GyRCP0BMQEMjOkgbKEI=?= <jinmei@isl.rdc.toshiba.co.jp>
To:        davids@webmaster.com
Cc:        current@FreeBSD.org
Subject:   Re: malloc(0) returns an invalid address
Message-ID:  <y7vfz2qpltw.wl@ocean.jinmei.org>
In-Reply-To: <MDEHLPKNGKAHNMBLJOLKAEOHACAB.davids@webmaster.com>
References:  <y7vis7mppd8.wl@ocean.jinmei.org> <MDEHLPKNGKAHNMBLJOLKAEOHACAB.davids@webmaster.com>

next in thread | previous in thread | raw e-mail | index | archive | help
>>>>> On Tue, 30 Nov 2004 21:40:25 -0800, 
>>>>> "David Schwartz" <davids@webmaster.com> said:

>> % ./a.out
>> address of p is 0x800
>> zsh: 794 segmentation fault (core dumped)  ./a.out
>> 
>> Is this a malloc bug?  Or is this the intended behavior and the man
>> page description is old?

> 	This is the intended behavior but the man page description is correct. The
> problem is not that the pointer is invalid but that you assumed that it was
> large enough to hold a 'char' and it is not.

I know the line of XXX is not correct; I simply tried to highlight the
problem, but I seem to convey the real point.  How about this example?

main()
{
	char *p = malloc(0), *q;

	printf("address of p is %p\n", p);
	printf("the value of p is %c\n", *p);
}

the execution of this code would be like this:

% ./a.out
address of p is 0x800
zsh: 645 segmentation fault (core dumped)  ./a.out

And, more specifically, my real-world problem is that 'ndp -r' fails
when it calls sysctl without any IPv6 default routers.  The related
code of ndp is as follows:

	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST };

  (...)

	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
		err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
		/*NOTREACHED*/
	}
	buf = malloc(l);
	if (!buf) {
		err(1, "malloc");
		/*NOTREACHED*/
	}
	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
		err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
		/*NOTREACHED*/
	}

The first call to sysctl sets 'l' to 0, since the list is empty.  Then
the malloc returns '0x800' as a *valid pointer*.  But in the second
call to sysctl, kernel rejects this pointer at line 1299 of
sys/kern/kern_sysctl.c:

userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
    size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
{

	(...)

	if (old) {
-->		if (!useracc(old, req.oldlen, VM_PROT_WRITE))
-->			return (EFAULT);

and so we'll see

% ndp -r
ndp: sysctl(ICMPV6CTL_ND6_DRLIST): Bad address

Note that the same code worked with, e.g., FreeBSD 4.10.

So, if we wanted to call 0x800 "a valid pointer just with
not-enough-size", it would be fine.  But then we need to implement the
same logic in the kernel to provide consistent behavior.  (I would
"fix" the malloc behavior though).

					JINMEI, Tatuya
					Communication Platform Lab.
					Corporate R&D Center, Toshiba Corp.
					jinmei@isl.rdc.toshiba.co.jp



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?y7vfz2qpltw.wl>