From patchwork Thu Apr 14 12:22:51 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 610436 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3qm0Fj1t58z9sBl for ; Thu, 14 Apr 2016 22:23:37 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b=Xomb2jzz; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:subject:to:references:cc:from:message-id:date :mime-version:in-reply-to:content-type; q=dns; s=default; b=Gsgs R+1xFtzpVzSyaqYtGkDqDbKLFAtK6d8REtAlVUZz8wcMJUL70f4kFBZGNCK+iPqa zpcW+np7clT8MSZu19C6+6sWk0hYH9imuqsgZ7hITjVDaA2nt02MTtFJ1BfXy1Lz GkXfK9hBbNwpTTmYpCoBe9Sy7wyPgwmzd63ZbDU= 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:subject:to:references:cc:from:message-id:date :mime-version:in-reply-to:content-type; s=default; bh=3lmSCum67u suAwPrmAVZbDMLkpY=; b=Xomb2jzzcTEVXvxXeo7pYdKX+qilxV1GzcueL/uKmc Wqu6UpTjcJkhsZ4k4jDRMEa5nfA2RLlyJ6GNTgJZoUyySssJg02AuUWYYZKqyNBp bws/KTJdPDaSLHoXD00x7rA+tuOdADP/2aSXIYgdtuMKsEB38tViYWqy/5GMdzoa k= Received: (qmail 59088 invoked by alias); 14 Apr 2016 12:23:06 -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 58878 invoked by uid 89); 14 Apr 2016 12:23:04 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.9 required=5.0 tests=BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy= X-HELO: mx1.redhat.com Subject: Re: [PATCH] vfprintf: Fix memory with large width and precision [BZ #19931] To: eggert@cs.ucla.edu References: <570BC02D.2040901@redhat.com> <570BC840.6060807@cs.ucla.edu> Cc: libc-alpha@sourceware.org From: Florian Weimer Message-ID: <570F8B9B.6020402@redhat.com> Date: Thu, 14 Apr 2016 14:22:51 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.6.0 MIME-Version: 1.0 In-Reply-To: <570BC840.6060807@cs.ucla.edu> On 04/11/2016 05:52 PM, Paul Eggert wrote: > On 04/11/2016 08:18 AM, Florian Weimer wrote: >> + /* Deallocate any previously allocated buffer because it is >> + too small. */ >> + if (workstart != NULL) >> + { >> + free (workstart); >> + workstart = NULL; >> + } > > Other places in that function use this code instead: > > if (__glibc_unlikely (workstart != NULL)) > free (workstart); > workstart = NULL; > > Is there some reason to do things differently here? Here's an updated patch. Florian 2016-04-14 Florian Weimer [BZ #19931] * stdio-common/tst-vfprintf-width-prec.c: New file. * stdio-common/Makefile (tests): Add tst-vfprintf-width-prec. (tests-special): Add tst-vfprintf-width-prec-mem.out. (generated): Add mtrace-related files. (tst-vfprintf-width-prec-ENV): Set MALLOC_TRACE. (tst-%-mem.out): New pattern rule, replaces tst-printf-bz18872-mem.out. * stdio-common/vfprintf.c (vfprintf): When handling a precision specifier, deallocate any previously allocated work buffer. diff --git a/stdio-common/Makefile b/stdio-common/Makefile index cc79d34..6c597c1 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -58,16 +58,18 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \ scanf16 scanf17 tst-setvbuf1 tst-grouping bug23 bug24 \ bug-vfprintf-nargs tst-long-dbl-fphex tst-fphex-wide tst-sprintf3 \ bug25 tst-printf-round bug23-2 bug23-3 bug23-4 bug26 tst-fmemopen3 \ - tst-printf-bz18872 + tst-printf-bz18872 tst-vfprintf-width-prec test-srcs = tst-unbputc tst-printf ifeq ($(run-built-tests),yes) tests-special += $(objpfx)tst-unbputc.out $(objpfx)tst-printf.out \ $(objpfx)tst-printf-bz18872-mem.out \ - $(objpfx)tst-setvbuf1-cmp.out + $(objpfx)tst-setvbuf1-cmp.out \ + $(objpfx)tst-vfprintf-width-prec-mem.out generated += tst-printf-bz18872.c tst-printf-bz18872.mtrace \ - tst-printf-bz18872-mem.out + tst-printf-bz18872-mem.out \ + tst-vfprintf-width-prec.mtrace tst-vfprintf-width-prec-mem.out endif include ../Rules @@ -86,6 +88,8 @@ $(objpfx)tst-swprintf.out: $(gen-locales) endif tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace +tst-vfprintf-width-prec-ENV = \ + MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace $(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc $(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \ @@ -100,8 +104,8 @@ $(objpfx)tst-printf.out: tst-printf.sh $(objpfx)tst-printf $(objpfx)tst-printf-bz18872.c: tst-printf-bz18872.sh rm -f $@ && $(BASH) $^ > $@.new && mv $@.new $@ -$(objpfx)tst-printf-bz18872-mem.out: $(objpfx)tst-printf-bz18872.out - $(common-objpfx)malloc/mtrace $(objpfx)tst-printf-bz18872.mtrace > $@; \ +$(objpfx)tst-%-mem.out: $(objpfx)tst-%.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-$*.mtrace > $@; \ $(evaluate-test) CFLAGS-vfprintf.c = -Wno-uninitialized diff --git a/stdio-common/tst-vfprintf-width-prec.c b/stdio-common/tst-vfprintf-width-prec.c new file mode 100644 index 0000000..c2455e0 --- /dev/null +++ b/stdio-common/tst-vfprintf-width-prec.c @@ -0,0 +1,58 @@ +/* Test for memory leak with large width and precision. + Copyright (C) 1991-2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +static int +do_test (void) +{ + mtrace (); + int ret; + { + char *result; + ret = asprintf (&result, "%133000.133001x", 17); + if (ret < 0) + { + printf ("error: asprintf: %m\n"); + return 1; + } + free (result); + } + { + wchar_t *result = calloc (ret + 1, sizeof (wchar_t)); + if (result == NULL) + { + printf ("error: calloc (%d, %zu): %m", ret + 1, sizeof (wchar_t)); + return 1; + } + + ret = swprintf (result, ret + 1, L"%133000.133001x", 17); + if (ret < 0) + { + printf ("error: swprintf: %d (%m)\n", ret); + return 1; + } + free (result); + } + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c index 6829d4d..4a2aab1 100644 --- a/stdio-common/vfprintf.c +++ b/stdio-common/vfprintf.c @@ -1564,6 +1564,10 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) prec = 0; if (prec > width && prec > WORK_BUFFER_SIZE - 32) { + /* Deallocate any previously allocated buffer because it is + too small. */ + if (__glibc_unlikely (workstart != NULL)) + free (workstart); if (__glibc_unlikely (prec >= INT_MAX / sizeof (CHAR_T) - 32)) { __set_errno (EOVERFLOW);