Re: svn commit: r300956 - head/lib/libc/stdlib

2016-05-31 Thread Chris Torek
>That was what I was complaining about.  div.c is for C90 (misspelled
>"ANSI").

It wasn't misspelled when I wrote it.  :-)  The 1989 ANSI C
standard was formally ratified in Dec 1989, and the draft was
pretty firm by the time I wrote the code (which I am sure was also
1989, despite the 1990 copyright; we added or updated all the
copyrights at the last minute, for net-2).  ISO's quick adoption,
and hence the name C90, post-date all of that.

>... div.c hasn't caught up with C99.  C99 broke this by changing
>the rules for integer division to disallow correct rounding for and
>require consistently incorrect rounding.

Specifically, C99 requires truncation towards zero, so that
(-1)/2 = 0 (not -1) and 1/(-2) = 0 (not -1).  You (and I) might
prefer (-1)/2 = -1, but most CPU "integer divide" ops provide
the other result (so that "x >> 1" and "x / 2" are different
when x is negative: "x >> 1" sign extends so that (-1)>>1 == -1).

C90 (and C99) both require div() and ldiv() to behave like most
CPUs, this this truncation-towards-zero behavior, which makes
the two functions kind of pointless in C99.

>Correct rounding for a
>positive divisor is towards minus infinity so that the remainder is
>not negative.  This is modulo arithmetic and has good algebraic
>properties.  C99 requires rounding minus infinity, at least for positive
>divisors, under the extension "reliable integer division".

Did you state this backwards?  For integer divison I see:

When integers are divided, the result of the / operator is the
algebraic quotient with any fractional part discarded.[105] If
the quotient a/b is representable, the expression (a/b)*b + a%b
shall equal a; otherwise, the behavior of both a/b and a%b is
undefined.

which (as footnote 105 notes) is "truncation towards zero", so that
(-1)/2 is 0 and not -1.

>In C90,
>the rounding is implementation-defined, so it may be correct, but it
>is "unreliable" since it can be anything.
>
>In C90, div() is specified as giving "reliable" division, and that is
>what the fixups implement.  This now wastes time to change nothing.

Right -- as long as the compiler must meet C99 rules, div.c
can just use the / and % operators.

Chris
___
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"


Re: svn commit: r301024 - head/sbin/swapon

2016-05-31 Thread Chris Torek
> This change makes the code use the POSIX basename() function. It has the
> advantage that (if implemented correctly), it also imposes no restrict
> on the pathname length.

I'm not sure what the parenthetic remark "if implemented correctly"
means, but libc basename() has this in it:

char *
basename(const char *path)
{
static char *bname = NULL;

if (bname == NULL) {
bname = (char *)malloc(MAXPATHLEN);
if (bname == NULL)
return (NULL);
}
return (basename_r(path, bname));
}

which means that it is not only not thread-safe, it also
imposes restrictions on pathname length.

