From patchwork Fri Dec 28 14:13:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 154605 Delivered-To: patch@linaro.org Received: by 2002:a2e:299d:0:0:0:0:0 with SMTP id p29-v6csp8064180ljp; Fri, 28 Dec 2018 06:13:35 -0800 (PST) X-Google-Smtp-Source: ALg8bN7bGMVdn1ulqNrSmTvKeDNDp4OwTnild0tP7UaS4M6olA3U7M/u674pTqfo25vmgPruigHb X-Received: by 2002:a17:902:bb05:: with SMTP id l5mr28243898pls.230.1546006415418; Fri, 28 Dec 2018 06:13:35 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1546006415; cv=none; d=google.com; s=arc-20160816; b=f+PpCZ/MJkBY5OmgiJg+aNI6HUIG9fDJvihJyoOYW6XgnFZqne3mcW4OM6ZvZrWRrV 5pbVUB398NQXn9Lfb93ekqPJ4R7ZZU3DlJOgQeCZKAYoK7pzo6X3jbnZAkbkxG3gDwx0 Qilbp/uBZTCw8MzNsWdCv0HZ30cWByRm9WvPqwr2BFMVdnCWl8j+nOY+qrP7DCPMF7ZM 7vem45cLdadZchBvZDZzhD4LrMjeNTStYWJ4L0OOq9IZryFiNpIRxTRzFyUaonsROQRy N44Uowgq2/UtFn9gugjDEfpNog/Xj7lTfB7zGyRF9Op43SIJid8ZyJIedo7YuRkyeCVj r9lQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=message-id:date:subject:to:from:dkim-signature:delivered-to:sender :list-help:list-post:list-archive:list-subscribe:list-unsubscribe :list-id:precedence:mailing-list:dkim-signature:domainkey-signature; bh=BYIVfGE1wQTDR1PsOUin+Nls3l0W0MWbnhxGF3+UU6o=; b=jdwX11ugSKNm6pWDXhkGd/2eHa3Qc99w6ag94tBZkBStaPd7FTKx8Ljyfx2ek332nV Ba2IPce+W6KL0ZVUG35e2MdBDhKUPiH8GHOvkwdCvd4MtRo8Jkfn1PnEoKTgGEAMK6/U ripOKN/NviClBSyLU1LpFNCZhrAZCh/8TdK4YihuJZ/oJQouCvy8mDO5iWK0vjYnivSu zTvGf762PekEkKiFJG1PMzWuQZpLSyuV6AHkkyj63xSxw2DkRKhzIvxw3QxDcTXAJ9/C xv6HlgxLLNrnNt2bYPXLaxb8TxAzagtIhV943nmYZXeYUwmN8NpFIaAwa/SbbjvSF2e2 7w/g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=MyfQ4G6C; dkim=pass header.i=@linaro.org header.s=google header.b=fN+El9ov; spf=pass (google.com: domain of libc-alpha-return-98843-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-98843-patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id u72si36984603pgc.360.2018.12.28.06.13.35 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 28 Dec 2018 06:13:35 -0800 (PST) Received-SPF: pass (google.com: domain of libc-alpha-return-98843-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=MyfQ4G6C; dkim=pass header.i=@linaro.org header.s=google header.b=fN+El9ov; spf=pass (google.com: domain of libc-alpha-return-98843-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-98843-patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id; q=dns; s= default; b=ou6K4g+8TLw8PDn3uDZqlMupHQub+7HkOBbAkxOF0FtI+Fly7micE YnOEOFhlCQFj/b0tfF/BCYefiWGeKeSWw4t3BgGE0KZuq4b/+nVnI4SzUjDse4Xa rj+KWlubi29eDXyMnYKYtNl6xaeorIrCuMlFIUN3nPTWzOFtmO0Ois= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id; s=default; bh=63vyR3V3rkuLuFwRiwrH8z/r/Bs=; b=MyfQ4G6ClTDthf/YTBaHfCBaqmG6 V/VTAlO95mrrXyOf7qGbQj5Kfh3UWsPb1ws3aynCM9hq8X3SEMyPeNKW6S2hlKgZ VEDf/tWU+/+wKPe8HDF0cZLEUycBhXV/nCK6WudOwaMjvmrhkjHTUa8YEuGhK6fk CeCzfQ42TP92kAc= Received: (qmail 116044 invoked by alias); 28 Dec 2018 14:13:25 -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 116034 invoked by uid 89); 28 Dec 2018 14:13:25 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=scratch X-HELO: mail-qk1-f194.google.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:subject:date:message-id; bh=BYIVfGE1wQTDR1PsOUin+Nls3l0W0MWbnhxGF3+UU6o=; b=fN+El9ovFxZgrH5KRm+GWbXmGU3oDr4n55rhdCmteRA9ijg54B8i5ThEYFHf78Fiku I4BNUkqxxoJJdx6qWwrfzh+dSAlYsuGWhkzAXAQ3X8wj49JV0Nja3P3Jn7lXD/0pBVo5 QUFxnjjYhu2OB6imw4yzWEp+c2IbsvjETEIOQ= Return-Path: From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH v2 1/2] Replace check_mul_overflow_size_t with __builtin_mul_overflow Date: Fri, 28 Dec 2018 12:13:15 -0200 Message-Id: <20181228141316.25952-1-adhemerval.zanella@linaro.org> Changes from previous version: - Replace INT_MULTIPLY_WRAPV with check_mul_overflow_size_t. -- Checked on x86_64-linux-gnu and i686-linux-gnu. * malloc/alloc_buffer_alloc_array.c (__libc_alloc_buffer_alloc_array): Use __builtin_mul_overflow in place of check_mul_overflow_size_t. * malloc/dynarray_emplace_enlarge.c (__libc_dynarray_emplace_enlarge): Likewise. * malloc/dynarray_resize.c (__libc_dynarray_resize): Likewise. * malloc/reallocarray.c (__libc_reallocarray): Likewise. * malloc/malloc-internal.h (check_mul_overflow_size_t): Remove function. * support/blob_repeat.c (check_mul_overflow_size_t, (minimum_stride_size, support_blob_repeat_allocate): Likewise. --- ChangeLog | 13 +++++++++++++ malloc/alloc_buffer_alloc_array.c | 3 +-- malloc/dynarray_emplace_enlarge.c | 3 +-- malloc/dynarray_resize.c | 3 +-- malloc/malloc-internal.h | 20 -------------------- malloc/reallocarray.c | 7 +++---- support/blob_repeat.c | 26 +++----------------------- 7 files changed, 22 insertions(+), 53 deletions(-) -- 2.17.1 diff --git a/malloc/alloc_buffer_alloc_array.c b/malloc/alloc_buffer_alloc_array.c index 1dd098a8fc..7505422b43 100644 --- a/malloc/alloc_buffer_alloc_array.c +++ b/malloc/alloc_buffer_alloc_array.c @@ -17,7 +17,6 @@ . */ #include -#include #include void * @@ -28,7 +27,7 @@ __libc_alloc_buffer_alloc_array (struct alloc_buffer *buf, size_t element_size, /* The caller asserts that align is a power of two. */ size_t aligned = ALIGN_UP (current, align); size_t size; - bool overflow = check_mul_overflow_size_t (element_size, count, &size); + bool overflow = __builtin_mul_overflow (element_size, count, &size); size_t new_current = aligned + size; if (!overflow /* Multiplication did not overflow. */ && aligned >= current /* No overflow in align step. */ diff --git a/malloc/dynarray_emplace_enlarge.c b/malloc/dynarray_emplace_enlarge.c index 0408271e27..aa8f5fae3f 100644 --- a/malloc/dynarray_emplace_enlarge.c +++ b/malloc/dynarray_emplace_enlarge.c @@ -18,7 +18,6 @@ #include #include -#include #include #include @@ -52,7 +51,7 @@ __libc_dynarray_emplace_enlarge (struct dynarray_header *list, } size_t new_size; - if (check_mul_overflow_size_t (new_allocated, element_size, &new_size)) + if (__builtin_mul_overflow (new_allocated, element_size, &new_size)) return false; void *new_array; if (list->array == scratch) diff --git a/malloc/dynarray_resize.c b/malloc/dynarray_resize.c index 0bfca1ba4b..0205cf7ab2 100644 --- a/malloc/dynarray_resize.c +++ b/malloc/dynarray_resize.c @@ -18,7 +18,6 @@ #include #include -#include #include #include @@ -38,7 +37,7 @@ __libc_dynarray_resize (struct dynarray_header *list, size_t size, over-allocation here. */ size_t new_size_bytes; - if (check_mul_overflow_size_t (size, element_size, &new_size_bytes)) + if (__builtin_mul_overflow (size, element_size, &new_size_bytes)) { /* Overflow. */ __set_errno (ENOMEM); diff --git a/malloc/malloc-internal.h b/malloc/malloc-internal.h index 9cee0fb2d7..70d5b38504 100644 --- a/malloc/malloc-internal.h +++ b/malloc/malloc-internal.h @@ -74,24 +74,4 @@ void __malloc_fork_unlock_child (void) attribute_hidden; /* Called as part of the thread shutdown sequence. */ void __malloc_arena_thread_freeres (void) attribute_hidden; -/* Set *RESULT to LEFT * RIGHT. Return true if the multiplication - overflowed. */ -static inline bool -check_mul_overflow_size_t (size_t left, size_t right, size_t *result) -{ -#if __GNUC__ >= 5 - return __builtin_mul_overflow (left, right, result); -#else - /* size_t is unsigned so the behavior on overflow is defined. */ - *result = left * right; - size_t half_size_t = ((size_t) 1) << (8 * sizeof (size_t) / 2); - if (__glibc_unlikely ((left | right) >= half_size_t)) - { - if (__glibc_unlikely (right != 0 && *result / right != left)) - return true; - } - return false; -#endif -} - #endif /* _MALLOC_INTERNAL_H */ diff --git a/malloc/reallocarray.c b/malloc/reallocarray.c index 319eccd21f..4905dc6e4b 100644 --- a/malloc/reallocarray.c +++ b/malloc/reallocarray.c @@ -18,19 +18,18 @@ #include #include -#include +#include void * __libc_reallocarray (void *optr, size_t nmemb, size_t elem_size) { size_t bytes; - if (check_mul_overflow_size_t (nmemb, elem_size, &bytes)) + if (__builtin_mul_overflow (nmemb, elem_size, &bytes)) { __set_errno (ENOMEM); return 0; } - else - return realloc (optr, bytes); + return realloc (optr, bytes); } libc_hidden_def (__libc_reallocarray) diff --git a/support/blob_repeat.c b/support/blob_repeat.c index 718846d81d..daa1b7fd96 100644 --- a/support/blob_repeat.c +++ b/support/blob_repeat.c @@ -34,26 +34,6 @@ optimization because mappings carry a lot of overhead. */ static const size_t maximum_small_size = 4 * 1024 * 1024; -/* Set *RESULT to LEFT * RIGHT. Return true if the multiplication - overflowed. See . */ -static inline bool -check_mul_overflow_size_t (size_t left, size_t right, size_t *result) -{ -#if __GNUC__ >= 5 - return __builtin_mul_overflow (left, right, result); -#else - /* size_t is unsigned so the behavior on overflow is defined. */ - *result = left * right; - size_t half_size_t = ((size_t) 1) << (8 * sizeof (size_t) / 2); - if (__glibc_unlikely ((left | right) >= half_size_t)) - { - if (__glibc_unlikely (right != 0 && *result / right != left)) - return true; - } - return false; -#endif -} - /* Internal helper for fill. */ static void fill0 (char *target, const char *element, size_t element_size, @@ -138,8 +118,8 @@ minimum_stride_size (size_t page_size, size_t element_size) common multiple, it appears only once. Therefore, shift one factor. */ size_t multiple; - if (check_mul_overflow_size_t (page_size >> common_zeros, element_size, - &multiple)) + if (__builtin_mul_overflow (page_size >> common_zeros, element_size, + &multiple)) return 0; return multiple; } @@ -275,7 +255,7 @@ support_blob_repeat_allocate (const void *element, size_t element_size, size_t count) { size_t total_size; - if (check_mul_overflow_size_t (element_size, count, &total_size)) + if (__builtin_mul_overflow (element_size, count, &total_size)) { errno = EOVERFLOW; return (struct support_blob_repeat) { 0 }; From patchwork Fri Dec 28 14:13:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 154606 Delivered-To: patch@linaro.org Received: by 2002:a2e:299d:0:0:0:0:0 with SMTP id p29-v6csp8064352ljp; Fri, 28 Dec 2018 06:13:45 -0800 (PST) X-Google-Smtp-Source: AFSGD/V6x4kfC3KbmGTP6YvOQY5C9diSVRI3soEejMsGEB7tZfegg4ZRCmaOb+bhKnrAhromN4Qv X-Received: by 2002:a62:4e83:: with SMTP id c125mr28472452pfb.101.1546006425734; Fri, 28 Dec 2018 06:13:45 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1546006425; cv=none; d=google.com; s=arc-20160816; b=FMbvzQ8+KvAjlk4Ws/AY1DgBv6gaboPqfVqZrGbvZOVfemZpxrS0kUe3uMrP1iQDlE AAYgaXKfIDd/y2U+FiWEPnr6dXVmut1ukLWjS3Otnyv6zOBK3DGiQf0rN+bHsrTexvjH hE3tUR9X2edI2Z9U+iWsNQ3N/um+DvVAj5cG7v1dJREKCS3jDk3STMAy5vv/wD7AqNT/ j7PkoRYzdEmZaPrpOoo2fnrfUF5KJa3XsU9GEKKXPhbqZLMAzEzXW2e4hK+L61rqsuzL JrUG1i3yN5n474pUykejk12GnPiWAPEWSv/P48y3QcQcPidD4uk1VWiERLa4prmYoiAs ES3w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:to:from :dkim-signature:delivered-to:sender:list-help:list-post:list-archive :list-subscribe:list-unsubscribe:list-id:precedence:mailing-list :dkim-signature:domainkey-signature; bh=Z0AyZnrIHYQRPwxbBl8gsX44PL9dvKCc0okt21Dj1Ws=; b=COziA+lxgxqg6SHTdb1146/nCUE+779W+4oKbO1LZy1/l29SPvN22xhGrVUWe27efi EB12O4CAyzPS+uk4Z0zli8zP1gfwhrqmfPCUQ9WSuwYfUf0rhPbWlRBwlLwLJOkVatUQ TNiE+WEneLtIhuJx8vWBRe7EmOJ0w9WbVrrEiyzsj5Z95vb5KBPzSPgPcISj2Maif1H/ mDsj5iF7TNAiftnswCRopNeuUPLg57lmZvwpDaV+JyjYhQetEYr2mhge95yqJ0JzIXhU tLIkzbpRHpbuZsP8Jv2lUr4EQ3XI47rDobc6dqUgh3VYSclaq7RbWpaKoVpsIeMZTkot 7RdQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=kBdl97wq; dkim=pass header.i=@linaro.org header.s=google header.b=H8dconWS; spf=pass (google.com: domain of libc-alpha-return-98844-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-98844-patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id s73si1146109pfs.54.2018.12.28.06.13.45 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 28 Dec 2018 06:13:45 -0800 (PST) Received-SPF: pass (google.com: domain of libc-alpha-return-98844-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=kBdl97wq; dkim=pass header.i=@linaro.org header.s=google header.b=H8dconWS; spf=pass (google.com: domain of libc-alpha-return-98844-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-98844-patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:in-reply-to :references; q=dns; s=default; b=sqTjIgpGvgmF6ppc5uCc3yuHgQzIrpD whRGzMwtdaGfsnzEgqXowM5I8dWjWkq94zd3cPnBpBtVZTehpr1JwYrI65Eono0+ RLybWAe49pHm2tH2otw0VovRAWGDmk4D2ML+s8i3y2OQ9kr0BVs+97lGD6E1GaSq G7YWm6sGZkZE= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:in-reply-to :references; s=default; bh=6Q8+Xu7bYcwqe1W1Zh3DilU7TzU=; b=kBdl9 7wq0xnmHHMMbH95gi1OK06i8Taz+E1KbcZc9XlsM6LyXejHlP/GFQ6LfNkpErv54 vTG4cI9E8CaslbhJ7+81Wsxfc8FKlZqFf4SGEXNSf8QMEYhodcJLhTh2ByLtY4z4 eO5OkZa0oaSv/kWS1PzKZebxnnY68i2xjgquvM= Received: (qmail 117097 invoked by alias); 28 Dec 2018 14:13:35 -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 116941 invoked by uid 89); 28 Dec 2018 14:13:33 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=victim, play, consideration, expectation X-HELO: mail-qk1-f194.google.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:subject:date:message-id:in-reply-to:references; bh=Z0AyZnrIHYQRPwxbBl8gsX44PL9dvKCc0okt21Dj1Ws=; b=H8dconWSETwOdLPndjy3EBqZPPWQa+7ZrdNYmkob00GMAKUrLFjLLzBwAN1sdCjnvE 4PLP3hgNDVtJBi3JyVXkIyRZ4fAuYrQhguevN6oGXEKEV3NRonVDKCwg7TkukmTHzLUv Q8WC7x7YmGuD4jdM8rryASuAJV3S2fL+alW/w= Return-Path: From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH v2 2/2] malloc: make malloc fail with requests larger than PTRDIFF_MAX Date: Fri, 28 Dec 2018 12:13:16 -0200 Message-Id: <20181228141316.25952-2-adhemerval.zanella@linaro.org> In-Reply-To: <20181228141316.25952-1-adhemerval.zanella@linaro.org> References: <20181228141316.25952-1-adhemerval.zanella@linaro.org> Changes from previous version: - Fix wording on NEWS entry. - Added static assert to check for PTRDIFF_MAX == SIZE_MAX / 2. - Remove padsize check, requested size after aligning and padding are checked against PTRDIFF_MAX. This does not guarantee that sysmalloc will eventually issue an request larger than PTRDIFF_MAX. One option to enforce it is to either add the PTRDIFF_MAX check on mmap or create an internal mmap implementation to enforce it. -- As discussed previously on libc-alpha [1], this patch follows up the idea and add both the __attribute_alloc_size__ on malloc functions (malloc, calloc, realloc, reallocarray, valloc, pvalloc, memaling, and posix_memalign) and limit maximum requested allocation size to up PTRDIFF_MAX (taking in consideration internal padding and alignment). This aligns glibc with gcc expected size defined by default warning -Walloc-size-larger-than value which warns for allocation larger than PTRDIFF_MAX. It also aligns with gcc expectation regarding libc and expected size, such as described in PR#67999 [2] and previously discussed ISO C11 issues [3] on libc-alpha. >From the RFC thread [4] and previous discussion, it seems that consensus is only to limit such requested size for malloc functions, not system allocation one (mmap, sbrk, etc.). The implementation changes checked_request2size to check for both overflow and maximum object size up to PTRDIFF_MAX. No additional checks are done on sysmalloc, so it can still issues mmap with values larger than PTRDIFF_T depending of requested size. Checked on x86_64-linux-gnu and i686-linux-gnu. [BZ #23741] * malloc/hooks.c (malloc_check, realloc_check): Use __builtin_add_overflow on overflow check and adapt to checked_request2size change. * malloc/malloc.c (__libc_malloc, __libc_realloc, _mid_memalign, __libc_pvalloc, __libc_calloc, _int_memalign): Limit maximum allocation size to PTRDIFF_MAX. (REQUEST_OUT_OF_RANGE): Remove macro. (checked_request2size): Change to inline function, use __builtin_add_overflow for overflow check and limit maximum requested size to PTRDIFF_MAX. (__libc_malloc, __libc_realloc, _int_malloc, _int_memalign): Limit maximum allocation size to PTRDIFF_MAX. (_mid_memalign): Rely on _int_memalign call for overflow check. (__libc_pvalloc): Use __builtin_add_overflow on overflow check. (__libc_calloc): Use __builtin_mul_overflow for overflow check and limit maximum requested size to PTRDIFF_MAX. * malloc/malloc.h (malloc, calloc, realloc, reallocarray, memalign, valloc, pvalloc): Add __attribute_alloc_size__. * stdlib/stdlib.h (malloc, realloc, reallocarray, valloc, posix_memalign): Likewise. * malloc/tst-malloc-too-large.c (do_test): Add check for allocation larger than PTRDIFF_MAX. * malloc/tst-memalign.c (do_test): Disable -Walloc-size-larger-than= around tests of malloc with negative sizes. * malloc/tst-posix_memalign.c (do_test): Likewise. * malloc/tst-pvalloc.c (do_test): Likewise. * malloc/tst-valloc.c (do_test): Likewise. * malloc/tst-reallocarray.c (do_test): Replace call to reallocarray with resulting size allocation larger than PTRDIFF_MAX with reallocarray_nowarn. (reallocarray_nowarn): New function. * NEWS: Mention the malloc function semantic change. [1] https://sourceware.org/ml/libc-alpha/2018-11/msg00223.html [2] https://gcc.gnu.org/bugzilla//show_bug.cgi?id=67999 [3] https://sourceware.org/ml/libc-alpha/2011-12/msg00066.html [4] https://sourceware.org/ml/libc-alpha/2018-11/msg00224.html --- ChangeLog | 34 ++++++++++ NEWS | 6 ++ malloc/hooks.c | 18 +++-- malloc/malloc.c | 121 ++++++++++++++++------------------ malloc/malloc.h | 17 +++-- malloc/tst-malloc-too-large.c | 10 +++ malloc/tst-memalign.c | 10 +++ malloc/tst-posix_memalign.c | 10 +++ malloc/tst-pvalloc.c | 10 +++ malloc/tst-reallocarray.c | 27 ++++++-- malloc/tst-valloc.c | 10 +++ stdlib/stdlib.h | 13 ++-- 12 files changed, 198 insertions(+), 88 deletions(-) -- 2.17.1 diff --git a/NEWS b/NEWS index cd29ec7c81..67dd692b73 100644 --- a/NEWS +++ b/NEWS @@ -68,6 +68,12 @@ Deprecated and removed features, and other changes affecting compatibility: used by the Linux kernel. This affects the size and layout of those structures. +* Memory allocation functions malloc, calloc, realloc, reallocarray, valloc, + pvalloc, memalign, and posix_memalign fail now with total object size + larger than PTRDIFF_MAX. This is to avoid potential undefined behavior with + pointer subtraction within the allocated object, where results might + overflow the ptrdiff_t type. + Changes to build and runtime requirements: * Python 3.4 or later is required to build the GNU C Library. diff --git a/malloc/hooks.c b/malloc/hooks.c index ae7305b036..c1deb9edf3 100644 --- a/malloc/hooks.c +++ b/malloc/hooks.c @@ -226,8 +226,9 @@ static void * malloc_check (size_t sz, const void *caller) { void *victim; + size_t nb; - if (sz + 1 == 0) + if (__builtin_add_overflow (sz, 1, &nb)) { __set_errno (ENOMEM); return NULL; @@ -235,7 +236,7 @@ malloc_check (size_t sz, const void *caller) __libc_lock_lock (main_arena.mutex); top_check (); - victim = _int_malloc (&main_arena, sz + 1); + victim = _int_malloc (&main_arena, nb); __libc_lock_unlock (main_arena.mutex); return mem2mem_check (victim, sz); } @@ -268,8 +269,9 @@ realloc_check (void *oldmem, size_t bytes, const void *caller) INTERNAL_SIZE_T nb; void *newmem = 0; unsigned char *magic_p; + size_t rb; - if (bytes + 1 == 0) + if (__builtin_add_overflow (bytes, 1, &rb)) { __set_errno (ENOMEM); return NULL; @@ -289,7 +291,11 @@ realloc_check (void *oldmem, size_t bytes, const void *caller) malloc_printerr ("realloc(): invalid pointer"); const INTERNAL_SIZE_T oldsize = chunksize (oldp); - checked_request2size (bytes + 1, nb); + if (!checked_request2size (rb, &nb)) + { + __set_errno (ENOMEM); + return NULL; + } __libc_lock_lock (main_arena.mutex); if (chunk_is_mmapped (oldp)) @@ -308,7 +314,7 @@ realloc_check (void *oldmem, size_t bytes, const void *caller) { /* Must alloc, copy, free. */ top_check (); - newmem = _int_malloc (&main_arena, bytes + 1); + newmem = _int_malloc (&main_arena, rb); if (newmem) { memcpy (newmem, oldmem, oldsize - 2 * SIZE_SZ); @@ -320,8 +326,6 @@ realloc_check (void *oldmem, size_t bytes, const void *caller) else { top_check (); - INTERNAL_SIZE_T nb; - checked_request2size (bytes + 1, nb); newmem = _int_realloc (&main_arena, oldp, oldsize, nb); } diff --git a/malloc/malloc.c b/malloc/malloc.c index c33709e966..21a117bd6b 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -1187,17 +1187,6 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ((uintptr_t)(MALLOC_ALIGNMENT == 2 * SIZE_SZ ? (p) : chunk2mem (p)) \ & MALLOC_ALIGN_MASK) - -/* - Check if a request is so large that it would wrap around zero when - padded and aligned. To simplify some other code, the bound is made - low enough so that adding MINSIZE will also not wrap around zero. - */ - -#define REQUEST_OUT_OF_RANGE(req) \ - ((unsigned long) (req) >= \ - (unsigned long) (INTERNAL_SIZE_T) (-2 * MINSIZE)) - /* pad request bytes into a usable size -- internal version */ #define request2size(req) \ @@ -1205,21 +1194,27 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ MINSIZE : \ ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) -/* Same, except also perform an argument and result check. First, we check - that the padding done by request2size didn't result in an integer - overflow. Then we check (using REQUEST_OUT_OF_RANGE) that the resulting - size isn't so large that a later alignment would lead to another integer - overflow. */ -#define checked_request2size(req, sz) \ -({ \ - (sz) = request2size (req); \ - if (((sz) < (req)) \ - || REQUEST_OUT_OF_RANGE (sz)) \ - { \ - __set_errno (ENOMEM); \ - return 0; \ - } \ -}) +/* Check if REQ overflows when padded and aligned and if the resulting value + is less than PTRDIFF_T. Returns TRUE and the requested size or MINSIZE in + case the value is less than MINSIZE on SZ or false if any of the previous + check fail. */ +static inline bool +checked_request2size (size_t req, size_t *sz) __nonnull (1) +{ + size_t ret; + if (__glibc_unlikely (__builtin_add_overflow (req, + SIZE_SZ + MALLOC_ALIGN_MASK, + &ret))) + return false; + + ret = ret < MINSIZE ? MINSIZE : ret & ~MALLOC_ALIGN_MASK; + if (__glibc_unlikely (ret > PTRDIFF_MAX)) + return false; + + *sz = ret; + return true; +} + /* --------------- Physical chunk operations --------------- @@ -3109,6 +3104,9 @@ __libc_malloc (size_t bytes) mstate ar_ptr; void *victim; + _Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2, + "PTRDIFF_MAX is not more than half of SIZE_MAX"); + void *(*hook) (size_t, const void *) = atomic_forced_read (__malloc_hook); if (__builtin_expect (hook != NULL, 0)) @@ -3116,7 +3114,11 @@ __libc_malloc (size_t bytes) #if USE_TCACHE /* int_free also calls request2size, be careful to not pad twice. */ size_t tbytes; - checked_request2size (bytes, tbytes); + if (!checked_request2size (bytes, &tbytes)) + { + __set_errno (ENOMEM); + return NULL; + } size_t tc_idx = csize2tidx (tbytes); MAYBE_INIT_TCACHE (); @@ -3253,7 +3255,11 @@ __libc_realloc (void *oldmem, size_t bytes) && !DUMPED_MAIN_ARENA_CHUNK (oldp)) malloc_printerr ("realloc(): invalid pointer"); - checked_request2size (bytes, nb); + if (!checked_request2size (bytes, &nb)) + { + __set_errno (ENOMEM); + return NULL; + } if (chunk_is_mmapped (oldp)) { @@ -3363,13 +3369,6 @@ _mid_memalign (size_t alignment, size_t bytes, void *address) return 0; } - /* Check for overflow. */ - if (bytes > SIZE_MAX - alignment - MINSIZE) - { - __set_errno (ENOMEM); - return 0; - } - /* Make sure alignment is power of 2. */ if (!powerof2 (alignment)) @@ -3429,14 +3428,16 @@ __libc_pvalloc (size_t bytes) void *address = RETURN_ADDRESS (0); size_t pagesize = GLRO (dl_pagesize); - size_t rounded_bytes = ALIGN_UP (bytes, pagesize); - - /* Check for overflow. */ - if (bytes > SIZE_MAX - 2 * pagesize - MINSIZE) + size_t rounded_bytes; + /* ALIGN_UP with overflow check. */ + if (__glibc_unlikely (__builtin_add_overflow (bytes, + pagesize - 1, + &rounded_bytes))) { __set_errno (ENOMEM); return 0; } + rounded_bytes = rounded_bytes & -(pagesize - 1); return _mid_memalign (pagesize, rounded_bytes, address); } @@ -3446,30 +3447,24 @@ __libc_calloc (size_t n, size_t elem_size) { mstate av; mchunkptr oldtop, p; - INTERNAL_SIZE_T bytes, sz, csz, oldtopsize; + INTERNAL_SIZE_T sz, csz, oldtopsize; void *mem; unsigned long clearsize; unsigned long nclears; INTERNAL_SIZE_T *d; + ptrdiff_t bytes; - /* size_t is unsigned so the behavior on overflow is defined. */ - bytes = n * elem_size; -#define HALF_INTERNAL_SIZE_T \ - (((INTERNAL_SIZE_T) 1) << (8 * sizeof (INTERNAL_SIZE_T) / 2)) - if (__builtin_expect ((n | elem_size) >= HALF_INTERNAL_SIZE_T, 0)) + if (__glibc_unlikely (__builtin_mul_overflow (n, elem_size, &bytes))) { - if (elem_size != 0 && bytes / elem_size != n) - { - __set_errno (ENOMEM); - return 0; - } + __set_errno (ENOMEM); + return NULL; } + sz = bytes; void *(*hook) (size_t, const void *) = atomic_forced_read (__malloc_hook); if (__builtin_expect (hook != NULL, 0)) { - sz = bytes; mem = (*hook)(sz, RETURN_ADDRESS (0)); if (mem == 0) return 0; @@ -3477,8 +3472,6 @@ __libc_calloc (size_t n, size_t elem_size) return memset (mem, 0, sz); } - sz = bytes; - MAYBE_INIT_TCACHE (); if (SINGLE_THREAD_P) @@ -3625,12 +3618,16 @@ _int_malloc (mstate av, size_t bytes) Convert request size to internal form by adding SIZE_SZ bytes overhead plus possibly more to obtain necessary alignment and/or to obtain a size of at least MINSIZE, the smallest allocatable - size. Also, checked_request2size traps (returning 0) request sizes + size. Also, checked_request2size returns false for request sizes that are so large that they wrap around zero when padded and aligned. */ - checked_request2size (bytes, nb); + if (!checked_request2size (bytes, &nb)) + { + __set_errno (ENOMEM); + return NULL; + } /* There are no usable arenas. Fall back to sysmalloc to get a chunk from mmap. */ @@ -4743,21 +4740,17 @@ _int_memalign (mstate av, size_t alignment, size_t bytes) - checked_request2size (bytes, nb); + if (!checked_request2size (bytes, &nb)) + { + __set_errno (ENOMEM); + return NULL; + } /* Strategy: find a spot within that chunk that meets the alignment request, and then possibly free the leading and trailing space. */ - - /* Check for overflow. */ - if (nb > SIZE_MAX - alignment - MINSIZE) - { - __set_errno (ENOMEM); - return 0; - } - /* Call malloc with worst case padding to hit alignment. */ m = (char *) (_int_malloc (av, nb + alignment + MINSIZE)); diff --git a/malloc/malloc.h b/malloc/malloc.h index 3e7c447be1..d3c4841f11 100644 --- a/malloc/malloc.h +++ b/malloc/malloc.h @@ -35,11 +35,12 @@ __BEGIN_DECLS /* Allocate SIZE bytes of memory. */ -extern void *malloc (size_t __size) __THROW __attribute_malloc__ __wur; +extern void *malloc (size_t __size) __THROW __attribute_malloc__ + __attribute_alloc_size__ ((1)) __wur; /* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ extern void *calloc (size_t __nmemb, size_t __size) -__THROW __attribute_malloc__ __wur; +__THROW __attribute_malloc__ __attribute_alloc_size__ ((1, 2)) __wur; /* Re-allocate the previously allocated block in __ptr, making the new block SIZE bytes long. */ @@ -47,7 +48,7 @@ __THROW __attribute_malloc__ __wur; the same pointer that was passed to it, aliasing needs to be allowed between objects pointed by the old and new pointers. */ extern void *realloc (void *__ptr, size_t __size) -__THROW __attribute_warn_unused_result__; +__THROW __attribute_warn_unused_result__ __attribute_alloc_size__ ((2)); /* Re-allocate the previously allocated block in PTR, making the new block large enough for NMEMB elements of SIZE bytes each. */ @@ -55,21 +56,23 @@ __THROW __attribute_warn_unused_result__; the same pointer that was passed to it, aliasing needs to be allowed between objects pointed by the old and new pointers. */ extern void *reallocarray (void *__ptr, size_t __nmemb, size_t __size) -__THROW __attribute_warn_unused_result__; +__THROW __attribute_warn_unused_result__ __attribute_alloc_size__ ((2, 3)); /* Free a block allocated by `malloc', `realloc' or `calloc'. */ extern void free (void *__ptr) __THROW; /* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ extern void *memalign (size_t __alignment, size_t __size) -__THROW __attribute_malloc__ __wur; +__THROW __attribute_malloc__ __attribute_alloc_size__ ((2)) __wur; /* Allocate SIZE bytes on a page boundary. */ -extern void *valloc (size_t __size) __THROW __attribute_malloc__ __wur; +extern void *valloc (size_t __size) __THROW __attribute_malloc__ + __attribute_alloc_size__ ((1)) __wur; /* Equivalent to valloc(minimum-page-that-holds(n)), that is, round up __size to nearest pagesize. */ -extern void *pvalloc (size_t __size) __THROW __attribute_malloc__ __wur; +extern void *pvalloc (size_t __size) __THROW __attribute_malloc__ + __attribute_alloc_size__ ((1)) __wur; /* Underlying allocation function; successive calls should return contiguous pieces of memory. */ diff --git a/malloc/tst-malloc-too-large.c b/malloc/tst-malloc-too-large.c index 10fb136528..ca41827a2a 100644 --- a/malloc/tst-malloc-too-large.c +++ b/malloc/tst-malloc-too-large.c @@ -226,6 +226,16 @@ do_test (void) test_large_aligned_allocations (SIZE_MAX - i); } + /* Allocation larger than PTRDIFF_MAX does play well with C standard, + since pointer subtraction within the object might overflow ptrdiff_t + resulting in undefined behavior. To prevent it malloc function fail + for such allocations. */ + for (size_t i = 0; i <= FOURTEEN_ON_BITS; i++) + { + test_large_allocations (PTRDIFF_MAX + i); + test_large_aligned_allocations (PTRDIFF_MAX + i); + } + #if __WORDSIZE >= 64 /* On 64-bit targets, we need to test a much wider range of too-large sizes, so we test at intervals of (1 << 50) that allocation sizes diff --git a/malloc/tst-memalign.c b/malloc/tst-memalign.c index 904bf9491d..3cba6dc7d3 100644 --- a/malloc/tst-memalign.c +++ b/malloc/tst-memalign.c @@ -21,6 +21,7 @@ #include #include #include +#include static int errors = 0; @@ -41,9 +42,18 @@ do_test (void) errno = 0; + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about too-large allocations; here we want to test + that they fail. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif /* An attempt to allocate a huge value should return NULL and set errno to ENOMEM. */ p = memalign (sizeof (void *), -1); +#if __GNUC_PREREQ (7, 0) + DIAG_POP_NEEDS_COMMENT; +#endif save = errno; diff --git a/malloc/tst-posix_memalign.c b/malloc/tst-posix_memalign.c index 81b4c05ef4..5c4188a7ac 100644 --- a/malloc/tst-posix_memalign.c +++ b/malloc/tst-posix_memalign.c @@ -21,6 +21,7 @@ #include #include #include +#include static int errors = 0; @@ -41,9 +42,18 @@ do_test (void) p = NULL; + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about too-large allocations; here we want to test + that they fail. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif /* An attempt to allocate a huge value should return ENOMEM and p should remain NULL. */ ret = posix_memalign (&p, sizeof (void *), -1); +#if __GNUC_PREREQ (7, 0) + DIAG_POP_NEEDS_COMMENT; +#endif if (ret != ENOMEM) merror ("posix_memalign (&p, sizeof (void *), -1) succeeded."); diff --git a/malloc/tst-pvalloc.c b/malloc/tst-pvalloc.c index aa391447ee..cd3b46d68b 100644 --- a/malloc/tst-pvalloc.c +++ b/malloc/tst-pvalloc.c @@ -21,6 +21,7 @@ #include #include #include +#include static int errors = 0; @@ -41,9 +42,18 @@ do_test (void) errno = 0; + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about too-large allocations; here we want to test + that they fail. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif /* An attempt to allocate a huge value should return NULL and set errno to ENOMEM. */ p = pvalloc (-1); +#if __GNUC_PREREQ (7, 0) + DIAG_POP_NEEDS_COMMENT; +#endif save = errno; diff --git a/malloc/tst-reallocarray.c b/malloc/tst-reallocarray.c index b0d80ebc58..784f77e7b0 100644 --- a/malloc/tst-reallocarray.c +++ b/malloc/tst-reallocarray.c @@ -20,6 +20,23 @@ #include #include #include +#include + +static void * +reallocarray_nowarn (void *ptr, size_t nmemb, size_t size) +{ +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about too-large allocations; here we want to test + that they fail. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif + void *ret = reallocarray (ptr, nmemb, size); +#if __GNUC_PREREQ (7, 0) + DIAG_POP_NEEDS_COMMENT; +#endif + return ret; +} + static int do_test (void) @@ -34,24 +51,24 @@ do_test (void) /* Test overflow detection. */ errno = 0; - ptr = reallocarray (NULL, max, 2); + ptr = reallocarray_nowarn (NULL, max, 2); TEST_VERIFY (!ptr); TEST_VERIFY (errno == ENOMEM); errno = 0; - ptr = reallocarray (NULL, 2, max); + ptr = reallocarray_nowarn (NULL, 2, max); TEST_VERIFY (!ptr); TEST_VERIFY (errno == ENOMEM); a = 65537; b = max/65537 + 1; errno = 0; - ptr = reallocarray (NULL, a, b); + ptr = reallocarray_nowarn (NULL, a, b); TEST_VERIFY (!ptr); TEST_VERIFY (errno == ENOMEM); errno = 0; - ptr = reallocarray (NULL, b, a); + ptr = reallocarray_nowarn (NULL, b, a); TEST_VERIFY (!ptr); TEST_VERIFY (errno == ENOMEM); @@ -97,7 +114,7 @@ do_test (void) /* Overflow should leave buffer untouched. */ errno = 0; - ptr2 = reallocarray (ptr, 2, ~(size_t)0); + ptr2 = reallocarray_nowarn (ptr, 2, ~(size_t)0); TEST_VERIFY (!ptr2); TEST_VERIFY (errno == ENOMEM); diff --git a/malloc/tst-valloc.c b/malloc/tst-valloc.c index ba57d9559a..b37edb6c74 100644 --- a/malloc/tst-valloc.c +++ b/malloc/tst-valloc.c @@ -21,6 +21,7 @@ #include #include #include +#include static int errors = 0; @@ -41,9 +42,18 @@ do_test (void) errno = 0; + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about too-large allocations; here we want to test + that they fail. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif /* An attempt to allocate a huge value should return NULL and set errno to ENOMEM. */ p = valloc (-1); +#if __GNUC_PREREQ (7, 0) + DIAG_POP_NEEDS_COMMENT; +#endif save = errno; diff --git a/stdlib/stdlib.h b/stdlib/stdlib.h index 870e02d904..4e55d82f4c 100644 --- a/stdlib/stdlib.h +++ b/stdlib/stdlib.h @@ -536,10 +536,11 @@ extern int lcong48_r (unsigned short int __param[7], #endif /* Use misc or X/Open. */ /* Allocate SIZE bytes of memory. */ -extern void *malloc (size_t __size) __THROW __attribute_malloc__ __wur; +extern void *malloc (size_t __size) __THROW __attribute_malloc__ + __attribute_alloc_size__ ((1)) __wur; /* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ extern void *calloc (size_t __nmemb, size_t __size) - __THROW __attribute_malloc__ __wur; + __THROW __attribute_malloc__ __attribute_alloc_size__ ((1, 2)) __wur; /* Re-allocate the previously allocated block in PTR, making the new block SIZE bytes long. */ @@ -547,7 +548,7 @@ extern void *calloc (size_t __nmemb, size_t __size) the same pointer that was passed to it, aliasing needs to be allowed between objects pointed by the old and new pointers. */ extern void *realloc (void *__ptr, size_t __size) - __THROW __attribute_warn_unused_result__; + __THROW __attribute_warn_unused_result__ __attribute_alloc_size__ ((2)); #ifdef __USE_MISC /* Re-allocate the previously allocated block in PTR, making the new @@ -556,7 +557,8 @@ extern void *realloc (void *__ptr, size_t __size) the same pointer that was passed to it, aliasing needs to be allowed between objects pointed by the old and new pointers. */ extern void *reallocarray (void *__ptr, size_t __nmemb, size_t __size) - __THROW __attribute_warn_unused_result__; + __THROW __attribute_warn_unused_result__ + __attribute_alloc_size__ ((2, 3)); #endif /* Free a block allocated by `malloc', `realloc' or `calloc'. */ @@ -569,7 +571,8 @@ extern void free (void *__ptr) __THROW; #if (defined __USE_XOPEN_EXTENDED && !defined __USE_XOPEN2K) \ || defined __USE_MISC /* Allocate SIZE bytes on a page boundary. The storage cannot be freed. */ -extern void *valloc (size_t __size) __THROW __attribute_malloc__ __wur; +extern void *valloc (size_t __size) __THROW __attribute_malloc__ + __attribute_alloc_size__ ((1)) __wur; #endif #ifdef __USE_XOPEN2K