Greg A. Woods | 1 Jul 2009 20:25
X-Face
Favicon

Re: strtonum(3) from OpenBSD?

At Tue, 30 Jun 2009 03:00:17 +0000, David Holland <dholland-tech <at> netbsd.org> wrote:
Subject: Re: strtonum(3) from OpenBSD?
> 
> On Sat, Jun 27, 2009 at 10:26:49PM -0400, Greg A. Woods wrote:
>  > > That's the POINT. Calls that succeed may set errno anyway. You have to
>  > > check that an error occurred before inspecting errno.
>  > 
>  > Well, with strtol(3) _both_ conditions must hold exactly -- it doesn't
>  > really matter which test is done first!  :-)
> 
> In all cases, not just strtol, both conditions must hold, but it does
> matter which test is done first if errno might contain a trap
> representation.

I meant in the strict ordering of terms in the test expression(s).
I.e. all of the following statements are equivalent.  I.e. it does not
matter which test is done first.  It can be either errno first:

	if (errno == ERANGE && rval == LONG_MAX)
		err();

	if (errno == ERANGE)
		if (rval == LONG_MAX)
			err();

etc., or the return value first:

	if (rval == LONG_MAX && errno == ERANGE)
		err();

(Continue reading)

der Mouse | 1 Jul 2009 21:28

Re: strtonum(3) from OpenBSD?

>> [...], but it does matter which test is done first if errno might
>> contain a trap representation.
> I meant in the strict ordering of terms in the test expression(s).

> 	if (errno == ERANGE && rval == LONG_MAX)

> 	if (rval == LONG_MAX && errno == ERANGE)

These are not equivalent if errno might contain a trap representation
for non-LONG_MAX returns.  (Because of strtol()'s special case for
errno, this can happen only if it was that way on entry.)

>> [...] if strtol were allowed to leave trash in errno, [...]
> Hmmm... yes, but _only_ if that "trash" value were ERANGE (or the
> undocumented EINVAL return).

Yes...so?  Trash has a nasty habit of being what you least want it to
at the most inconvenient times.

> If I understand you correctly, you are suggesting that ERANGE may be
> inadvertently set by some arithmetic operation during the conversion
> of a string that represents _exactly_ LONG_MAX.

Not necessarily _arithmetic_ operation.  There is no guarantee that
strtol() and friends are leaf routines, and, indeed, it's not
implausible that they may do something (like locale setup) which may
leave relatively unpredictable trash in errno.

But, since there is no other way to disambiguate LONG_MAX, strtol()'s
interface contract includes special mention of errno - namely, that a
(Continue reading)

Greg A. Woods | 1 Jul 2009 21:54
X-Face
Picon
Favicon

why cast to char* through void*

Either I have a brain-block, or I'm missing something, or...

A long time ago I suggested to myself in a comment in login_cap.c that
the pointer arithmetic in setuserenv() should be replaced with an array
reference and thus avoid a lot of ugliness.

I see that's been done now, but the cast to char* through void* remains.

It doesn't make any sense to me -- there shouldn't be any alignment
work-arounds necessary here (should there?), and I see no other possible
reason for it.

--- login_cap.c	10 Feb 2007 12:57:39 -0500	1.25
+++ login_cap.c	01 Jul 2009 15:14:06 -0400	
 <at>  <at>  -517,8 +517,8  <at>  <at> 
 	if (!res)
 		return -1;
 	
-	ptr = (char *)(void *)&res[count];
-	(void)strcpy(ptr, str);
+	ptr = (char *) &res[count];
+	(void) strcpy(ptr, str);

 	/* split string */
 	for (i = 0; (res[i] = stresep(&ptr, stop, '\\')) != NULL; )

--

-- 
						Greg A. Woods

+1 416 218-0098                VE3TCP          RoboHack <woods <at> robohack.ca>
(Continue reading)

Christos Zoulas | 2 Jul 2009 00:33

Re: why cast to char* through void*

In article <m1MM5sb-000kmuC <at> most.weird.com>,
Greg A. Woods <tech-userlevel <at> NetBSD.org> wrote:
>-=-=-=-=-=-
>
>Either I have a brain-block, or I'm missing something, or...
>
>A long time ago I suggested to myself in a comment in login_cap.c that
>the pointer arithmetic in setuserenv() should be replaced with an array
>reference and thus avoid a lot of ugliness.
>
>I see that's been done now, but the cast to char* through void* remains.
>
>It doesn't make any sense to me -- there shouldn't be any alignment
>work-arounds necessary here (should there?), and I see no other possible
>reason for it.
>
>
>--- login_cap.c	10 Feb 2007 12:57:39 -0500	1.25
>+++ login_cap.c	01 Jul 2009 15:14:06 -0400	
> <at>  <at>  -517,8 +517,8  <at>  <at> 
> 	if (!res)
> 		return -1;
> 	
>-	ptr = (char *)(void *)&res[count];
>-	(void)strcpy(ptr, str);
>+	ptr = (char *) &res[count];
>+	(void) strcpy(ptr, str);
> 
> 	/* split string */
> 	for (i = 0; (res[i] = stresep(&ptr, stop, '\\')) != NULL; )
(Continue reading)

Greg Troxel | 2 Jul 2009 00:39
Picon

Re: why cast to char* through void*