I recently wrote a pair of can-be-thread-safe yet can-be-
unlimited-path-length yet can-be-backwards-compatible basename
and dirname functions (I tested to see if they produced the same
errno's and oddball outputs like for dirname("///")).  I'll toss
them in here in case anyone has some enthusiasm for fixing the
mess.  Of course they are equally non-standard, unless we can
convince a future POSIX committee or something.

(I also wrote some halfway useable reentrant getpw* and getgr*
functions but they need more thought and do not play well with
nsswitch so I am not including them here.  NB: rfuncs.h just
contains declarations for these reentrant r_* functions.)

Chris

---

/*
 * Copyright 2016 Chris Torek <chris.to...@gmail.com>
 * All rights reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted providing that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *notice, this list of conditions and the following disclaimer in the
 *documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include 
#include 
#include 
#include 

#include "rfuncs.h"

/*
 * This is essentially a clone of the BSD basename_r function,
 * which is like POSIX basename() but puts the result in a user
 * supplied buffer.
 *
 * In BSD basename_r, the buffer must be least MAXPATHLEN bytes
 * long.  In our case we take the size of the buffer as an argument.
 *
 * Note that it's impossible in general to do this without
 * a temporary buffer since basename("foo/bar") is "bar",
 * but basename("foo/bar/") is still "bar" -- no trailing
 * slash is allowed.
 *
 * The return value is your supplied buffer , or NULL if
 * the length of the basename of the supplied  equals or
 * exceeds your indicated .
 *
 * As a special but useful case, if you supply NULL for the 
 * argument, we allocate the buffer dynamically to match the
 * basename, i.e., the result is basically strdup()ed for you.
 * In this case  is ignored (recommended: pass 0 here).
 */
char *
r_basename(const char *path, char *buf, size_t bufsize)
{
const char *endp, *comp;
size_t len;

/*
 * NULL or empty path means ".".  This is perhaps overly
 * forgiving but matches libc basename_r(), and avoids
 * breaking the code below.
 */
if (path == NULL || *path == '\0') {
comp = ".";
len = 1;
} else {
/*
 * Back up over any trailing slashes.  If we reach
 * the top of the path and it's still a trailing
 * slash, it's also a leading slash and the entire
 * path is just "/" (or "//", or "///", etc).
 */
endp = path + strlen(path) - 1;
while (*endp == '/' && endp > path)
endp--;
/* Invariant: *endp != '/' || endp == path */
if (*endp == '/') {
/* then endp==path and hence entire path is "/" */
comp = "/";
len = 1

Re: svn commit: r300332 - in head/sys: amd64/amd64 i386/i386

2016-05-21 Thread Chris Torek
>> Can you explain a little bit about the badly behaved ordering of
>> unsigned integers?  I am not familiar with that.
>
>The strongest ordering properties for real numbers depend on the existence
>of negative numbers (and zero).  E.g., x >= y if and only if x - y >= 0.
>To apply that, you need the more basic property that the ordering keeps
>negative numbers separate from strictly positive numbers and zero.
>
>Without negative numbers, we can hope for weaker properties.  One is
>that x1 <= x2 implies x1 + y <= x2 + y.  The is true for C signed and
>unsigned integers if there is no overflow, but for the unsigned case
>overflow is often considered normal and is technically not described
>as overflow.

On the other hand, since most C compilers don't bother to trap
signed integer overflow, but some can, signed integers may behave
just as badly.  :-)

Overall I personally find the rules simpler for unsigned integers
(occasionally surprising, but predictable and provable behavior in
the mod-2^k ring) than for signed integers (occasionally
surprising, possible trap on overflow, possible nonsense on
overflow, unpredictable and hence unprovable in general).

The ANSI C folks in 1989 made a mess with the "value preserving"
rules where unsigned integers become signed integers if the
widened type is capable of representing all the values of the
narrower type, but become wider unsigned integers if the widened
type is not capable of representing all these values.

Even restricting operation to two's complement, 8-bit-byte,
conventional systems, this means we have several realistic cases:

  * 16-bit int, 32-bit long, 64-bit long long ("I16L32"):
unsigned char widens to signed int, but unsigned short widens
to unsigned int.  (This model is does not run BSD but is still
used in some embedded systems.)

  * 32-bit int, 32-bit long, 64-bit long long ("IL32"):
unsigned char and unsigned short widen to signed int;
unsigned int stays unsigned.  Mixing unsigned int or
unsigned long with signed long long gives you signed behavior.

  * 32-bit int, 64-bit long, 64-bit long long ("I32L64"): mostly
behaves like IL32, but mixing unsigned long with signed
long long gives you unsigned behavior.

The byte length of pointers may be any of these, and the
short-hand notation names usually have a "P" in there, e.g.,
ILP32 means all are 32 bit, I32LP64 means 32-bit int but
64-bit long and pointers, and so on.

Exotic machines with variable-length or variable-format pointers
(depending on the data type) are rarer now, although some still
make code pointers much longer than data pointers.  (Some bypass
the problem by using data pointers to descriptors instead of raw
code pointers.  That is, for void (*fp)(), fp need not point
directly to the code to run: it can point instead to a data
descriptor that may include both a raw code address and some
sort of context, for instance.)

 ---

Ultimately, assuming "i" and "limit" are (a) both signed, or have
the same type except that "limit" is unsigned, and (b) "limit" is
sane (is nonnegative), using:

if (i >= 0 && i < limit)

and:

if ((unsigned T)i < (unsigned T)limit)

do the same thing.  But the second form obviously requires knowing
what type-name T to insert, and knowing something about "limit"
(that it is nonnegative).  It used to generate significantly
better code to write just the one unsigned-cast test, but these
days it's better to just spell out the ">= 0" and let the compiler
optimize when possible.

Chris
___
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"


Re: svn commit: r300167 - in head: contrib/bsnmp/snmpd usr.sbin/bsnmpd/bsnmpd

2016-05-18 Thread Chris Torek
>I don't know much about CMSG*, so I wouldn't have if you didn't ask :-).

One thing to know about the CMSG (control message) stuff is that
it is badly broken, at least on I32LP64 systems.  Not the CMSG_*
aligning macros themselves (the alignment is linked to stuff I did
back in the early sparc-port days, around 1992 or so), but
internally, when file descriptor rights are internalized before
sending.  This converts them from 32 bit "int"s to 64 bit
pointers, which winds up breaking other code.

See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=181741
(I attached a revised set of patches that apply to current kernels,
adding a rewrite of the transform code for sanity / readability.)

>... So void * works better in all cases in the kernel.

If someone wanted to change CMSG_DATA, CMSG_FIRSTHDR, and
CMSG_NEXTHDR to produce "void *", I'd vote in favor of that. :-)

Chris
___
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"


Re: svn commit: r281451 - head/sys/vm

2015-04-24 Thread Chris Torek
The problem seems likely to be related to odd compiler handling of
alignment.  Consider this code bit, which extracts the essentials:

struct x {
int x;
} __attribute__((__aligned__(32)));

struct s1 {
int a;
struct x b[1];
};

struct s2 {
int a;
struct x b[];
};

extern void test2(int);
void test(void) {
test2(sizeof(struct s1));
test2(sizeof(struct s2));
}

Compiled, here are the two sizeof values (this particular compiler
output is from clang but gcc and clang both agree on sizeof here):

movl$64, %edi
callq   test2
movl$32, %edi
popq%rbp
jmp test2   # TAILCALL

With the flexible array, (sizeof(struct uma_cache)) is going to be
32 bytes smaller than without it.

(I have not looked closely enough to determine what the size should be.)

Chris
___
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to svn-src-all-unsubscr...@freebsd.org


Re: svn commit: r281451 - head/sys/vm

2015-04-24 Thread Chris Torek
True, it's not actually odd, it's just surprising the first time
one comes across it.

Also, I goofed in the text:

 With the flexible array, (sizeof(struct uma_cache)) is going to be
 32 bytes smaller than without it.

It's `struct uma_zone` that shrinks by (potentially) more than one
would expect.  (The uma_cache struct is itself 32 bytes and is not
changed, so the args.size value should be the same -- implying that
some OTHER sizeof(struct uma_zone) is where things are going wrong.)

Chris
___
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to svn-src-all-unsubscr...@freebsd.org