From patchwork Tue Jan 14 02:02:31 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joseph Myers X-Patchwork-Id: 104723 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id BE5933858288 for ; Tue, 14 Jan 2025 02:05:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BE5933858288 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Faujb+tf X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 65E95385800F for ; Tue, 14 Jan 2025 02:02:37 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 65E95385800F Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 65E95385800F Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1736820157; cv=none; b=VfxNkYdj9jEB1aMxlTlWJ/T/n6XJbpFDtc0pKhw6O2ALSrgRL6v7DUmXBVGTIw5pvG2SuoX5zuwXZNCq+LY2314uItIHotiGSkHkGWrrokHoQRx1A4u3nSWesmmgQ7Ti9YFr3GEFZQouwhN/B5X9zkspHk+YXduD8Swe28YrfiI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1736820157; c=relaxed/simple; bh=6gjJcnJrjj0cLtjSfaZWnyn2fCr5Zd0Hx258er3GrcE=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=tPNlyIadC93aKVIUC9JO2sFf+6ZWBWKXVn+NXnVunn9lyd4ArnbqCUWVS7YaEGfTaq69ikAWALZpG/Cqnerom+tr1LVwWrCPSNvl5EqeuT6/H4/EzKikGegVqg20osyTA+bZAsXTXJ5S1K+c5hp+l1ywMa8gcuwWzXQxBahpvhA= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 65E95385800F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1736820157; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=P3eJpJnUb1+KMVQ0N+M3XtttQBM3pj7zVR7DkeILtms=; b=Faujb+tfESB1XJocZ6xqq7GCN8jLMge902i3nvxlsXeEwIFaFz8bGZK/Sk40IIUX7kDim8 boYcQBKFSZ3+ItLbwCvEAYdqnOweHnzWGAYu0Mag760zS7BFuiRvvNOZQhxnskwcoSZAln GVywi3F7V5MyllvsjYKPCq6FjaEqkzY= Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-228-LuDUjPskNKK1xxTWCVXOzw-1; Mon, 13 Jan 2025 21:02:35 -0500 X-MC-Unique: LuDUjPskNKK1xxTWCVXOzw-1 X-Mimecast-MFC-AGG-ID: LuDUjPskNKK1xxTWCVXOzw Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-385dcae001fso2204167f8f.1 for ; Mon, 13 Jan 2025 18:02:35 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736820154; x=1737424954; h=mime-version:references:message-id:in-reply-to:subject:to:from:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=P3eJpJnUb1+KMVQ0N+M3XtttQBM3pj7zVR7DkeILtms=; b=nQDAeSo4Cdt6X1f9EPptxyAxpZAqZb5Fz4ux8rJuPwUHWibFgGi4SJx4rB/8SFTxOL Yb7nyUO8N1w3Dn+XiWsP62LPSPdHiqMy+UEsRMtwsFR8j1JsGItujge8g/E+S9fyhGrD ugQwgMchFjJeXB7R7dQGTIfB9ah80Ku6dWG3hLaYFBfTIvKnN3OvhcYs/6wWOIKiLuyZ SXIhFLHAjK/TPOe6J5zvbWiifSRaPvgtzwM8iq4X5vGPbrKJbr7Fa68qP2FzKppmjaBy dbVKRwDO7yvXU02fiId2tRYb55NpKoaHB+D7WSQJsDxIQVzYWyC1k0Jv7LD4vDp1j/9/ aOmQ== X-Gm-Message-State: AOJu0YzAxpoINrp2vTneZU6WZnR7PP8ZdsrmuU03nEo36au2p0nNyUdN +ILzkPaszvvdyCntxoRNHskrqIvs3Sfnjg4tc+7EMsiWEbAoHh5RKP6zdbPKyRGRU2jusLOga+x 2vGwVbsJ8D8B604WCRW8Uy43UrZQXXZHzGQvZ1WuNrfYj2muXQ1w8REMjo0Y06qdH3E7F0bvLfT yVJACPdmbm1fzGMhJ6g6JRuD3xoyHM4r9HC+mER4EiEw== X-Gm-Gg: ASbGncsoAG3sL05yaalQ5/mAMqPSLfClruE8Q9J2HxTiRQnDx3rfhBCgdWwqvUxOALv hLVCXGgIr7/Dp5jhInGn566fypzzJvTN3dCrG/G4xQyvBMkE4JP8RBNdmjjWJbTCcjeYq8IqOjj h5vkk3M91p/1ZFG4v17nNPeLIUN8gFF6v1oRPvEdIXXpLzkzG1d2dWeKGdLRupMPjqio8tNWeKf JDilK4fnLHxEhPQuFThOOj5tF+82hCjOzmVt1CUDmdm2LjQZM2HlkP6Pv41iig/NtqzwVlMvnN/ spbTjF/UO+nh X-Received: by 2002:a05:6000:401e:b0:38a:4184:151c with SMTP id ffacd0b85a97d-38a8730ad01mr20093708f8f.27.1736820154227; Mon, 13 Jan 2025 18:02:34 -0800 (PST) X-Google-Smtp-Source: AGHT+IEuoJZloFAkGyBlb0nlOwQGxs23dRueq6FUSpLUt49CMQ0MkQVK9TuFfO5saFEf9Thh187Ncw== X-Received: by 2002:a05:6000:401e:b0:38a:4184:151c with SMTP id ffacd0b85a97d-38a8730ad01mr20093685f8f.27.1736820153727; Mon, 13 Jan 2025 18:02:33 -0800 (PST) Received: from digraph.polyomino.org.uk (digraph.polyomino.org.uk. [2001:8b0:bf73:93f7::51bb:e332]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-38a8e38d013sm13774269f8f.58.2025.01.13.18.02.32 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 18:02:33 -0800 (PST) Received: from jsm28 (helo=localhost) by digraph.polyomino.org.uk with local-esmtp (Exim 4.97) (envelope-from ) id 1tXWGF-0000000Cvjo-0Nag for libc-alpha@sourceware.org; Tue, 14 Jan 2025 02:02:31 +0000 Date: Tue, 14 Jan 2025 02:02:31 +0000 (UTC) From: Joseph Myers To: libc-alpha@sourceware.org Subject: [PATCH 1/6] Fix fflush after ungetc on input file (bug 5994) In-Reply-To: Message-ID: <3cbb9e5a-f404-7294-bdef-3ff606d8c8f4@redhat.com> References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: woN0STC3v-822fnL4Av4we8wbNRAD2MdNXHsz6viNdY_1736820154 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org As discussed in bug 5994 (plus duplicates), POSIX requires fflush after ungetc to discard pushed-back characters but preserve the file position indicator. For this purpose, each ungetc decrements the file position indicator by 1; it is unspecified after ungetc at the start of the file, and after ungetwc, so no special handling is needed for either of those cases. This is fixed with appropriate logic in _IO_new_file_sync. I haven't made any attempt to test or change things in this area for the "old" functions; the case of files using mmap is addressed in a subsequent patch (and there seem to be no problems in this area with files opened with fmemopen). Tested for x86_64. Reviewed-by: DJ Delorie --- libio/fileops.c | 5 +++ stdio-common/Makefile | 1 + stdio-common/tst-ungetc-fflush.c | 64 ++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 stdio-common/tst-ungetc-fflush.c diff --git a/libio/fileops.c b/libio/fileops.c index 775999deb3..27e1977eb6 100644 --- a/libio/fileops.c +++ b/libio/fileops.c @@ -799,6 +799,11 @@ _IO_new_file_sync (FILE *fp) if (fp->_IO_write_ptr > fp->_IO_write_base) if (_IO_do_flush(fp)) return EOF; delta = fp->_IO_read_ptr - fp->_IO_read_end; + if (_IO_in_backup (fp)) + { + _IO_switch_to_main_get_area (fp); + delta += fp->_IO_read_ptr - fp->_IO_read_end; + } if (delta != 0) { off64_t new_pos = _IO_SYSSEEK (fp, delta, 1); diff --git a/stdio-common/Makefile b/stdio-common/Makefile index bbdc1ff709..589b786f45 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -302,6 +302,7 @@ tests := \ tst-swscanf \ tst-tmpnam \ tst-ungetc \ + tst-ungetc-fflush \ tst-ungetc-leak \ tst-ungetc-nomem \ tst-unlockedio \ diff --git a/stdio-common/tst-ungetc-fflush.c b/stdio-common/tst-ungetc-fflush.c new file mode 100644 index 0000000000..a86d1fdb7f --- /dev/null +++ b/stdio-common/tst-ungetc-fflush.c @@ -0,0 +1,64 @@ +/* Test flushing input file after ungetc (bug 5994). + Copyright (C) 2025 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 +#include +#include + +int +do_test (void) +{ + char *filename = NULL; + int fd = create_temp_file ("tst-ungetc-fflush", &filename); + TEST_VERIFY_EXIT (fd != -1); + xclose (fd); + + /* Test as in bug 5994. */ + FILE *fp = xfopen (filename, "w"); + TEST_VERIFY_EXIT (fputs ("#include", fp) >= 0); + xfclose (fp); + fp = xfopen (filename, "r"); + TEST_COMPARE (fgetc (fp), '#'); + TEST_COMPARE (fgetc (fp), 'i'); + TEST_COMPARE (ungetc ('@', fp), '@'); + TEST_COMPARE (fflush (fp), 0); + TEST_COMPARE (lseek (fileno (fp), 0, SEEK_CUR), 1); + TEST_COMPARE (fgetc (fp), 'i'); + TEST_COMPARE (fgetc (fp), 'n'); + xfclose (fp); + + /* Test as in bug 12799 (duplicate of 5994). */ + fp = xfopen (filename, "w+"); + TEST_VERIFY_EXIT (fputs ("hello world", fp) >= 0); + rewind (fp); + TEST_VERIFY (fileno (fp) >= 0); + char buffer[10]; + TEST_COMPARE (fread (buffer, 1, 5, fp), 5); + TEST_COMPARE (fgetc (fp), ' '); + TEST_COMPARE (ungetc ('@', fp), '@'); + TEST_COMPARE (fflush (fp), 0); + TEST_COMPARE (fgetc (fp), ' '); + xfclose (fp); + + return 0; +} + +#include From patchwork Tue Jan 14 02:03:05 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joseph Myers X-Patchwork-Id: 104726 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8614B3857709 for ; Tue, 14 Jan 2025 02:07:37 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8614B3857709 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=PMshv1hG X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 14567385842A for ; Tue, 14 Jan 2025 02:03:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 14567385842A Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 14567385842A Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1736820192; cv=none; b=RrJhB6fQw2se4+TAf3UUZeaZ8Yy5l3jQSZYR0pUd4u0FPxaIRuFP060/3D1h8BE+qw1fbAPxyF/8BfQJkMQ8o078y/rYhmubmLKt4ZVaFtp0E34Edu0VULxILr0MIeWQxA8UsaJYjWNBjY97dICmxOkWE3P1w5W7kEqiG1mJu2Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1736820192; c=relaxed/simple; bh=eKBtwM6Zpm1iy2jnz8ibNxPqG0olxw6z+au8TeD2D0g=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=uKX1l9k4ifJPReApREj8uG2RY71niR4GBMXykA1Sk8tsqJqQwaWzTJh21KkO+JfX0XICJnSffm1u57wWZTxW1dHBfD8iHo0YtAIr1sQ6+6wuZ9omWcpiP76Diyun9Q+IW5TnfA41C9elfvhdbX7JfVwzplLIiAEcaJ+0t9IP5uA= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 14567385842A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1736820191; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=t3/GOv57K+MyFbq42b4mYJpKhCTtZmxQwSeQa1fTzF8=; b=PMshv1hGZhxgUV/tilVIKcpne6pd83Hi2k4waLpIoLaB8Cxeh3FZVGH/aR8Zd354h3T96s ox72B8WvyfYZuLInu1OUtjl+GHuyyh/a3R1VHTm0LKnwwU0O0DsCDWoamqhUu6eXSfFnPR +qWJBwMC7OWclLIomCVDSi6u2P80nY4= Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-427-IpTPNadlM3GtpDF7cECIZA-1; Mon, 13 Jan 2025 21:03:10 -0500 X-MC-Unique: IpTPNadlM3GtpDF7cECIZA-1 X-Mimecast-MFC-AGG-ID: IpTPNadlM3GtpDF7cECIZA Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-43582d49dacso33940165e9.2 for ; Mon, 13 Jan 2025 18:03:10 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736820189; x=1737424989; h=mime-version:references:message-id:in-reply-to:subject:to:from:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=t3/GOv57K+MyFbq42b4mYJpKhCTtZmxQwSeQa1fTzF8=; b=rzd2UpUtkwdJ1nwmFBgRhzAthKVmyMehmDFk/uBcFLpBPBU7VFoDTr1WUdKJ7ueRH1 TIZR16UsL2R+7q3AOg+gDBDlBtPcrldI2m87eZRuJcW+GslkwrrjDBM8v3NCGkdiAa2g +1xzZCFxam0bsntMMWWbhCddzMHmHwTqHClytkpskh6OK1P5VYamy7gIJYcaxebqxNRX 6Q2x3EyNv4BbbpeenaOqbkYvorAeqyTcSiSKNjiMXmepm67nK4p2l2yINPY7GL1N375L 5UcllKkawBrAs9fd/Eo//fZfB/8Zf2nfaZAeJgtnXa7pjJQkE11mj8X/CTd304z7t5vG 3etg== X-Gm-Message-State: AOJu0YwAY4+eN1C4iuyUlQZ1kBur4r7VO7txevYOk6NOP7KH6QVreEfF FPO2vsWGVVw4F6a8SQOpGXuWy3mG4Q8l5P8KeGDM8diCnqiC7GDcH//dvvhyHCUGH/qEts1+nVJ 3Mx/ZgJGsdELdzyB3x8siyzgw5o2iIt4I/Y4MgnSCnuWFfS4kNznjnSQ9vNfIt+i4M1/vS7L3p8 88TKRjtKsU92YjRwhulzsxOCKuUIHHtxloVlWtdmuEkg== X-Gm-Gg: ASbGncvXmOJeMOGYb8zW/pkqyYHtsofPy7EnQ7qi34qyRkIG1hL3deNk9xC9OsuK36W /08xe3KZ/XpNK9ckrEdAkW4bXr54C1fM9GggzFEdVlzsCFNfD+IyXsAN3OWS4xAcYli/nV9ZUPU AmCBoqJ2T1RCoDbc+ZZUuGiDOB+/zp1+RqFfrUrU9xN4iIcSnT81bvxzgTPKocs+Qey1tBYAXmf BWVVpjtoaQBidWg34dsokNezzsTIxxBeWyIgjQO32iUGgH005Sfa0NtdtDzJwql0AL/d784pYae UYAs9+n8E5Zd X-Received: by 2002:a5d:47c3:0:b0:386:3329:6a04 with SMTP id ffacd0b85a97d-38a8732c076mr22658199f8f.39.1736820188825; Mon, 13 Jan 2025 18:03:08 -0800 (PST) X-Google-Smtp-Source: AGHT+IFiO915BZQLGPAJFC+Z9J+g3GGXj3W3Kwbezz5Qr8L4cazTeDfZpKcxGI2tB8jPBbY1v849ZA== X-Received: by 2002:a5d:47c3:0:b0:386:3329:6a04 with SMTP id ffacd0b85a97d-38a8732c076mr22658165f8f.39.1736820187867; Mon, 13 Jan 2025 18:03:07 -0800 (PST) Received: from digraph.polyomino.org.uk (digraph.polyomino.org.uk. [2001:8b0:bf73:93f7::51bb:e332]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-38a8e37e36asm13225180f8f.5.2025.01.13.18.03.06 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 18:03:07 -0800 (PST) Received: from jsm28 (helo=localhost) by digraph.polyomino.org.uk with local-esmtp (Exim 4.97) (envelope-from ) id 1tXWGn-0000000CvkI-1EbI for libc-alpha@sourceware.org; Tue, 14 Jan 2025 02:03:05 +0000 Date: Tue, 14 Jan 2025 02:03:05 +0000 (UTC) From: Joseph Myers To: libc-alpha@sourceware.org Subject: [PATCH 2/6] Make fclose seek input file to right offset (bug 12724) In-Reply-To: Message-ID: <217b4e2c-4c71-678c-2827-41866c4012a8@redhat.com> References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 70qcg_IySMJyb5bU3aTTMSA-r7qwtWbYIykn_D1liOY_1736820189 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.2 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org As discussed in bug 12724 and required by POSIX, before an input file (based on an underlying seekable file descriptor) is closed, fclose is sometimes required to seek that file descriptor to the correct offset, so that any other file descriptors sharing the underlying open file description are left at that offset (as a motivating example, a script could call a sequence of commands each of which processes some data from (seekable) stdin using stdio; fclose needs to do this so that each successive command can read exactly the data not handled by previous commands), but glibc fails to do this. The precise POSIX wording has changed a few times; in the 2024 edition it's "If the file is not already at EOF, and the file is one capable of seeking, the file offset of the underlying open file description shall be set to the file position of the stream if the stream is the active handle to the underlying file description.". Add appropriate logic to _IO_new_file_close_it to handle this case. I haven't made any attempt to test or change things in this area for the "old" functions. Note that there was a previous attempt to fix bug 12724, reverted in commit eb6cbd249f4465b01f428057bf6ab61f5f0c07e3. The fix version here addresses the original test in that bug report without breaking the one given in a subsequent comment in that bug report (which works with glibc before the patch, but maybe was broken by the original fix that was reverted). The logic here tries to take care not to seek the file, even to its newly computed current offset, if at EOF / possibly not the active handle; even seeking to the current offset would be problematic because of a potential race (fclose computes the current offset, another thread or process with the active handle does its own seek, fclose does a seek (not permitted by POSIX in this case) that loses the effect of the seek on the active handle in another thread or process). There are tests included for various cases of being or not being the active handle, though there aren't tests for the potential race condition. Tested for x86_64. Reviewed-by: DJ Delorie --- libio/fileops.c | 43 +++++- stdio-common/Makefile | 1 + stdio-common/tst-fclose-offset.c | 225 +++++++++++++++++++++++++++++++ 3 files changed, 264 insertions(+), 5 deletions(-) create mode 100644 stdio-common/tst-fclose-offset.c diff --git a/libio/fileops.c b/libio/fileops.c index 27e1977eb6..358378431f 100644 --- a/libio/fileops.c +++ b/libio/fileops.c @@ -127,15 +127,48 @@ _IO_new_file_init (struct _IO_FILE_plus *fp) int _IO_new_file_close_it (FILE *fp) { - int write_status; + int flush_status = 0; if (!_IO_file_is_open (fp)) return EOF; if ((fp->_flags & _IO_NO_WRITES) == 0 && (fp->_flags & _IO_CURRENTLY_PUTTING) != 0) - write_status = _IO_do_flush (fp); - else - write_status = 0; + flush_status = _IO_do_flush (fp); + else if (fp->_fileno >= 0 + /* If this is the active handle, we must seek the + underlying open file description (possibly shared with + other file descriptors that remain open) to the correct + offset. But if this stream is in a state such that some + other handle might have become the active handle, then + (a) at the time it entered that state, the underlying + open file description had the correct offset, and (b) + seeking the underlying open file description, even to + its newly determined current offset, is not safe because + it can race with operations on a different active + handle. So check here for cases where it is necessary + to seek, while avoiding seeking in cases where it is + unsafe to do so. */ + && (_IO_in_backup (fp) + || (fp->_mode <= 0 && fp->_IO_read_ptr < fp->_IO_read_end) + || (_IO_vtable_offset (fp) == 0 + && fp->_mode > 0 && (fp->_wide_data->_IO_read_ptr + < fp->_wide_data->_IO_read_end)))) + { + off64_t o = _IO_SEEKOFF (fp, 0, _IO_seek_cur, 0); + if (o == EOF) + { + if (errno != ESPIPE) + flush_status = EOF; + } + else + { + if (_IO_in_backup (fp)) + o -= fp->_IO_save_end - fp->_IO_save_base; + flush_status = (_IO_SYSSEEK (fp, o, SEEK_SET) < 0 && errno != ESPIPE + ? EOF + : 0); + } + } _IO_unsave_markers (fp); @@ -160,7 +193,7 @@ _IO_new_file_close_it (FILE *fp) fp->_fileno = -1; fp->_offset = _IO_pos_BAD; - return close_status ? close_status : write_status; + return close_status ? close_status : flush_status; } libc_hidden_ver (_IO_new_file_close_it, _IO_file_close_it) diff --git a/stdio-common/Makefile b/stdio-common/Makefile index 589b786f45..b5f78c365b 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -234,6 +234,7 @@ tests := \ tst-bz11319-fortify2 \ tst-cookie \ tst-dprintf-length \ + tst-fclose-offset \ tst-fdopen \ tst-fdopen2 \ tst-ferror \ diff --git a/stdio-common/tst-fclose-offset.c b/stdio-common/tst-fclose-offset.c new file mode 100644 index 0000000000..a31de1117c --- /dev/null +++ b/stdio-common/tst-fclose-offset.c @@ -0,0 +1,225 @@ +/* Test offset of input file descriptor after close (bug 12724). + Copyright (C) 2025 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 + +#include +#include +#include +#include + +int +do_test (void) +{ + char *filename = NULL; + int fd = create_temp_file ("tst-fclose-offset", &filename); + TEST_VERIFY_EXIT (fd != -1); + + /* Test offset of open file description for output and input streams + after fclose, case from bug 12724. */ + + const char buf[] = "hello world"; + xwrite (fd, buf, sizeof buf); + TEST_COMPARE (lseek (fd, 1, SEEK_SET), 1); + int fd2 = xdup (fd); + FILE *f = fdopen (fd2, "w"); + TEST_VERIFY_EXIT (f != NULL); + TEST_COMPARE (fputc (buf[1], f), buf[1]); + xfclose (f); + errno = 0; + TEST_COMPARE (lseek (fd2, 0, SEEK_CUR), -1); + TEST_COMPARE (errno, EBADF); + TEST_COMPARE (lseek (fd, 0, SEEK_CUR), 2); + + /* Likewise for an input stream. */ + fd2 = xdup (fd); + f = fdopen (fd2, "r"); + TEST_VERIFY_EXIT (f != NULL); + TEST_COMPARE (fgetc (f), buf[2]); + xfclose (f); + errno = 0; + TEST_COMPARE (lseek (fd2, 0, SEEK_CUR), -1); + TEST_COMPARE (errno, EBADF); + TEST_COMPARE (lseek (fd, 0, SEEK_CUR), 3); + + /* Test offset of open file description for output and input streams + after fclose, case from comment on bug 12724 (failed after first + attempt at fixing that bug). This verifies that the offset is + not reset when there has been no input or output on the FILE* (in + that case, the FILE* might not be the active handle). */ + + TEST_COMPARE (lseek (fd, 0, SEEK_SET), 0); + xwrite (fd, buf, sizeof buf); + TEST_COMPARE (lseek (fd, 1, SEEK_SET), 1); + fd2 = xdup (fd); + f = fdopen (fd2, "w"); + TEST_VERIFY_EXIT (f != NULL); + TEST_COMPARE (lseek (fd, 4, SEEK_SET), 4); + xfclose (f); + errno = 0; + TEST_COMPARE (lseek (fd2, 0, SEEK_CUR), -1); + TEST_COMPARE (errno, EBADF); + TEST_COMPARE (lseek (fd, 0, SEEK_CUR), 4); + + /* Likewise for an input stream. */ + fd2 = xdup (fd); + f = fdopen (fd2, "r"); + TEST_VERIFY_EXIT (f != NULL); + TEST_COMPARE (lseek (fd, 4, SEEK_SET), 4); + xfclose (f); + errno = 0; + TEST_COMPARE (lseek (fd2, 0, SEEK_CUR), -1); + TEST_COMPARE (errno, EBADF); + TEST_COMPARE (lseek (fd, 0, SEEK_CUR), 4); + + /* Further cases without specific tests in bug 12724, to verify + proper operation of the rules about the offset only being set + when the stream is the active handle. */ + + /* Test offset set by fclose after fseek and fgetc. */ + TEST_COMPARE (lseek (fd, 0, SEEK_SET), 0); + fd2 = xdup (fd); + f = fdopen (fd2, "r"); + TEST_VERIFY_EXIT (f != NULL); + TEST_COMPARE (fseek (f, 1, SEEK_SET), 0); + TEST_COMPARE (fgetc (f), buf[1]); + xfclose (f); + errno = 0; + TEST_COMPARE (lseek (fd2, 0, SEEK_CUR), -1); + TEST_COMPARE (errno, EBADF); + TEST_COMPARE (lseek (fd, 0, SEEK_CUR), 2); + + /* Test offset not set by fclose after fseek and fgetc, if that + fgetc is at EOF (in which case the active handle might have + changed). */ + TEST_COMPARE (lseek (fd, 0, SEEK_SET), 0); + fd2 = xdup (fd); + f = fdopen (fd2, "r"); + TEST_VERIFY_EXIT (f != NULL); + TEST_COMPARE (fseek (f, sizeof buf, SEEK_SET), 0); + TEST_COMPARE (fgetc (f), EOF); + TEST_COMPARE (lseek (fd, 4, SEEK_SET), 4); + xfclose (f); + errno = 0; + TEST_COMPARE (lseek (fd2, 0, SEEK_CUR), -1); + TEST_COMPARE (errno, EBADF); + TEST_COMPARE (lseek (fd, 0, SEEK_CUR), 4); + + /* Test offset not set by fclose after fseek and fgetc and fflush + (active handle might have changed after fflush). */ + TEST_COMPARE (lseek (fd, 0, SEEK_SET), 0); + fd2 = xdup (fd); + f = fdopen (fd2, "r"); + TEST_VERIFY_EXIT (f != NULL); + TEST_COMPARE (fseek (f, 1, SEEK_SET), 0); + TEST_COMPARE (fgetc (f), buf[1]); + TEST_COMPARE (fflush (f), 0); + TEST_COMPARE (lseek (fd, 4, SEEK_SET), 4); + xfclose (f); + errno = 0; + TEST_COMPARE (lseek (fd2, 0, SEEK_CUR), -1); + TEST_COMPARE (errno, EBADF); + TEST_COMPARE (lseek (fd, 0, SEEK_CUR), 4); + + /* Test offset not set by fclose after fseek and fgetc, if the + stream is unbuffered (active handle might change at any + time). */ + TEST_COMPARE (lseek (fd, 0, SEEK_SET), 0); + fd2 = xdup (fd); + f = fdopen (fd2, "r"); + TEST_VERIFY_EXIT (f != NULL); + setbuf (f, NULL); + TEST_COMPARE (fseek (f, 1, SEEK_SET), 0); + TEST_COMPARE (fgetc (f), buf[1]); + TEST_COMPARE (lseek (fd, 4, SEEK_SET), 4); + xfclose (f); + errno = 0; + TEST_COMPARE (lseek (fd2, 0, SEEK_CUR), -1); + TEST_COMPARE (errno, EBADF); + TEST_COMPARE (lseek (fd, 0, SEEK_CUR), 4); + + /* Also test such cases with the stream in wide mode. */ + + /* Test offset set by fclose after fseek and fgetwc. */ + TEST_COMPARE (lseek (fd, 0, SEEK_SET), 0); + fd2 = xdup (fd); + f = fdopen (fd2, "r"); + TEST_VERIFY_EXIT (f != NULL); + TEST_COMPARE (fseek (f, 1, SEEK_SET), 0); + TEST_COMPARE (fgetwc (f), (wint_t) buf[1]); + xfclose (f); + errno = 0; + TEST_COMPARE (lseek (fd2, 0, SEEK_CUR), -1); + TEST_COMPARE (errno, EBADF); + TEST_COMPARE (lseek (fd, 0, SEEK_CUR), 2); + + /* Test offset not set by fclose after fseek and fgetwc, if that + fgetwc is at EOF (in which case the active handle might have + changed). */ + TEST_COMPARE (lseek (fd, 0, SEEK_SET), 0); + fd2 = xdup (fd); + f = fdopen (fd2, "r"); + TEST_VERIFY_EXIT (f != NULL); + TEST_COMPARE (fseek (f, sizeof buf, SEEK_SET), 0); + TEST_COMPARE (fgetwc (f), WEOF); + TEST_COMPARE (lseek (fd, 4, SEEK_SET), 4); + xfclose (f); + errno = 0; + TEST_COMPARE (lseek (fd2, 0, SEEK_CUR), -1); + TEST_COMPARE (errno, EBADF); + TEST_COMPARE (lseek (fd, 0, SEEK_CUR), 4); + + /* Test offset not set by fclose after fseek and fgetwc and fflush + (active handle might have changed after fflush). */ + TEST_COMPARE (lseek (fd, 0, SEEK_SET), 0); + fd2 = xdup (fd); + f = fdopen (fd2, "r"); + TEST_VERIFY_EXIT (f != NULL); + TEST_COMPARE (fseek (f, 1, SEEK_SET), 0); + TEST_COMPARE (fgetwc (f), (wint_t) buf[1]); + TEST_COMPARE (fflush (f), 0); + TEST_COMPARE (lseek (fd, 4, SEEK_SET), 4); + xfclose (f); + errno = 0; + TEST_COMPARE (lseek (fd2, 0, SEEK_CUR), -1); + TEST_COMPARE (errno, EBADF); + TEST_COMPARE (lseek (fd, 0, SEEK_CUR), 4); + + /* Test offset not set by fclose after fseek and fgetwc, if the + stream is unbuffered (active handle might change at any + time). */ + TEST_COMPARE (lseek (fd, 0, SEEK_SET), 0); + fd2 = xdup (fd); + f = fdopen (fd2, "r"); + TEST_VERIFY_EXIT (f != NULL); + setbuf (f, NULL); + TEST_COMPARE (fseek (f, 1, SEEK_SET), 0); + TEST_COMPARE (fgetwc (f), (wint_t) buf[1]); + TEST_COMPARE (lseek (fd, 4, SEEK_SET), 4); + xfclose (f); + errno = 0; + TEST_COMPARE (lseek (fd2, 0, SEEK_CUR), -1); + TEST_COMPARE (errno, EBADF); + TEST_COMPARE (lseek (fd, 0, SEEK_CUR), 4); + + return 0; +} + +#include From patchwork Tue Jan 14 02:03:31 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joseph Myers X-Patchwork-Id: 104724 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 00BB93857712 for ; Tue, 14 Jan 2025 02:06:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 00BB93857712 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=I0gxX+iJ X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 2D4473858C5F for ; Tue, 14 Jan 2025 02:03:37 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2D4473858C5F Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 2D4473858C5F Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1736820217; cv=none; b=QFeolPLFzwWlAECMzCr+VG8FgHziSrfZbPzL0+Y5VMVJmOBCekQz2NFwgPJuebsFxRL8ZX7htIUwXbNHuUIAodStC70DGYrA1atev2X0tn75CVtmpG/zRx8gb48I8Pn4iRvwTTAzFBVHq2pY01q9de1MI19NzkujZZcrdAr9XBY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1736820217; c=relaxed/simple; bh=O8kHjS0YXXsf0pzyNnZyeDT2fup4hnIdlyVABeddesg=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=bQfEraq3alKAU0N4boJsyU2X3dGRSgf3ylG0viN1kDX8e4fZbyNEqNLxILRgPGxK4YrY9cQR3hBB4IIJ14qTE4GyP4gNtB7D27pLGpV6nz/mBj+Cq5GWO/ATQ12PKtWFtSkuafcsIu9/kP5382l5xRON3uDBhHgHjZ+3JTvqhq8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2D4473858C5F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1736820216; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=VNPAuWtBSI6c9pHB3KZkfGnu4/+9ZJtNqWw1ON79ZYo=; b=I0gxX+iJQjIrXAoRYZpL73GXWYjYXByqATrM2bJUuCIL1nChhlkU/o3tNSPwapTD/Vt9sw KSYFaYMHri+kzmj/xZKI7SAxA6GlfpbNAOTxaNLyhTYO44dn9GTuBxPw28axqMoktMy3/T N+Q6KXoUMLO0qWMuYES2cjknxDbJVrg= Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-632-oic9olzFOheEave1T_AR8Q-1; Mon, 13 Jan 2025 21:03:35 -0500 X-MC-Unique: oic9olzFOheEave1T_AR8Q-1 X-Mimecast-MFC-AGG-ID: oic9olzFOheEave1T_AR8Q Received: by mail-wr1-f69.google.com with SMTP id ffacd0b85a97d-385ed79291eso2662242f8f.0 for ; Mon, 13 Jan 2025 18:03:35 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736820214; x=1737425014; h=mime-version:references:message-id:in-reply-to:subject:to:from:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=VNPAuWtBSI6c9pHB3KZkfGnu4/+9ZJtNqWw1ON79ZYo=; b=B8aKipZnfAT+M3mZ2tTb0C+N1KXO90/+0yckPUg6I+nn6eyFJnxprHX9BgwrUpneug 3SqLGN7zubLUDkchxKG/uMCs71e9bCVAu5SdLVZ35LWmc2sYMRwM2RRDd3d2gutcUc45 sZTh8GtSa0qA9fmagMJQ/4P0jwS4+sbbNnJbzxtlZpdqDVFQ0euDd+Ra2ck9gY/adZ60 SX/JWeOgTF/9qnTBGVWCoAov/ZPIxZYV/KcwN6pDrdOaMO40JQPAvmMfiu1fVgHL2j8O 4Wm2pNGNf4efxA7yBS5Gk5ht3UmRd+eFF0CJrKAKSN0oTtCco7S+xnmBXb6aP5ErmJAR Levg== X-Gm-Message-State: AOJu0YzbLcXtIsqechJ5kyi2FScjsYV++yiz54jtZUMD9tNCSuqaNjLD e6xmrXW/SV6OPmPky8S3eG5clsggtru4nr96e2UZ0EYx0CD5RLLG/r32+3EVfjolJHb0H4siDYq CO4HS05xBvzb8C6++V/Uy02537L5n2TG03EQCEjG/xzJUzBf0Y3G9DkPbhDJNdbQW4f0kIsU99M WH4pjwc53uEeWA5MtkoOoRmbJiHyCQ9nQniblmY2WJUA== X-Gm-Gg: ASbGncs+cq08XFO7cMQ8Ei5ubEA6EtcFeGqIL32IIkgwX6LciZ0ROEezQtz+P7FB8dp z2YLdjWaSCo21mTCUB3/DCd/3XBkN1SgQJE1U77RLUv3DIVQWJPgW4ysT9pJ2oqacQjiKygDvB6 P39ONTqQtLPn+1auaudWruO0amJyso5Ji8ySDhlafshaYMOGfYBHqg7l0263Hg54XTtT4lgs+wM 5laa8mHR46vv7hXAIXgtg+j37O9ohU2ruLeEVdwgk6BGoF1dpnTU5wi0AVzYoLw4WXnvDTnvZ2c 4/MQMjKna7iU X-Received: by 2002:a5d:6d0e:0:b0:38a:a117:3dbe with SMTP id ffacd0b85a97d-38aa1174168mr6190998f8f.21.1736820213857; Mon, 13 Jan 2025 18:03:33 -0800 (PST) X-Google-Smtp-Source: AGHT+IEKRYTI/v1SREouCd6coaomu46tbcjcZ1FvuOkYvnAq9O1MT/c/Gg3De2V5UvSCKI06I7ySFg== X-Received: by 2002:a5d:6d0e:0:b0:38a:a117:3dbe with SMTP id ffacd0b85a97d-38aa1174168mr6190978f8f.21.1736820213434; Mon, 13 Jan 2025 18:03:33 -0800 (PST) Received: from digraph.polyomino.org.uk (digraph.polyomino.org.uk. [2001:8b0:bf73:93f7::51bb:e332]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-38a8e38efeesm13770196f8f.62.2025.01.13.18.03.32 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 18:03:32 -0800 (PST) Received: from jsm28 (helo=localhost) by digraph.polyomino.org.uk with local-esmtp (Exim 4.97) (envelope-from ) id 1tXWHD-0000000CvlA-0D7M for libc-alpha@sourceware.org; Tue, 14 Jan 2025 02:03:31 +0000 Date: Tue, 14 Jan 2025 02:03:31 +0000 (UTC) From: Joseph Myers To: libc-alpha@sourceware.org Subject: [PATCH 3/6] Make fflush (NULL) flush input files (bug 32369) In-Reply-To: Message-ID: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: N94328bI_TBxMspzSwuIIW-iNaFuAs9yObTKiNbaRd0_1736820214 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org As discussed in bug 32369 and required by POSIX, the POSIX feature fflush (NULL) should flush input files, not just output files. The POSIX requirement is that "fflush() shall perform this flushing action on all streams for which the behavior is defined above", and the definition for input files is for "a stream open for reading with an underlying file description, if the file is not already at EOF, and the file is one capable of seeking". Implement this requirement in glibc. (The underlying flushing implementation is what deals with avoiding errors for seeking on an unseekable file.) Tested for x86_64. Reviewed-by: DJ Delorie Reviewed-by: DJ Delorie --- libio/genops.c | 7 ++++ stdio-common/Makefile | 1 + stdio-common/tst-fflush-all-input.c | 53 +++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 stdio-common/tst-fflush-all-input.c diff --git a/libio/genops.c b/libio/genops.c index 2197bfe7a1..e4378ca48f 100644 --- a/libio/genops.c +++ b/libio/genops.c @@ -730,6 +730,13 @@ _IO_flush_all (void) ) && _IO_OVERFLOW (fp, EOF) == EOF) result = EOF; + if (_IO_fileno (fp) >= 0 + && ((fp->_mode <= 0 && fp->_IO_read_ptr < fp->_IO_read_end) + || (_IO_vtable_offset (fp) == 0 + && fp->_mode > 0 && (fp->_wide_data->_IO_read_ptr + < fp->_wide_data->_IO_read_end))) + && _IO_SYNC (fp) != 0) + result = EOF; _IO_funlockfile (fp); run_fp = NULL; diff --git a/stdio-common/Makefile b/stdio-common/Makefile index b5f78c365b..48fbf05a85 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -238,6 +238,7 @@ tests := \ tst-fdopen \ tst-fdopen2 \ tst-ferror \ + tst-fflush-all-input \ tst-fgets \ tst-fgets2 \ tst-fileno \ diff --git a/stdio-common/tst-fflush-all-input.c b/stdio-common/tst-fflush-all-input.c new file mode 100644 index 0000000000..e9df3a0c08 --- /dev/null +++ b/stdio-common/tst-fflush-all-input.c @@ -0,0 +1,53 @@ +/* Test fflush (NULL) flushes input files (bug 32369). + Copyright (C) 2025 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 + +#include +#include + +int +do_test (void) +{ + FILE *temp = tmpfile (); + TEST_VERIFY_EXIT (temp != NULL); + fprintf (temp, "abc"); + TEST_COMPARE (fflush (temp), 0); + TEST_COMPARE (lseek (fileno (temp), 0, SEEK_SET), 0); + TEST_COMPARE (fgetc (temp), 'a'); + TEST_COMPARE (fflush (NULL), 0); + TEST_COMPARE (lseek (fileno (temp), 0, SEEK_CUR), 1); + xfclose (temp); + + /* Likewise, but in wide mode. */ + temp = tmpfile (); + TEST_VERIFY_EXIT (temp != NULL); + fwprintf (temp, L"abc"); + TEST_COMPARE (fflush (temp), 0); + TEST_COMPARE (lseek (fileno (temp), 0, SEEK_SET), 0); + TEST_COMPARE (fgetwc (temp), L'a'); + TEST_COMPARE (fflush (NULL), 0); + TEST_COMPARE (lseek (fileno (temp), 0, SEEK_CUR), 1); + xfclose (temp); + + return 0; +} + +#include From patchwork Tue Jan 14 02:03:58 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joseph Myers X-Patchwork-Id: 104727 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CC1023858C52 for ; Tue, 14 Jan 2025 02:12:07 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CC1023858C52 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=HkQwzYIM X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id D984C3858C52 for ; Tue, 14 Jan 2025 02:04:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D984C3858C52 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org D984C3858C52 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1736820245; cv=none; b=wCb4rn0Ye8Hz1dGPYCkt8ZVv/wGHwPj+Wgo4PJttLdpkMzYoZpYZkdBsC9R/OJ7CewFH13bWUNlDdwJ8w9J09WXjeLqx/wCOFYA+xmU9koPtpDlF7t3FKFQVQduSolzobJuzi57Y3TiSx1ecvARhtG+7WKSoEo2oZcnHr67dUVk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1736820245; c=relaxed/simple; bh=9w2JF115U/ZtD1I25P7I5RygHKyWAbxlV8T43J5iCMk=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=Vh4EKdzpcFf0c3jVAex3gZnKo/mw5SsfCBt9xqLM/M87H6Yt0wqGX4Z3nhfgJBaFwRxMS2S0D8MFToMjRc2VxPsxxazCVA2jDaYO5vChtH5YM9jxkzM9giTdasS/yqwtvooDgiZ+MAPyBUR20AOQw6ERiVPjQz/8gjC95cITueo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D984C3858C52 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1736820245; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=bAMusX4vnU61BAFHq/j9+tXQ1KHkLC4QfXCtxACwG20=; b=HkQwzYIMDyxOpkMP6zRXGpgWBh+W48aFH1FlAloHnv7mbEwT3shHL7MPbSMW7cOd7+kYG3 2owJ1YofRn3Krrt6R9RvM8cbIwnWv9VwLhsOzMeqm4BnnSYQC4YWAiQBk7xWMg4rkf71LI 3CcILO2+lNfshGLmeqW5wKSD7JQkqpE= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-645-FJI9VvsfMVe3nHIrDsSaJQ-1; Mon, 13 Jan 2025 21:04:04 -0500 X-MC-Unique: FJI9VvsfMVe3nHIrDsSaJQ-1 X-Mimecast-MFC-AGG-ID: FJI9VvsfMVe3nHIrDsSaJQ Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-43631d8d9c7so23859505e9.1 for ; Mon, 13 Jan 2025 18:04:03 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736820243; x=1737425043; h=mime-version:references:message-id:in-reply-to:subject:to:from:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=bAMusX4vnU61BAFHq/j9+tXQ1KHkLC4QfXCtxACwG20=; b=fNGTG5rzPfwVbp3vXh80i6//Ow370jwsXakFFiYjU94FSn+SFYsRlgIaoIT+yYJz0w dUnJWxpnWFFGGLHIZ4U6P7Xz9wsKDujlxfHI1K3/2kXDAPFLrbcAKxl3MthHNrwa0dVm 7iCWs52K1+ceG7AuqghWEAiSCB7cBaAvBXLBMwGHXA6NmmTA66YgBdWT/FFbYK7eYwoT zVIxhJPBu//ogXoDWIJ9JHKo3exV6ZLUTp/+CIY3CTBrNwe+tfR0T4wOUh3oodoh7Qfg AMS8DQNHEDAHyeDms/VL/qVddhaOB6l0YzfeoUYLuNbmHDsYzedZNiUNPdxLro9OHQQb X34w== X-Gm-Message-State: AOJu0Yz7VdO5XjPbq2rDiEbCK3UVbxT8CaVf8kDj6KAGvQn5rCJpep1P LaPNAGw786WU1Fbx+b58dUBAJ98mRotoIds5p2gQY8nLQTwO0K7DZKCSlI+Q0u8hN8WNPkdsT2K poNC+Fd7rpvJ9aX6S9/+zJqiE0050TKVZZdEZvoTQE0we4P7B9gW6AMMH04r2zolOtvYH6QWjeF eE8Sxa6VrqIWNnoqygGUFIYk3+FgWzVONukbn1m1PwpA== X-Gm-Gg: ASbGncsXi7mGVR48gOec5lMXWn1SPKcaNgxBxZhJ8kfcTunmVvOLkhiS90xJSTT8WnW /YesiAKaHr+HkrA0M2NJ8WZREBxFCbugcs5V0F34WtTSD4vNwih1ZKewwvfJ5FaTpmUk6I+sgrb 3ospx6+eBK2Ak+I5td2Wa5BEWl+rZ5xeBYms4+gz6njPCO1N+IBCw6AFZS0HGrQHhdqDhmb3xEC 1+njqIIl9SV3NV1LFfjU0ncoxhIq/bcIuVJF4B0r21emF87M8R1FbJj8uMPYEIZvJfbzmMnT20W w+kKNIf5/Bk7 X-Received: by 2002:a05:600c:1e1f:b0:436:fdac:26eb with SMTP id 5b1f17b1804b1-436fdac27d7mr37874515e9.7.1736820242740; Mon, 13 Jan 2025 18:04:02 -0800 (PST) X-Google-Smtp-Source: AGHT+IERkyZgEb0Z5lMGNjodjPrlFrF0XyseX862iCNJA7R4iu15pLlSyJ3xkjmOiroOENAHP/JrrQ== X-Received: by 2002:a05:600c:1e1f:b0:436:fdac:26eb with SMTP id 5b1f17b1804b1-436fdac27d7mr37874375e9.7.1736820242142; Mon, 13 Jan 2025 18:04:02 -0800 (PST) Received: from digraph.polyomino.org.uk (digraph.polyomino.org.uk. [2001:8b0:bf73:93f7::51bb:e332]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-38a8e4b8209sm13689407f8f.70.2025.01.13.18.04.00 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 18:04:00 -0800 (PST) Received: from jsm28 (helo=localhost) by digraph.polyomino.org.uk with local-esmtp (Exim 4.97) (envelope-from ) id 1tXWHe-0000000CvlZ-3XB3 for libc-alpha@sourceware.org; Tue, 14 Jan 2025 02:03:58 +0000 Date: Tue, 14 Jan 2025 02:03:58 +0000 (UTC) From: Joseph Myers To: libc-alpha@sourceware.org Subject: [PATCH 4/6] Fix fseek handling for mmap files after ungetc or fflush (bug 32529) In-Reply-To: Message-ID: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: udXwEh0nENDfKkw26HIPmyYPYNjAiO8Q0z1L6zUfjBc_1736820243 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.2 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org As discussed in bug 32529, fseek fails on files opened for reading using mmap after ungetc. The implementation of fseek for such files has an offset computation that's also incorrect after fflush. A combined fix addresses both problems (with tests for both included as well) and it seems reasonable to consider them a single bug. Tested for x86_64. Reviewed-by: DJ Delorie --- libio/fileops.c | 9 +++++- stdio-common/Makefile | 1 + stdio-common/tst-fseek-mmap.c | 59 +++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 stdio-common/tst-fseek-mmap.c diff --git a/libio/fileops.c b/libio/fileops.c index 358378431f..97875d1eaf 100644 --- a/libio/fileops.c +++ b/libio/fileops.c @@ -1106,11 +1106,18 @@ _IO_file_seekoff_mmap (FILE *fp, off64_t offset, int dir, int mode) if (mode == 0) return fp->_offset - (fp->_IO_read_end - fp->_IO_read_ptr); + if (_IO_in_backup (fp)) + { + if (dir == _IO_seek_cur) + offset += fp->_IO_read_ptr - fp->_IO_read_end; + _IO_switch_to_main_get_area (fp); + } + switch (dir) { case _IO_seek_cur: /* Adjust for read-ahead (bytes is buffer). */ - offset += fp->_IO_read_ptr - fp->_IO_read_base; + offset += fp->_offset - (fp->_IO_read_end - fp->_IO_read_ptr); break; case _IO_seek_set: break; diff --git a/stdio-common/Makefile b/stdio-common/Makefile index 48fbf05a85..06c9eaf426 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -261,6 +261,7 @@ tests := \ tst-freopen64-7 \ tst-freopen7 \ tst-fseek \ + tst-fseek-mmap \ tst-fwrite \ tst-fwrite-memstrm \ tst-fwrite-overflow \ diff --git a/stdio-common/tst-fseek-mmap.c b/stdio-common/tst-fseek-mmap.c new file mode 100644 index 0000000000..86fa99a1a2 --- /dev/null +++ b/stdio-common/tst-fseek-mmap.c @@ -0,0 +1,59 @@ +/* Test fseek on files using mmap (bug 32529). + Copyright (C) 2025 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 +#include +#include + +int +do_test (void) +{ + char *filename = NULL; + int fd = create_temp_file ("tst-fseek-mmap", &filename); + TEST_VERIFY_EXIT (fd != -1); + xclose (fd); + + /* Test fseek after ungetc (bug 32529). */ + FILE *fp = xfopen (filename, "w"); + TEST_VERIFY (0 <= fputs ("test", fp)); + xfclose (fp); + + fp = xfopen (filename, "rm"); + TEST_COMPARE (fgetc (fp), 't'); + TEST_COMPARE (ungetc ('u', fp), 'u'); + TEST_COMPARE (fseek (fp, 0, SEEK_CUR), 0); + xfclose (fp); + + /* Test fseek positioning after fflush (another issue covered by the + same fix). */ + fp = xfopen (filename, "rm"); + TEST_COMPARE (fgetc (fp), 't'); + TEST_COMPARE (fflush (fp), 0); + TEST_COMPARE (ftell (fp), 1); + TEST_COMPARE (fseek (fp, 0, SEEK_CUR), 0); + TEST_COMPARE (ftell (fp), 1); + TEST_COMPARE (fgetc (fp), 'e'); + xfclose (fp); + + return 0; +} + +#include From patchwork Tue Jan 14 02:04:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joseph Myers X-Patchwork-Id: 104725 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 548423858C5F for ; Tue, 14 Jan 2025 02:07:14 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 548423858C5F Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=hG1q1U0T X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id C69CF3858D38 for ; Tue, 14 Jan 2025 02:04:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C69CF3858D38 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org C69CF3858D38 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1736820269; cv=none; b=Y4+g63EX/TRgJi9Q8JzJ/8wRdzdxtBUNiYXsS0qnNXvsPo75C0IVZPiop8O+c+Eqd9+4O93RwCshKsaVrUuC5iO/rFhiqpQnLV7o8D6xmJhFZ5JwHJADekZN9QR1qnuLjTzUCGRyG8sRCsrZ0QYK5a+xSGnpbaUh3IHEUSQnNsk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1736820269; c=relaxed/simple; bh=JfEQufexQmKgq2+K2lKNss0Ueow7RnKAtuvRFyXKtZw=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=G/cRQxae2AWEGF903Fzjy8OfIZNOzjagQrSQnEo9WVuof6YRedCGPoO3zrhEpuKUrmzeO265neWdpTETM+7QXpNCHGmC9iSfWn8pqi2AWVoLAsUHQFYwQoeBqGQOa4URIcNoGIX6uh8xEkORk7RTl+IPAT391IridCJw58+au6c= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C69CF3858D38 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1736820269; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=x+27KXVCCn0eBoLZfJdzzDHRvoocbWZRuPnQw8xV02A=; b=hG1q1U0Tk2fUvrbAyaMoaGRSfmBvfsa03bW+oxc6hE60mfeVud7qXkKiaP4onBtYcQ2ETv VGw0i8j/+ap3yWSpKfF2za3M3p5ZXyZYmkJmWLgOHQ7mRfQua4OZFQuBR9O6I1vjzn9WL+ 5UI90Xx4gAZ/kk6VzwOeu3mcJnWntmM= Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-615-JHIwgTF0N9WS59rLGZKZ2w-1; Mon, 13 Jan 2025 21:04:28 -0500 X-MC-Unique: JHIwgTF0N9WS59rLGZKZ2w-1 X-Mimecast-MFC-AGG-ID: JHIwgTF0N9WS59rLGZKZ2w Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-43625ceae52so27214715e9.0 for ; Mon, 13 Jan 2025 18:04:27 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736820267; x=1737425067; h=mime-version:references:message-id:in-reply-to:subject:to:from:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=x+27KXVCCn0eBoLZfJdzzDHRvoocbWZRuPnQw8xV02A=; b=OZq4nLz50UmO+zmxKVEQzkJLq8v80U0LB1DBOoAWhdkGmX+ScJFII/i8T3t+8RzMuI sPu1hNS/hEp3SMf918e+gZ/QOwRxGbR+dTRXv9gr7INbVIVUg8KjfgpmIeDmEEt22S15 Ln6/80thvWfO9BbWwkw0jA/ramkbt3uD/+b9ZKg3sIFa+Z8nQPJg1NKMBS7sqe6SZeXQ /RauBOstpYQioc5/2qlRhIccbGP7N8QvGh24mm0lmziju0gwLc0WrLyL9i9w9qrRPJNw y0cbqoHdJXKdwKGoD/UTHoRBc1pgRrcwTDtYuAlV66AtIxRR02GHngOksXMe4hB3gY8N 6zAA== X-Gm-Message-State: AOJu0YxbxOuUkfmp0E2bwfcLULmKtT284s3IJA+Cyh4sXYAneASDCQbL eFoGShbWZaflA0GI6zU034jYDuhprzShcZdGmHU4SSzNlPk+FK8d5jKx+Ncc+ZaiR8fH8MbPRDI qaPhnNkZddTj2xJmTB5Wc2y0koGoylyC6Ag/up19zAPtWi/RSuXVh95bzB3LDYMzfKj0H6l22ZE Sglk77uhVUagsI54Hvb+WZro+HCAd5kKoAdqGKZn2Dqg== X-Gm-Gg: ASbGncsPXAykMuhededios4y/y76Qo8Q+WbnqpShJxPPcV7slyBhA1s2R52s0b1Oike 7d0XB1PZNe3VBtQOxLdDTEdIfKfGlMFZJN2IklbVHCpVIY55fBrjXD7I79ygtTRzMFdtLw95Fpu N/Wv8nwvTO2kX24qCkFmEoE6+h+HmL/aUmmK0optZcg333avyqz0UE8Uu+oFKk+Jk97dGMjk6tc AaMHtw6WyDr9/mNOjNWAcOqbr5Ay5j5vf1xLog4E9mUA4WcUJJ23JzG7q1EqGiCWDOl6tnnr5MN F9RhuuPOOmXk X-Received: by 2002:a05:600c:4449:b0:435:192:63ca with SMTP id 5b1f17b1804b1-436e26f481dmr90696425e9.21.1736820266718; Mon, 13 Jan 2025 18:04:26 -0800 (PST) X-Google-Smtp-Source: AGHT+IH+L44grC+hwYAG9pec+OScjXWIuNGJygYIOFdxEw8ePfx4b+6h4WPgy5aVYtjXyYF6UCSQEQ== X-Received: by 2002:a05:600c:4449:b0:435:192:63ca with SMTP id 5b1f17b1804b1-436e26f481dmr90696265e9.21.1736820266229; Mon, 13 Jan 2025 18:04:26 -0800 (PST) Received: from digraph.polyomino.org.uk (digraph.polyomino.org.uk. [2001:8b0:bf73:93f7::51bb:e332]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-436e2e89e14sm194771395e9.33.2025.01.13.18.04.24 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 18:04:25 -0800 (PST) Received: from jsm28 (helo=localhost) by digraph.polyomino.org.uk with local-esmtp (Exim 4.97) (envelope-from ) id 1tXWI3-0000000Cvln-2m9k for libc-alpha@sourceware.org; Tue, 14 Jan 2025 02:04:23 +0000 Date: Tue, 14 Jan 2025 02:04:23 +0000 (UTC) From: Joseph Myers To: libc-alpha@sourceware.org Subject: [PATCH 5/6] Fix fflush handling for mmap files after ungetc (bug 32535) In-Reply-To: Message-ID: <8ef14304-75b4-6938-1cd4-d44c3390f7e0@redhat.com> References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: A0qRpVEPN7IydRZhbAA-um6hDGl6KpTKDUjVuXjkxRk_1736820267 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.2 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org As discussed in bug 32535, fflush fails on files opened for reading using mmap after ungetc. Fix the logic to handle this case and still compute the file offset correctly. Tested for x86_64. Reviewed-by: DJ Delorie --- libio/fileops.c | 12 ++++++--- stdio-common/Makefile | 1 + stdio-common/tst-fflush-mmap.c | 48 ++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 stdio-common/tst-fflush-mmap.c diff --git a/libio/fileops.c b/libio/fileops.c index 97875d1eaf..7e370d12b2 100644 --- a/libio/fileops.c +++ b/libio/fileops.c @@ -858,17 +858,21 @@ libc_hidden_ver (_IO_new_file_sync, _IO_file_sync) int _IO_file_sync_mmap (FILE *fp) { + off64_t o = fp->_offset - (fp->_IO_read_end - fp->_IO_read_ptr); if (fp->_IO_read_ptr != fp->_IO_read_end) { - if (__lseek64 (fp->_fileno, fp->_IO_read_ptr - fp->_IO_buf_base, - SEEK_SET) - != fp->_IO_read_ptr - fp->_IO_buf_base) + if (_IO_in_backup (fp)) + { + _IO_switch_to_main_get_area (fp); + o -= fp->_IO_read_end - fp->_IO_read_base; + } + if (__lseek64 (fp->_fileno, o, SEEK_SET) != o) { fp->_flags |= _IO_ERR_SEEN; return EOF; } } - fp->_offset = fp->_IO_read_ptr - fp->_IO_buf_base; + fp->_offset = o; fp->_IO_read_end = fp->_IO_read_ptr = fp->_IO_read_base; return 0; } diff --git a/stdio-common/Makefile b/stdio-common/Makefile index 06c9eaf426..703e8af7e8 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -239,6 +239,7 @@ tests := \ tst-fdopen2 \ tst-ferror \ tst-fflush-all-input \ + tst-fflush-mmap \ tst-fgets \ tst-fgets2 \ tst-fileno \ diff --git a/stdio-common/tst-fflush-mmap.c b/stdio-common/tst-fflush-mmap.c new file mode 100644 index 0000000000..fd3671f198 --- /dev/null +++ b/stdio-common/tst-fflush-mmap.c @@ -0,0 +1,48 @@ +/* Test fflush after ungetc on files using mmap (bug 32535). + Copyright (C) 2025 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 +#include +#include + +int +do_test (void) +{ + char *filename = NULL; + int fd = create_temp_file ("tst-fflush-mmap", &filename); + TEST_VERIFY_EXIT (fd != -1); + xclose (fd); + + /* Test fflush after ungetc (bug 32535). */ + FILE *fp = xfopen (filename, "w"); + TEST_VERIFY (0 <= fputs ("test", fp)); + xfclose (fp); + + fp = xfopen (filename, "rm"); + TEST_COMPARE (fgetc (fp), 't'); + TEST_COMPARE (ungetc ('u', fp), 'u'); + TEST_COMPARE (fflush (fp), 0); + xfclose (fp); + + return 0; +} + +#include From patchwork Tue Jan 14 02:04:50 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joseph Myers X-Patchwork-Id: 104728 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 095A93858C52 for ; Tue, 14 Jan 2025 02:15:45 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 095A93858C52 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=D22g+Voi X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 6436B3858C50 for ; Tue, 14 Jan 2025 02:04:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 6436B3858C50 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 6436B3858C50 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1736820298; cv=none; b=vA+Ti5Vq4BKkElVyHgW35OqpwH0b2TP6gVx7h1HbT0igK9FQq1+id09V5d3UOgWfpg+4mtovE7eHglKW02M76f+yWBFDqH+qVX4QgVxl+eWz6RXebY8oHbO7TIssPO11do7idepTYQf75H1rlWncdlkPVjejsnfMexGE2qodjyE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1736820298; c=relaxed/simple; bh=ivZKjee7GbIjureqeTUpOODY83l8Z68KQljwH92eJgU=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=Mp0edgc2pSDIgUAbKyoH5C2x0uHVbXVYLvp5z5AkytBq1PNFVlPHLWgl2onXfnzyK109T+LzeqcrpfTugG/+uK1w8jcWTA0k+d5/kOBf9EY5mLxOjG4rOu94wJqJai7bRMwGn7o8fR/V/y4q9DnkY9q+m1EEyE+l3BU+nlz9BU8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6436B3858C50 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1736820298; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=R78e5LXprWwuW1kXZO1SOP966L8SmRAdzA4wiEdZBLI=; b=D22g+VoirIEdo4G8ji5R2qYC+b2KMdhgwFfVA1DOBUrsL3yGOO448MiaoccwAcu8YpnF9C zvQqVDBE15OZ8QBCL/X3uokUGFnbpKWJTimXjoiQ89ycwMVRrCuoQNzHYvm78R25xs8v+I A89gq3yeFjl1iaZIyPp5s6L9BwozUQc= Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-192-Y0G0Yv2RO9-y7rCh1dm8-Q-1; Mon, 13 Jan 2025 21:04:56 -0500 X-MC-Unique: Y0G0Yv2RO9-y7rCh1dm8-Q-1 X-Mimecast-MFC-AGG-ID: Y0G0Yv2RO9-y7rCh1dm8-Q Received: by mail-wr1-f69.google.com with SMTP id ffacd0b85a97d-385dcadffebso2382008f8f.0 for ; Mon, 13 Jan 2025 18:04:56 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736820295; x=1737425095; h=mime-version:references:message-id:in-reply-to:subject:to:from:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=R78e5LXprWwuW1kXZO1SOP966L8SmRAdzA4wiEdZBLI=; b=jvYv+CkGiO6rfRn/chPnKgGZrnOEPSw2EAAV3SE9Ia+t6wjv+Lj27OsGR9rC8ZfTS6 1WJa2mYNpzRnUlWCBuExM3ymgRd6GNBTw7Y8H8CDSOnSA6bEbNpan0nR5DlRcqzlIErO nERAaRsoS/05yYsNWPcEF4viNAasJZdKNqnzvxeVvisTkRMTkxI/iVKT0G2mY7VgbBho sQJQkNPS3KdN3brpfbvGEslE8UqHRStiv5nQ6oK2jq7tp8FuXAUaBUsIrn9Jim7OX7t9 W8fLc69O3jSxaaI+dbLDq/nmlZGLVf/dNKjSuHXyeyuZpmYk8000tKBfFDys5dtfLvgn jwOQ== X-Gm-Message-State: AOJu0YzDk/oXEWCRfv9oNv3ABytzyBTpiYy9lpq3QDUA/8mNlo+xnEH9 d3PGyhGwdT4Q9N+92g5a7sW/lfyTBuYcDx4dYPOnte3VsEnOkhAvwQYOIcLRu0dWJ2QC0VV9JAE OekfZHw6qqaTDpCNlTHwM2HxLSf4PRjw2cAgT3t0me3BVprGYJlW/16GrKmw/lSnrZYNFPLZUGW zJLWucH7bxLVF41geSAxMbqplOyE2pAG69ijejKQFNAQ== X-Gm-Gg: ASbGncuvA70tdkhwB/4CPPiAK3LV7Vsj7OeC3YRD6UqIm2nLnnRYO3jh2NTXlgYYIaC TciRLQmSC9Mhi+loRVO5X/IRix99iLST2ADew1eHVYh1Rqx1UYxhYBL5LLULrC3kEKK3Cg+iHMj HSp0r+kj6ZRrObOdGQcQau6LBbS2F9BFDsXKC2p8Fc+slwyDBSHbYr60WjMotrTaFoiIddg5b/j TijkcYSGrHxmNWpYVvpdXRXws13BWPA9wWreLUl6l08aq4xfKXUvKMmMRePbTAyb54lQpxq+6go Q6SkZfZjvWu3 X-Received: by 2002:a5d:5886:0:b0:385:f840:e613 with SMTP id ffacd0b85a97d-38a87356509mr22901514f8f.51.1736820294911; Mon, 13 Jan 2025 18:04:54 -0800 (PST) X-Google-Smtp-Source: AGHT+IGSDGflq2gek3FbjHv1d83dWzxAeLllq+XWpKEExlgJxKs3SrwzjyAWfahZoq9MVc92yA45vQ== X-Received: by 2002:a5d:5886:0:b0:385:f840:e613 with SMTP id ffacd0b85a97d-38a87356509mr22901491f8f.51.1736820294248; Mon, 13 Jan 2025 18:04:54 -0800 (PST) Received: from digraph.polyomino.org.uk (digraph.polyomino.org.uk. [2001:8b0:bf73:93f7::51bb:e332]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-38a8e38bf65sm13364830f8f.49.2025.01.13.18.04.52 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 18:04:53 -0800 (PST) Received: from jsm28 (helo=localhost) by digraph.polyomino.org.uk with local-esmtp (Exim 4.97) (envelope-from ) id 1tXWIU-0000000Cvmj-3tTq for libc-alpha@sourceware.org; Tue, 14 Jan 2025 02:04:50 +0000 Date: Tue, 14 Jan 2025 02:04:50 +0000 (UTC) From: Joseph Myers To: libc-alpha@sourceware.org Subject: [PATCH 6/6] Add test of input file flushing / offset issues In-Reply-To: Message-ID: <79effec8-7345-3f39-1222-3ef1ae3f803c@redhat.com> References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: Zyi4Y4ijGK0ksIuJktuXd67J44F2IHOzeHp1Z515mRM_1736820295 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org Having fixed several bugs relating to flushing of FILE* streams (with fflush and other operations) and their offsets (both the file position indicator in the FILE*, and the offset in the underlying open file description), especially after ungetc but not limited to that case, add a test that more systematically covers different combinations of cases for such issues, with 25664 separate scenarios tested (which include examples of all the five separate fixed bugs), all of which pass given the five previous bug fixes. Tested for x86_64. Reviewed-by: DJ Delorie Reviewed-by: DJ Delorie --- stdio-common/Makefile | 1 + stdio-common/tst-read-offset.c | 544 +++++++++++++++++++++++++++++++++ 2 files changed, 545 insertions(+) create mode 100644 stdio-common/tst-read-offset.c diff --git a/stdio-common/Makefile b/stdio-common/Makefile index 703e8af7e8..c14cf32776 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -285,6 +285,7 @@ tests := \ tst-printf-round \ tst-printfsz \ tst-put-error \ + tst-read-offset \ tst-renameat2 \ tst-rndseek \ tst-scanf-binary-c11 \ diff --git a/stdio-common/tst-read-offset.c b/stdio-common/tst-read-offset.c new file mode 100644 index 0000000000..20ffbf55a4 --- /dev/null +++ b/stdio-common/tst-read-offset.c @@ -0,0 +1,544 @@ +/* Test offsets in files being read, in particular with ungetc. + Copyright (C) 2025 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 +#include +#include + +#include +#include +#include +#include + +static volatile bool fail = false; + +/* Induce a malloc failure whenever FAIL is set. */ +void * +malloc (size_t sz) +{ + if (fail) + return NULL; + + static void *(*real_malloc) (size_t); + + if (real_malloc == NULL) + real_malloc = dlsym (RTLD_NEXT, "malloc"); + + return real_malloc (sz); +} + +/* The name of the temporary file used by all the tests. */ +static char *filename; + +/* st_blksize value for that file, or BUFSIZ if out of range. */ +static int blksize = BUFSIZ; + +/* Test data, both written to that file and used as an in-memory + stream. */ +char test_data[2 * BUFSIZ]; + +/* Ways to open a test stream for reading (that may use different code + paths in libio). */ +enum test_open_case + { + test_open_fopen, + test_open_fopen_m, + test_open_fopen64, + test_open_fopen64_m, + test_open_fmemopen, + test_open_max + }; + +static const char *const test_open_case_name[test_open_max] = + { + "fopen", "fopen(mmap)", "fopen64", "fopen64(mmap)", "fmemopen" + }; + +static FILE * +open_test_stream (enum test_open_case c) +{ + FILE *fp; + switch (c) + { + case test_open_fopen: + fp = fopen (filename, "r"); + break; + + case test_open_fopen_m: + fp = fopen (filename, "rm"); + break; + + case test_open_fopen64: + fp = fopen64 (filename, "r"); + break; + + case test_open_fopen64_m: + fp = fopen64 (filename, "rm"); + break; + + case test_open_fmemopen: + fp = fmemopen (test_data, 2 * BUFSIZ, "r"); + break; + + default: + abort (); + } + TEST_VERIFY_EXIT (fp != NULL); + return fp; +} + +/* Base locations at which the main test (ungetc calls then doing + something that clears ungetc characters, then checking offset) + starts. */ +enum test_base_loc + { + base_loc_start, + base_loc_blksize, + base_loc_bufsiz, + base_loc_max + }; + +static int +base_loc_to_bytes (enum test_base_loc loc, int offset) +{ + switch (loc) + { + case base_loc_start: + return offset; + + case base_loc_blksize: + return blksize + offset; + + case base_loc_bufsiz: + return BUFSIZ + offset; + + default: + abort (); + } +} + +/* Ways to clear data from ungetc. */ +enum clear_ungetc_case + { + clear_fseek, + clear_fseekm1, + clear_fseekp1, + clear_fseeko, + clear_fseekom1, + clear_fseekop1, + clear_fseeko64, + clear_fseeko64m1, + clear_fseeko64p1, + clear_fsetpos, + clear_fsetposu, + clear_fsetpos64, + clear_fsetpos64u, + clear_fflush, + clear_fflush_null, + clear_fclose, + clear_max + }; + +static const char *const clear_ungetc_case_name[clear_max] = + { + "fseek", "fseek(-1)", "fseek(1)", "fseeko", "fseeko(-1)", "fseeko(1)", + "fseeko64", "fseeko64(-1)", "fseeko64(1)", "fsetpos", "fsetpos(before)", + "fsetpos64", "fsetpos64(before)", "fflush", "fflush(NULL)", "fclose" + }; + +static int +clear_offset (enum clear_ungetc_case c, int num_ungetc) +{ + switch (c) + { + case clear_fseekm1: + case clear_fseekom1: + case clear_fseeko64m1: + return -1; + + case clear_fseekp1: + case clear_fseekop1: + case clear_fseeko64p1: + return 1; + + case clear_fsetposu: + case clear_fsetpos64u: + return num_ungetc; + + default: + return 0; + } +} + +/* The offsets used with fsetpos / fsetpos64. */ +static fpos_t pos; +static fpos64_t pos64; + +static int +do_clear_ungetc (FILE *fp, enum clear_ungetc_case c, int num_ungetc) +{ + int ret; + int offset = clear_offset (c, num_ungetc); + switch (c) + { + case clear_fseek: + case clear_fseekm1: + case clear_fseekp1: + ret = fseek (fp, offset, SEEK_CUR); + break; + + case clear_fseeko: + case clear_fseekom1: + case clear_fseekop1: + ret = fseeko (fp, offset, SEEK_CUR); + break; + + case clear_fseeko64: + case clear_fseeko64m1: + case clear_fseeko64p1: + ret = fseeko64 (fp, offset, SEEK_CUR); + break; + + case clear_fsetpos: + case clear_fsetposu: + ret = fsetpos (fp, &pos); + break; + + case clear_fsetpos64: + case clear_fsetpos64u: + ret = fsetpos64 (fp, &pos64); + break; + + case clear_fflush: + ret = fflush (fp); + break; + + case clear_fflush_null: + ret = fflush (NULL); + break; + + case clear_fclose: + ret = fclose (fp); + break; + + default: + abort(); + } + TEST_COMPARE (ret, 0); + return offset; +} + +static bool +clear_valid (enum test_open_case c, enum clear_ungetc_case cl) +{ + switch (c) + { + case test_open_fmemopen: + /* fflush is not valid for input memory streams, and fclose is + useless for this test for such streams because there is no + underlying open file description for which an offset could be + checked after fclose. */ + switch (cl) + { + case clear_fflush: + case clear_fflush_null: + case clear_fclose: + return false; + + default: + return true; + } + + default: + /* All ways of clearing ungetc state are valid for streams with + an underlying file. */ + return true; + } +} + +static bool +clear_closes_file (enum clear_ungetc_case cl) +{ + switch (cl) + { + case clear_fclose: + return true; + + default: + return false; + } +} + +static void +clear_getpos_before (FILE *fp, enum clear_ungetc_case c) +{ + switch (c) + { + case clear_fsetposu: + TEST_COMPARE (fgetpos (fp, &pos), 0); + break; + + case clear_fsetpos64u: + TEST_COMPARE (fgetpos64 (fp, &pos64), 0); + break; + + default: + break; + } +} + +static void +clear_getpos_after (FILE *fp, enum clear_ungetc_case c) +{ + switch (c) + { + case clear_fsetpos: + TEST_COMPARE (fgetpos (fp, &pos), 0); + break; + + case clear_fsetpos64: + TEST_COMPARE (fgetpos64 (fp, &pos64), 0); + break; + + default: + break; + } +} + +/* Ways to verify results of clearing ungetc data. */ +enum verify_case + { + verify_read, + verify_ftell, + verify_ftello, + verify_ftello64, + verify_fd, + verify_max + }; + +static const char *const verify_case_name[verify_max] = + { + "read", "ftell", "ftello", "ftello64", "fd" + }; + +static bool +valid_fd_offset (enum test_open_case c, enum clear_ungetc_case cl) +{ + switch (c) + { + case test_open_fmemopen: + /* No open file description. */ + return false; + + default: + /* fseek does not necessarily set the offset for the underlying + open file description ("If the most recent operation, other + than ftell(), on a given stream is fflush(), the file offset + in the underlying open file description shall be adjusted to + reflect the location specified by fseek()." in POSIX does not + include the case here where getc was the last operation). + Similarly, fsetpos does not necessarily set that offset + either. */ + switch (cl) + { + case clear_fflush: + case clear_fflush_null: + case clear_fclose: + return true; + + default: + return false; + } + } +} + +static bool +verify_valid (enum test_open_case c, enum clear_ungetc_case cl, + enum verify_case v) +{ + switch (v) + { + case verify_fd: + return valid_fd_offset (c, cl); + + default: + switch (cl) + { + case clear_fclose: + return false; + + default: + return true; + } + } +} + +static bool +verify_uses_fd (enum verify_case v) +{ + switch (v) + { + case verify_fd: + return true; + + default: + return false; + } +} + +static int +read_to_test_loc (FILE *fp, enum test_base_loc loc, int offset) +{ + int to_read = base_loc_to_bytes (loc, offset); + for (int i = 0; i < to_read; i++) + TEST_COMPARE (getc (fp), (unsigned char) i); + return to_read; +} + +static void +setup (void) +{ + int fd = create_temp_file ("tst-read-offset", &filename); + TEST_VERIFY_EXIT (fd != -1); + struct stat64 st; + xfstat64 (fd, &st); + if (st.st_blksize > 0 && st.st_blksize < BUFSIZ) + blksize = st.st_blksize; + printf ("BUFSIZ = %d, blksize = %d\n", BUFSIZ, blksize); + xclose (fd); + FILE *fp = xfopen (filename, "w"); + for (size_t i = 0; i < 2 * BUFSIZ; i++) + { + unsigned char c = i; + TEST_VERIFY_EXIT (fputc (c, fp) == c); + test_data[i] = c; + } + xfclose (fp); +} + +static void +test_one_case (enum test_open_case c, enum test_base_loc loc, int offset, + int num_ungetc, int num_ungetc_diff, bool ungetc_fallback, + enum clear_ungetc_case cl, enum verify_case v) +{ + int full_offset = base_loc_to_bytes (loc, offset); + printf ("Testing %s offset %d ungetc %d different %d %s%s %s\n", + test_open_case_name[c], full_offset, num_ungetc, num_ungetc_diff, + ungetc_fallback ? "fallback " : "", clear_ungetc_case_name[cl], + verify_case_name[v]); + FILE *fp = open_test_stream (c); + int cur_offset = read_to_test_loc (fp, loc, offset); + clear_getpos_before (fp, cl); + for (int i = 0; i < num_ungetc; i++) + { + unsigned char c = (i >= num_ungetc - num_ungetc_diff + ? cur_offset + : cur_offset - 1); + if (ungetc_fallback) + fail = true; + TEST_COMPARE (ungetc (c, fp), c); + fail = false; + cur_offset--; + } + clear_getpos_after (fp, cl); + int fd = -1; + bool done_dup = false; + if (verify_uses_fd (v)) + { + fd = fileno (fp); + TEST_VERIFY (fd != -1); + if (clear_closes_file (cl)) + { + fd = xdup (fd); + done_dup = true; + } + } + cur_offset += do_clear_ungetc (fp, cl, num_ungetc); + switch (v) + { + case verify_read: + for (; cur_offset <= full_offset + 1; cur_offset++) + TEST_COMPARE (getc (fp), (unsigned char) cur_offset); + break; + + case verify_ftell: + TEST_COMPARE (ftell (fp), cur_offset); + break; + + case verify_ftello: + TEST_COMPARE (ftello (fp), cur_offset); + break; + + case verify_ftello64: + TEST_COMPARE (ftello64 (fp), cur_offset); + break; + + case verify_fd: + TEST_COMPARE (lseek (fd, 0, SEEK_CUR), cur_offset); + break; + + default: + abort (); + } + if (! clear_closes_file (cl)) + { + int ret = fclose (fp); + TEST_COMPARE (ret, 0); + } + if (done_dup) + xclose (fd); +} + +int +do_test (void) +{ + setup (); + for (enum test_open_case c = 0; c < test_open_max; c++) + for (enum test_base_loc loc = 0; loc < base_loc_max; loc++) + for (int offset = 0; offset <= 3; offset++) + for (int num_ungetc = 0; + num_ungetc <= 2 && num_ungetc <= base_loc_to_bytes (loc, offset); + num_ungetc++) + for (int num_ungetc_diff = 0; + num_ungetc_diff <= num_ungetc; + num_ungetc_diff++) + for (int ungetc_fallback = 0; + ungetc_fallback <= (num_ungetc == 1 ? 1 : 0); + ungetc_fallback++) + for (enum clear_ungetc_case cl = 0; cl < clear_max; cl++) + { + if (!clear_valid (c, cl)) + continue; + if ((base_loc_to_bytes (loc, offset) + - num_ungetc + + clear_offset (cl, num_ungetc)) < 0) + continue; + for (enum verify_case v = 0; v < verify_max; v++) + { + if (!verify_valid (c, cl, v)) + continue; + test_one_case (c, loc, offset, num_ungetc, + num_ungetc_diff, ungetc_fallback, cl, v); + } + } + return 0; +} + +#include