Re: svn commit: r300956 - head/lib/libc/stdlib
>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
> 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
>> 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
>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
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
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