From patchwork Wed Feb 3 12:29:08 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Cherepanov X-Patchwork-Id: 10703 Received: (qmail 12911 invoked by alias); 3 Feb 2016 12:29:18 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 12900 invoked by uid 89); 3 Feb 2016 12:29:17 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.4 required=5.0 tests=AWL, BAYES_00, KAM_ASCII_DIVIDERS, KAM_LOTSOFHASH, SPF_PASS autolearn=no version=3.3.2 spammy=salt, maximal, Round, 218, 7 X-HELO: contest.openwall.net Subject: Undefined behavior in glibc -- was: Re: [PATCH][BZ 17979][BZ 17721] Fix issues with sys/cdefs.h and uchar.h when using non-gcc compiler. To: Joseph Myers References: <27c31890079f41775175b94a4abedb0c.squirrel@server316.webhostingpad.com> <20160128225845.GE14840@vapier.lan> <20160128234356.GH14840@vapier.lan> <56AAB6CE.8060101@openwall.com> <20160129005816.GK14840@vapier.lan> <56AC16C8.4030202@openwall.com> Cc: Dwight Guth , libc-alpha@sourceware.org From: Alexander Cherepanov X-Enigmail-Draft-Status: N1110 Message-ID: <56B1F294.5020105@openwall.com> Date: Wed, 3 Feb 2016 15:29:08 +0300 MIME-Version: 1.0 In-Reply-To: Joseph, thanks a lot for the detailed reply. My comments are below. On 2016-01-31 19:12, Joseph Myers wrote: > On Sat, 30 Jan 2016, Alexander Cherepanov wrote: > >> But we can consider something much more real: glibc code contains many cases >> of undefined behavior (according to C11). I consider it bugs unwanted in >> production (maybe with the exception of strlen) but it's not clear to me what >> is the POV of the project on this. E.g., are bug reports about UB are welcome? > > It's an intrinsic part of implementing the C library that it involves > doing things that are not defined in ISO C (the ISO C library cannot all > be implemented in ISO C). But those parts which cannot be implemented in ISO C would be implemented in asm? AIUI there is no much magic in compiling C parts of glibc so they should obey the common rules? > If something involves undefined behavior in GNU C, GNU C is ISO C (whatever it means:-) + GCC implementation-defined behavior as described in [1] + GCC extensions[2], right? [1] https://gcc.gnu.org/onlinedocs/gcc/C-Implementation.html [2] https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html > on systems with the > properties that hold for all systems supported by glibc (e.g. 32-bit int, > 32-bit or 64-bit long and pointers), for inputs to library functions where > the library function semantics don't involve undefined behavior, taking > due account of both separate compilation and use of asm to reduce the > information available to the compiler in certain places and so make things > not undefined that would otherwise be undefined, then I'd consider bug > reports appropriate. Examples of this include buffer overruns and signed > integer arithmetic overflow. I think that applies even if there is no > plausible optimization that could result in the signed integer arithmetic > overflow causing problems. Of course, patches are even better. This looks reasonable but I guess there supposed to be some exceptions? E.g.: 1) strlen and other string functions read memory by chunks which is aliasing violation; 2) strlen accesses the OOB memory. AIUI for 1) there is may_alias gcc attribute but it almost never used in glibc. There are no tools in GNU C to make 2) well-defined but the speed-up is remarkable (Rich Felker mentioned 3x difference in speed in musl strlen on his hw). Documenting all the exceptions would be nice. Then, ASan is in glibc todo so a clean version of strlen has to be added. > If something is fully defined in GNU C, but undefined, unspecified or > implementation-defined in ISO C, I don't think bug reports are > appropriate. E.g., it's not a bug for glibc code to rely on signed shifts > by a nonnegative amount that's less than the width of the type, including > the aspects of those that are not defined by ISO C, or on the > fully-defined nature of conversions of out-of-range integer values to > signed integer types. Some such cases in code shared with gnulib (or > other external sources) may still be gnulib bugs where they aren't glibc > bugs, since gnulib is meant to be much more portable. And there may be > cases where you could argue that eliminating such usages is a desirable > *cleanup* in glibc - e.g., that the code is cleaner when it uses unsigned > types for bitwise operations. But in such cases there is not bug and so > patches should be sent without any bug reports in Bugzilla (or more > general groups of issues identified in the list of possible cleanups in > the todo list on the wiki). Ok Making glibc compilable by clang would be nice too (and it's in the glibc todo list). > Where something depends on a property common to all systems supported by > glibc, again it may be a useful *cleanup* to make this more explicit in > the code, without there being any *bug* that's appropriate to report to > Bugzilla. E.g., if code is using int in a way that requires it to be > exactly 32-bit, changing the code to use int32_t is a sensible cleanup; if > it really does mean int but is hardcoding the value of INT_MAX, making it > use INT_MAX is a sensible cleanup; if it's using long as a pointer-sized > integer type, changing it to use intptr_t is a sensible cleanup. Ok > Where glibc code relies on separate compilation to avoid undefined > behavior, this is not a bug; use of LTO on glibc's own code is not > supported. For example, where functions with different C types but > compatible ABIs are aliased, or a function is otherwise defined with a > different type from that used when it is called. Similarly, asm may be > used to limit code movement, and that could e.g. mean that aliasing is not > undefined behavior where it would otherwise be undefined. Not sure what you mean. Is it specific to calling functions or it's supposed to cover the case of strlen too? I don't see cleaning glibc for LTO in todo list in the wiki. Shouldn't it be there? > Of course, if the semantics for a function say that certain inputs result > in undefined behavior, it does not matter if C-level undefined behavior > occurs within that function for those inputs. Sure. Well, before I go and file the bugs, perhaps it's worth skimming through the list. It's mainly invalid pointer arithmetic. GNU C seems not to deviate from ISO C in this topic. Should the issues be grouped by type, by file, by subdir or in some other way? Pointer wrapping ---------------- Likely to be miscompiled in the future. Already reported: https://sourceware.org/bugzilla/show_bug.cgi?id=19411 https://sourceware.org/bugzilla/show_bug.cgi?id=19412 https://sourceware.org/bugzilla/show_bug.cgi?id=19413 Pointers pointing past an array ------------------------------- I guess there are a lot of these but searching for them is not easily automated so the list below is probably just the tip of the iceberg and maybe not even accurate. Sometimes it could be proved that the amount of "overflow" is small and, thus, it should be safe in practice (given that an object usually could not be allocated near the end of the address space). https://sourceware.org/git/?p=glibc.git;a=blob;f=resolv/ns_name.c;h=f355cf34443c46d091157ed06f4ef8487214bf10;hb=HEAD#l548 https://sourceware.org/git/?p=glibc.git;a=blob;f=nscd/nscd_getai.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l113 https://sourceware.org/git/?p=glibc.git;a=blob;f=nscd/nscd_getgr_r.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l240 https://sourceware.org/git/?p=glibc.git;a=blob;f=nscd/nscd_gethst_r.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l215 https://sourceware.org/git/?p=glibc.git;a=blob;f=nscd/nscd_gethst_r.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l370 https://sourceware.org/git/?p=glibc.git;a=blob;f=nscd/nscd_getpw_r.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l168 https://sourceware.org/git/?p=glibc.git;a=blob;f=nscd/nscd_getserv_r.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l139 https://sourceware.org/git/?p=glibc.git;a=blob;f=nscd/nscd_getserv_r.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l292 https://sourceware.org/git/?p=glibc.git;a=blob;f=nscd/nscd_initgroups.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l73 Pointers pointing before an array --------------------------------- Should be safe in practice? https://sourceware.org/git/?p=glibc.git;a=blob;f=wcsmbs/wcsncat.c;h=9b22764ca13b16a96b6f32636072203658950fdd;hb=HEAD#l39 https://sourceware.org/git/?p=glibc.git;a=blob;f=wcsmbs/wcsncpy.c;h=cd90024e4410cf06cc1083ec10d6f677f18f3e92;hb=HEAD#l32 https://sourceware.org/git/?p=glibc.git;a=blob;f=string/memcmp.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l131 https://sourceware.org/git/?p=glibc.git;a=blob;f=string/wordcopy.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l42 etc. Capping pointers at the end of the address space ------------------------------------------------ Some functions in C11 have a parameter which limits a number of characters written. IMHO it's clear that C11 doesn't intend this parameter to be a real size of output buffer and, thus, it could validly be SIZE_MAX. But we have seen differing opinions in the recent thread about strlcpy. Perhaps you can clear the question. Anyway, glibc inner parts use a pointer to the end of the buffer and upper-level functions have to check for pointer wrapping and to cap this pointer at the end of the address space. 1. Functions like snprintf cap the pointer in _IO_str_init_static_internal. 2. Functions like wcsrtombs have to cap __outbufend in struct __gconv_step_data. The capping itself is not UB (if done right) but later pointer comparisons with the resulting pointer are UB. Probably safe in practice as it's similar to [7/15] in https://gcc.gnu.org/ml/gcc/2015-04/msg00325.html . API change required? :-) Then, there are less important cases: https://sourceware.org/git/?p=glibc.git;a=blob;f=nscd/nscd_gethst_r.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l169 https://sourceware.org/git/?p=glibc.git;a=blob;f=nscd/nscd_getai.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l68 https://sourceware.org/git/?p=glibc.git;a=blob;f=nscd/nscd_getgr_r.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l105 https://sourceware.org/git/?p=glibc.git;a=blob;f=nscd/nscd_getpw_r.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l100 https://sourceware.org/git/?p=glibc.git;a=blob;f=nscd/nscd_getserv_r.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l113 and probably others. Subtracting NULL from a pointer ------------------------------- Plausible optimization: this is unconditional UB, hence mark the code as unreachable and remove everything around. https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/sigstack.c;h=b134d8e5b9655aec4afea961e1eb63f558be62c1;hb=HEAD#l45 https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/posix/profil.c;h=23e601c6c2d5a677a778df65c9088f34ff1b7a04;hb=HEAD#l40 35 other cases are in the attached subtract-null.patch (generated). Structs at NULL --------------- Plausible optimization: this is unconditional UB, hence mark the code as unreachable and remove everything around. https://sourceware.org/git/?p=glibc.git;a=blob;f=argp/argp-parse.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l81 https://sourceware.org/git/?p=glibc.git;a=blob;f=include/list.h;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l94 https://sourceware.org/git/?p=glibc.git;a=blob;f=intl/bindtextdom.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l44 https://sourceware.org/git/?p=glibc.git;a=blob;f=intl/dcigettext.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l120 https://sourceware.org/git/?p=glibc.git;a=blob;f=intl/dcigettext.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l125 https://sourceware.org/git/?p=glibc.git;a=blob;f=nptl_db/db_info.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l76 https://sourceware.org/git/?p=glibc.git;a=blob;f=posix/glob.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l151 https://sourceware.org/git/?p=glibc.git;a=blob;f=resolv/nss_dns/dns-network.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l241 https://sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/reg-modifier.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l58 https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/ia64/sys/ucontext.h;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l39 Pointers used after free (without dereferencing) ------------------------------------------------ https://sourceware.org/git/?p=glibc.git;a=blob;f=libio/fileops.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l1063 (IIUC conditions "fp->_IO_read_base != NULL" and "!_IO_in_backup (fp)" should be swapped.) https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/tst-obstack.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l25 https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/tst-malloc-backtrace.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l30 https://sourceware.org/git/?p=glibc.git;a=blob;f=io/pwd.c;hb=5163b4b76f61e361f0f4bbe3b96732b12e5c9b1a#l41 Memory allocations without check -------------------------------- Not UB but while we are at it... AIUI the policy in glibc is to check results of malloc no matter how small the requested amount of memory is. Right? So mallocs like in https://sourceware.org/bugzilla/show_bug.cgi?id=19416 should be reported? diff -u -p a/nss/nss_files/files-alias.c b/nss/nss_files/files-alias.c --- a/nss/nss_files/files-alias.c +++ b/nss/nss_files/files-alias.c @@ -338,7 +338,7 @@ get_next_alias (FILE *stream, const char /* Adjust the pointer so it is aligned for storing pointers. */ first_unused += __alignof__ (char *) - 1; - first_unused -= ((first_unused - (char *) 0) + first_unused -= ((uintptr_t)first_unused % __alignof__ (char *)); result->alias_members = (char **) first_unused; diff -u -p a/nss/nss_files/files-hosts.c b/nss/nss_files/files-hosts.c --- a/nss/nss_files/files-hosts.c +++ b/nss/nss_files/files-hosts.c @@ -211,7 +211,7 @@ _nss_files_gethostbyname3_r (const char } /* Make sure bufferend is aligned. */ - assert ((bufferend - (char *) 0) % sizeof (char *) == 0); + assert ((uintptr_t)bufferend % sizeof (char *) == 0); /* Now we can check whether the buffer is large enough. 16 is the maximal size of the IP address. */ @@ -264,7 +264,7 @@ _nss_files_gethostbyname3_r (const char /* Round up the buffer end address. */ bufferend += (sizeof (char *) - - ((bufferend - (char *) 0) + - ((uintptr_t)bufferend % sizeof (char *))) % sizeof (char *); /* Now the new address. */ diff -u -p a/nss/nss_files/files-parse.c b/nss/nss_files/files-parse.c --- a/nss/nss_files/files-parse.c +++ b/nss/nss_files/files-parse.c @@ -243,7 +243,7 @@ parse_list (char **linep, char *eol, cha /* Adjust the pointer so it is aligned for storing pointers. */ eol += __alignof__ (char *) - 1; - eol -= (eol - (char *) 0) % __alignof__ (char *); + eol -= (uintptr_t)eol % __alignof__ (char *); /* We will start the storage here for the vector of pointers. */ list = (char **) eol; diff -u -p a/nis/nss_nisplus/nisplus-rpc.c b/nis/nss_nisplus/nisplus-rpc.c --- a/nis/nss_nisplus/nisplus-rpc.c +++ b/nis/nss_nisplus/nisplus-rpc.c @@ -96,7 +96,7 @@ _nss_nisplus_parse_rpcent (nis_result *r /* Adjust the pointer so it is aligned for storing pointers. */ size_t adjust = ((__alignof__ (char *) - - (first_unused - (char *) 0) % __alignof__ (char *)) + - (uintptr_t)first_unused % __alignof__ (char *)) % __alignof__ (char *)); if (room_left < adjust + sizeof (char *)) goto no_more_room; diff -u -p a/nis/nss_nisplus/nisplus-network.c b/nis/nss_nisplus/nisplus-network.c --- a/nis/nss_nisplus/nisplus-network.c +++ b/nis/nss_nisplus/nisplus-network.c @@ -100,7 +100,7 @@ _nss_nisplus_parse_netent (nis_result *r /* Adjust the pointer so it is aligned for storing pointers. */ size_t adjust = ((__alignof__ (char *) - - (first_unused - (char *) 0) % __alignof__ (char *)) + - (uintptr_t)first_unused % __alignof__ (char *)) % __alignof__ (char *)); if (room_left < adjust + sizeof (char *)) goto no_more_room; diff -u -p a/nis/nss_nisplus/nisplus-alias.c b/nis/nss_nisplus/nisplus-alias.c --- a/nis/nss_nisplus/nisplus-alias.c +++ b/nis/nss_nisplus/nisplus-alias.c @@ -121,7 +121,7 @@ _nss_nisplus_parse_aliasent (nis_result /* Adjust the pointer so it is aligned for storing pointers. */ size_t adjust = ((__alignof__ (char *) - - (first_unused - (char *) 0) % __alignof__ (char *)) + - (uintptr_t)first_unused % __alignof__ (char *)) % __alignof__ (char *)); if (room_left < adjust) goto no_more_room; diff -u -p a/nis/nss_nisplus/nisplus-service.c b/nis/nss_nisplus/nisplus-service.c --- a/nis/nss_nisplus/nisplus-service.c +++ b/nis/nss_nisplus/nisplus-service.c @@ -103,7 +103,7 @@ _nss_nisplus_parse_servent (nis_result * /* Adjust the pointer so it is aligned for storing pointers. */ size_t adjust = ((__alignof__ (char *) - - (first_unused - (char *) 0) % __alignof__ (char *)) + - (uintptr_t)first_unused % __alignof__ (char *)) % __alignof__ (char *)); if (room_left < adjust + sizeof (char *)) goto no_more_room; diff -u -p a/nis/nss_nisplus/nisplus-hosts.c b/nis/nss_nisplus/nisplus-hosts.c --- a/nis/nss_nisplus/nisplus-hosts.c +++ b/nis/nss_nisplus/nisplus-hosts.c @@ -142,7 +142,7 @@ _nss_nisplus_parse_hostent (nis_result * /* Adjust the pointer so it is aligned for storing pointers. */ size_t adjust = ((__alignof__ (char *) - - (first_unused - (char *) 0) % __alignof__ (char *)) + - (uintptr_t)first_unused % __alignof__ (char *)) % __alignof__ (char *)); if (room_left < adjust + 3 * sizeof (char *)) goto no_more_room; diff -u -p a/nis/nss_nisplus/nisplus-parser.c b/nis/nss_nisplus/nisplus-parser.c --- a/nis/nss_nisplus/nisplus-parser.c +++ b/nis/nss_nisplus/nisplus-parser.c @@ -218,7 +218,7 @@ _nss_nisplus_parse_grent (nis_result *re /* Adjust the pointer so it is aligned for storing pointers. */ size_t adjust = ((__alignof__ (char *) - - (first_unused - (char *) 0) % __alignof__ (char *)) + - (uintptr_t)first_unused % __alignof__ (char *)) % __alignof__ (char *)); if (room_left < adjust) goto no_more_room; diff -u -p a/nis/nss_nisplus/nisplus-proto.c b/nis/nss_nisplus/nisplus-proto.c --- a/nis/nss_nisplus/nisplus-proto.c +++ b/nis/nss_nisplus/nisplus-proto.c @@ -97,7 +97,7 @@ _nss_nisplus_parse_protoent (nis_result /* Adjust the pointer so it is aligned for storing pointers. */ size_t adjust = ((__alignof__ (char *) - - (first_unused - (char *) 0) % __alignof__ (char *)) + - (uintptr_t)first_unused % __alignof__ (char *)) % __alignof__ (char *)); if (room_left < adjust + sizeof (char *)) goto no_more_room; diff -u -p a/nis/nss_nis/nis-alias.c b/nis/nss_nis/nis-alias.c --- a/nis/nss_nis/nis-alias.c +++ b/nis/nss_nis/nis-alias.c @@ -67,7 +67,7 @@ _nss_nis_parse_aliasent (const char *key /* Adjust the pointer so it is aligned for storing pointers. */ first_unused += __alignof__ (char *) - 1; - first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *)); + first_unused -= ((uintptr_t)first_unused % __alignof__ (char *)); result->alias_members = (char **) first_unused; line = alias; diff -u -p a/crypt/sha256-crypt.c b/crypt/sha256-crypt.c --- a/crypt/sha256-crypt.c +++ b/crypt/sha256-crypt.c @@ -143,7 +143,7 @@ __sha256_crypt_r (const char *key, const salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX); key_len = strlen (key); - if ((key - (char *) 0) % __alignof__ (uint32_t) != 0) + if ((uintptr_t)key % __alignof__ (uint32_t) != 0) { char *tmp; @@ -158,20 +158,20 @@ __sha256_crypt_r (const char *key, const key = copied_key = memcpy (tmp + __alignof__ (uint32_t) - - (tmp - (char *) 0) % __alignof__ (uint32_t), + - (uintptr_t)tmp % __alignof__ (uint32_t), key, key_len); - assert ((key - (char *) 0) % __alignof__ (uint32_t) == 0); + assert ((uintptr_t)key % __alignof__ (uint32_t) == 0); } - if ((salt - (char *) 0) % __alignof__ (uint32_t) != 0) + if ((uintptr_t)salt % __alignof__ (uint32_t) != 0) { char *tmp = (char *) alloca (salt_len + __alignof__ (uint32_t)); alloca_used += salt_len + __alignof__ (uint32_t); salt = copied_salt = memcpy (tmp + __alignof__ (uint32_t) - - (tmp - (char *) 0) % __alignof__ (uint32_t), + - (uintptr_t)tmp % __alignof__ (uint32_t), salt, salt_len); - assert ((salt - (char *) 0) % __alignof__ (uint32_t) == 0); + assert ((uintptr_t)salt % __alignof__ (uint32_t) == 0); } #ifdef USE_NSS diff -u -p a/crypt/sha512-crypt.c b/crypt/sha512-crypt.c --- a/crypt/sha512-crypt.c +++ b/crypt/sha512-crypt.c @@ -143,7 +143,7 @@ __sha512_crypt_r (const char *key, const salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX); key_len = strlen (key); - if ((key - (char *) 0) % __alignof__ (uint64_t) != 0) + if ((uintptr_t)key % __alignof__ (uint64_t) != 0) { char *tmp; @@ -158,19 +158,19 @@ __sha512_crypt_r (const char *key, const key = copied_key = memcpy (tmp + __alignof__ (uint64_t) - - (tmp - (char *) 0) % __alignof__ (uint64_t), + - (uintptr_t)tmp % __alignof__ (uint64_t), key, key_len); - assert ((key - (char *) 0) % __alignof__ (uint64_t) == 0); + assert ((uintptr_t)key % __alignof__ (uint64_t) == 0); } - if ((salt - (char *) 0) % __alignof__ (uint64_t) != 0) + if ((uintptr_t)salt % __alignof__ (uint64_t) != 0) { char *tmp = (char *) alloca (salt_len + __alignof__ (uint64_t)); salt = copied_salt = memcpy (tmp + __alignof__ (uint64_t) - - (tmp - (char *) 0) % __alignof__ (uint64_t), + - (uintptr_t)tmp % __alignof__ (uint64_t), salt, salt_len); - assert ((salt - (char *) 0) % __alignof__ (uint64_t) == 0); + assert ((uintptr_t)salt % __alignof__ (uint64_t) == 0); } #ifdef USE_NSS diff -u -p a/crypt/md5-crypt.c b/crypt/md5-crypt.c --- a/crypt/md5-crypt.c +++ b/crypt/md5-crypt.c @@ -111,7 +111,7 @@ __md5_crypt_r (const char *key, const ch salt_len = MIN (strcspn (salt, "$"), 8); key_len = strlen (key); - if ((key - (char *) 0) % __alignof__ (md5_uint32) != 0) + if ((uintptr_t)key % __alignof__ (md5_uint32) != 0) { char *tmp; @@ -126,19 +126,19 @@ __md5_crypt_r (const char *key, const ch key = copied_key = memcpy (tmp + __alignof__ (md5_uint32) - - (tmp - (char *) 0) % __alignof__ (md5_uint32), + - (uintptr_t)tmp % __alignof__ (md5_uint32), key, key_len); - assert ((key - (char *) 0) % __alignof__ (md5_uint32) == 0); + assert ((uintptr_t)key % __alignof__ (md5_uint32) == 0); } - if ((salt - (char *) 0) % __alignof__ (md5_uint32) != 0) + if ((uintptr_t)salt % __alignof__ (md5_uint32) != 0) { char *tmp = (char *) alloca (salt_len + __alignof__ (md5_uint32)); salt = copied_salt = memcpy (tmp + __alignof__ (md5_uint32) - - (tmp - (char *) 0) % __alignof__ (md5_uint32), + - (uintptr_t)tmp % __alignof__ (md5_uint32), salt, salt_len); - assert ((salt - (char *) 0) % __alignof__ (md5_uint32) == 0); + assert ((uintptr_t)salt % __alignof__ (md5_uint32) == 0); } #ifdef USE_NSS diff -u -p a/stdlib/msort.c b/stdlib/msort.c --- a/stdlib/msort.c +++ b/stdlib/msort.c @@ -282,15 +282,15 @@ __qsort_r (void *b, size_t n, size_t s, else { if ((s & (sizeof (uint32_t) - 1)) == 0 - && ((char *) b - (char *) 0) % __alignof__ (uint32_t) == 0) + && (uintptr_t)b % __alignof__ (uint32_t) == 0) { if (s == sizeof (uint32_t)) p.var = 0; else if (s == sizeof (uint64_t) - && ((char *) b - (char *) 0) % __alignof__ (uint64_t) == 0) + && (uintptr_t)b % __alignof__ (uint64_t) == 0) p.var = 1; else if ((s & (sizeof (unsigned long) - 1)) == 0 - && ((char *) b - (char *) 0) + && (uintptr_t)b % __alignof__ (unsigned long) == 0) p.var = 2; }