christos <at> astron.com (Christos Zoulas) writes:

>>It doesn't make any sense to me -- there shouldn't be any alignment
>>work-arounds necessary here (should there?), and I see no other possible
>>reason for it.
>>
>>
>>--- login_cap.c	10 Feb 2007 12:57:39 -0500	1.25
>>+++ login_cap.c	01 Jul 2009 15:14:06 -0400	
>> <at>  <at>  -517,8 +517,8  <at>  <at> 
>> 	if (!res)
>> 		return -1;
>> 	
>>-	ptr = (char *)(void *)&res[count];
>>-	(void)strcpy(ptr, str);
>>+	ptr = (char *) &res[count];
>>+	(void) strcpy(ptr, str);
>> 
>> 	/* split string */
>> 	for (i = 0; (res[i] = stresep(&ptr, stop, '\\')) != NULL; )
>>
>
> Typically used to shut up gcc type punning warnings. Not that it is the TRTTD
> in all cases. Does anyone know if this makes gcc produce "the wanted" code
> (has the effect of -fno-strict-aliasing) or it just shuts up the warning?

I think the C99 spec says that a void* can alias other types, so you
don't get the warning because the unwarranted assumption isn't made, and
this should be safe.
(Continue reading)

David Holland | 2 Jul 2009 01:31
Picon

Re: why cast to char* through void*

On Wed, Jul 01, 2009 at 06:39:47PM -0400, Greg Troxel wrote:
 > > Typically used to shut up gcc type punning warnings. Not that it
 > > is the TRTTD in all cases. Does anyone know if this makes gcc
 > > produce "the wanted" code (has the effect of
 > > -fno-strict-aliasing) or it just shuts up the warning?
 > 
 > I think the C99 spec says that a void* can alias other types, 

Yes

 > so you don't get the warning 

Yes

 > because the unwarranted assumption isn't made, and this should be
 > safe.

No

The compiler is allowed to assume that two pointers of different types
point to things that don't overlap. If you violate this assumption,
any changes you make to the overlapping data are done behind the
compiler's back and may cause demons to fly out of your nose.

It doesn't matter how the overlapping pointers got that way, so
inserting extra casts doesn't help. Such casts might or might not
cause gcc to behave conservatively this year (and/or next year) but
mostly just serve to hide the problem.

--

-- 
(Continue reading)

David Holland | 2 Jul 2009 01:44
Picon

Re: strtonum(3) from OpenBSD?

On Wed, Jul 01, 2009 at 02:25:34PM -0400, Greg A. Woods wrote:
 > Speaking of the NetBSD implementation, I see it returns an undocumented
 > errno in some cases too, and the documentation is far more convoluted
 > and complex than necessary too, especially in light of knowing that
 > errno must be set to zero on return if there was no overflow during an
 > otherwise error-free conversion.

The code is also more convoluted than necessary.

I think the long-term reason is that (as this thread has shown) the
exact specification is not widely known and has not been well
understood.

--

-- 
David A. Holland
dholland <at> netbsd.org

Thor Lancelot Simon | 2 Jul 2009 04:16
Picon
Favicon

Re: why cast to char* through void*

On Wed, Jul 01, 2009 at 11:31:53PM +0000, David Holland wrote:
> 
> The compiler is allowed to assume that two pointers of different types
> point to things that don't overlap.

But there's an exception for pointers of type char *, isn't there?  At
least, I thought I remembered it was char *, but now I suspect it's
void *.

--

-- 
Thor Lancelot Simon	                                   tls <at> rek.tjls.com
    "Even experienced UNIX users occasionally enter rm *.* at the UNIX
     prompt only to realize too late that they have removed the wrong
     segment of the directory structure." - Microsoft WSS whitepaper

David Holland | 2 Jul 2009 09:13
Picon

Re: why cast to char* through void*

On Wed, Jul 01, 2009 at 10:16:05PM -0400, Thor Lancelot Simon wrote:
 > > The compiler is allowed to assume that two pointers of different types
 > > point to things that don't overlap.
 > 
 > But there's an exception for pointers of type char *, isn't there?  At
 > least, I thought I remembered it was char *, but now I suspect it's
 > void *.

Er, yes, yes there is. I meant to put that in the original post,
honest.

char * and unsigned char *.

void * doesn't matter because you can't dereference it.

--

-- 
David A. Holland
dholland <at> netbsd.org

David Laight | 2 Jul 2009 08:51
Picon

Re: why cast to char* through void*

On Wed, Jul 01, 2009 at 10:16:05PM -0400, Thor Lancelot Simon wrote:
> On Wed, Jul 01, 2009 at 11:31:53PM +0000, David Holland wrote:
> > 
> > The compiler is allowed to assume that two pointers of different types
> > point to things that don't overlap.
> 
> But there's an exception for pointers of type char *, isn't there?  At
> least, I thought I remembered it was char *, but now I suspect it's
> void *.

There is an exception for 'char *'.

But gcc will track the original pointer type through casts (probably
especially to 'void *'!) which it uses to remember the alignment
constraint of the pointer - which is fubar when you are trying to
use memcpy() to copy from a misaligned pointer.
Technically you can't have a misaligned pointer ...

	David

--

-- 
David Laight: david <at> l8s.co.uk


Gmane