From patchwork Wed Apr 10 12:28:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 162016 Delivered-To: patch@linaro.org Received: by 2002:a02:c6d8:0:0:0:0:0 with SMTP id r24csp6145374jan; Wed, 10 Apr 2019 05:28:49 -0700 (PDT) X-Google-Smtp-Source: APXvYqy/iKcPw4pysDEGFyxJif8KeSKg3QUDD3VbgyU7xw6yzMBaMFl49voMw/J5a1PUvE99BsrH X-Received: by 2002:a65:4247:: with SMTP id d7mr38386986pgq.114.1554899329356; Wed, 10 Apr 2019 05:28:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1554899329; cv=none; d=google.com; s=arc-20160816; b=MdDzZzpS86/EMrvroW/X+trY2QralFcWqBOVNnTByWHUqbwOsHdyikz3HbqilweZgD kFl04xKHPEGtHAxMmFsgTQM7OGeNfsfb0nW2EklLXuVb/pcOv8/+xaUvxv+8xYTpiiNl mMSLcQz4ygYkIT4U4LT7KLYP3i0NFs6FNDb3TjblduaNpVcBGD/xhUV2hJkS+XLQgFTI qhBpWgt7JMvGZ1YYR3uocpQVtjXTvcnsfeRxlxkZAAigyVPDBXYodkxYx+a/rEk2xas9 h2QxAF0jt6MySJpXPXvAeQvSoeoXMvYIfMzRB4jWlv8yq3andpAuEe3VlODzk5KsiPSC 9X9A== 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=YizvrwCOryea0zCR7A6W0T36UtEIwaxulnNIRJwL0/E=; b=XcEmvyO8TsFXWMiv5In8LcP53UsQhjCuvNRt43TUPqw84ErpF6SMfd6AOP1s6qzt+r 4rFb6od9jdXefB2YjOAIAC2b9/+FRZJN2eIFMEzlrXlUZVgoypMvx2InsJZF8CC7uW9U 5A+PwJ3nlAcROlyTp3uEkKns0gbGiXPXHeVNwNfG7vJnFs8iAEfyK3nAUUGhknkFkxc9 tC4NbeSWI+4GXzNyyf7eSd6vX5C9GYyRjaT49RtwajZ0iEPhgZ/VIrGMmpzZdy9/7LjM DA2PybL4hj8/1+0D5EvqCdm4rP6nHuynlJ7lS7KS2TPF3lZvteAOJvMkjKh3jJ2H990S Lj6g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=yaCeOETj; dkim=pass header.i=@linaro.org header.s=google header.b="vPwXi1/k"; spf=pass (google.com: domain of libc-alpha-return-101304-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-101304-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 123si18935621pgg.104.2019.04.10.05.28.49 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 10 Apr 2019 05:28:49 -0700 (PDT) Received-SPF: pass (google.com: domain of libc-alpha-return-101304-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=yaCeOETj; dkim=pass header.i=@linaro.org header.s=google header.b="vPwXi1/k"; spf=pass (google.com: domain of libc-alpha-return-101304-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-101304-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=rLw58M6cMxEEQz1VML3vswSduv658vcYwmzK3YVu94OdY6juSA7H6 EAoLCBlP+Fejhk9D1H/5btvh747dKJOuhZAVkVhX0VhtGTvMZludi1VaJRMlKi82 1YwohmC7DcqpLwRCAIiSdmy1TCzx8fciDg7+Lj75hQFE40VolInoCc= 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=PjhXQvXdXzt7vYrYveqFWEcI+oU=; b=yaCeOETjAaCZ/enCt/OlTD5zvgP+ VhBvLECWhX/35DldX1LR91905U4Gd1KiPxzcxAdzUK3BaSlzim+uTjzCDhv99NOt GKJz/xkLZbSwJutrXGQHTvsxiQfVL0nlAm3lYytTNkXw6i60Y4lSpMTXIGmwvMOM VNN4udVvYpJxJLU= Received: (qmail 22088 invoked by alias); 10 Apr 2019 12:28:40 -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 22077 invoked by uid 89); 10 Apr 2019 12:28:39 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-18.2 required=5.0 tests=AWL, 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.1 spammy=sitting X-HELO: mail-vs1-f67.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=YizvrwCOryea0zCR7A6W0T36UtEIwaxulnNIRJwL0/E=; b=vPwXi1/kjjo7RKOJRa+kjDbXfgSaJevgeKU7msywGtEyG1z5jNB3YvAmmidne/ky4f LfVZQHYdmyw/Bu1B7Yui9wcSmXRnoQRyFxgntKrC0N4VfM8Ps/bB5a11VMlu5LHYEG+a tpHpqKAy2FnGKz82/IQV3uwtc4NEvTwG9k1+fM12eE/n0+Duc9NeDBJFwA6hUtanUyQQ ddD0F1PoYy9+vkLIfKbPhq6+VRjAEl2gKxHXzY/dkCmH0FgDLK3p+WxM7L5Biw0dQQeZ Kzs30sp5mJ8zk9QQt2o/fCC8B0SOSvA29ZcmOY18+C7NyR3yYgPTG+COdjknlyYuLRDZ EzUg== Return-Path: From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH v3] libio: Fix seek-past-end returned size for open_{w}memstream (BZ#15298) Date: Wed, 10 Apr 2019 09:28:29 -0300 Message-Id: <20190410122829.6131-1-adhemerval.zanella@linaro.org> It has been sitting for some time in my backlog. Changes from previous version: - Change test name to adjust to new additions. --- POSIX states that after a successfull fflush() or fclose() the variable pointed by the input size shall contain the smaller of the current buffer length and the number of bytes (or wide characters for wide version) [1]. Current GLIBC behavior returns the seek position even there is no previous write operation. To correctly report the buffer size the implementation must track both the buffer position and current byte written. However internal _IO_write_ptr is update on both write and seek operations. This patch fixes how open_{w}memstream updates the returned buffer size of a fclose/fflush operation by adding two new internal fields to keep track of both previous and next position after a write operation. Checked on x86_64-linux-gnu and i686-linux-gnu. [1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/open_memstream.html [BZ #15298] * libio/Makefile (tests): Add tst-memstream5 and tst-wmemstream5. * libio/memstream.c (_IO_FILE_memstream): Add prevwriteptr and seekwriteptr fields. (_IO_mem_seekoff): New function. (libio_vtable): Use _IO_mem_seekoff instead of _IO_str_seekoff. (__open_memstream): Initialize prevwriteptr and seekwriteptr. (_IO_mem_sync): Update sizeloc based on written bytes instead of buffer current position. (_IO_mem_finish): Likewise. * libio/memstream.c (_IO_FILE_wmemstream): Add prevwriteptr and seekwriteptr fields. (_IO_wmem_seekoff): New function. (libio_vtable): Use _IO_mem_seekoff instead of _IO_str_seekoff. (__open_wmemstream): Initialize prevwriteptr and seekwriteptr. (_IO_wmem_sync): Update sizeloc based on written bytes instead of buffer current position. (_IO_wmem_finish): Likewise. * libio/tst-memstream3.c (do_test_bz18241): Check for expected size after a fseek followed by a fflush. * libio/tst-memstream5.c: New file. * libio/tst-wmemstream5.c: Likewise. --- ChangeLog | 25 ++++++++++++++ libio/Makefile | 2 ++ libio/memstream.c | 59 ++++++++++++++++++++++++++++++--- libio/tst-memstream3.c | 8 +++-- libio/tst-memstream5.c | 73 +++++++++++++++++++++++++++++++++++++++++ libio/tst-wmemstream5.c | 20 +++++++++++ libio/wmemstream.c | 62 +++++++++++++++++++++++++++++----- 7 files changed, 234 insertions(+), 15 deletions(-) create mode 100644 libio/tst-memstream5.c create mode 100644 libio/tst-wmemstream5.c -- 2.17.1 diff --git a/libio/Makefile b/libio/Makefile index 95b91084dd..83b83d1a8b 100644 --- a/libio/Makefile +++ b/libio/Makefile @@ -60,7 +60,9 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ tst-mmap2-eofsync tst-mmap-offend bug-fopena+ bug-wfflush \ bug-ungetc2 bug-ftell bug-ungetc3 bug-ungetc4 tst-fopenloc2 \ tst-memstream1 tst-memstream2 tst-memstream3 tst-memstream4 \ + tst-memstream5 \ tst-wmemstream1 tst-wmemstream2 tst-wmemstream3 tst-wmemstream4 \ + tst-wmemstream5 \ bug-memstream1 bug-wmemstream1 \ tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \ tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \ diff --git a/libio/memstream.c b/libio/memstream.c index d48e30be93..8d496676b6 100644 --- a/libio/memstream.c +++ b/libio/memstream.c @@ -26,11 +26,15 @@ struct _IO_FILE_memstream _IO_strfile _sf; char **bufloc; size_t *sizeloc; + char *prevwriteptr; + char *seekwriteptr; }; static int _IO_mem_sync (FILE* fp) __THROW; static void _IO_mem_finish (FILE* fp, int) __THROW; +static off64_t _IO_mem_seekoff (FILE *fp, off64_t offset, + int dir, int mode) __THROW; static const struct _IO_jump_t _IO_mem_jumps libio_vtable = @@ -43,7 +47,7 @@ static const struct _IO_jump_t _IO_mem_jumps libio_vtable = JUMP_INIT (pbackfail, _IO_str_pbackfail), JUMP_INIT (xsputn, _IO_default_xsputn), JUMP_INIT (xsgetn, _IO_default_xsgetn), - JUMP_INIT (seekoff, _IO_str_seekoff), + JUMP_INIT (seekoff, _IO_mem_seekoff), JUMP_INIT (seekpos, _IO_default_seekpos), JUMP_INIT (setbuf, _IO_default_setbuf), JUMP_INIT (sync, _IO_mem_sync), @@ -96,6 +100,26 @@ __open_memstream (char **bufloc, size_t *sizeloc) new_f->fp.bufloc = bufloc; new_f->fp.sizeloc = sizeloc; + /* To correctly report the buffer size the implementation must track both + the buffer size and currently bytes are written. However _IO_write_ptr + is updated on both write and seek operations (since some _IO_* function + access the pointer directly to optimize updates). So to track current + written bytes two fields are used: + + - prevwriteptr: track previous _IO_write_ptr before a seek operation on + the stream. + - seekwriteptr: track resulted _IO_write_ptr after a seek operation on + the stream. + + Also, prevwriteptr is only updated iff _IO_write_ptr changed over calls + (meaning that a write operation happened). + + So final buffer size is based on current _IO_write_ptr only if + its value is different than seekwriteptr. Otherwise it uses the old + _IO_write_ptr value before seek operation (prevwriteptr). */ + new_f->fp.prevwriteptr = new_f->fp.seekwriteptr = + new_f->fp._sf._sbf._f._IO_write_ptr; + /* Disable single thread optimization. BZ 21735. */ new_f->fp._sf._sbf._f._flags2 |= _IO_FLAGS2_NEED_LOCK; @@ -104,6 +128,21 @@ __open_memstream (char **bufloc, size_t *sizeloc) libc_hidden_def (__open_memstream) weak_alias (__open_memstream, open_memstream) +/* Update FP with SIZE number of bytes written and return true if a write + operation has occurred. */ +static bool +update_bufsize (const FILE *fp, size_t *size) +{ + const struct _IO_FILE_memstream *mp = + (const struct _IO_FILE_memstream *) fp; + if (fp->_IO_write_ptr == mp->seekwriteptr) + { + *size = mp->prevwriteptr - fp->_IO_write_base; + return false; + } + *size = fp->_IO_write_ptr - fp->_IO_write_base; + return true; +} static int _IO_mem_sync (FILE *fp) @@ -117,7 +156,7 @@ _IO_mem_sync (FILE *fp) } *mp->bufloc = fp->_IO_write_base; - *mp->sizeloc = fp->_IO_write_ptr - fp->_IO_write_base; + update_bufsize (fp, mp->sizeloc); return 0; } @@ -132,11 +171,23 @@ _IO_mem_finish (FILE *fp, int dummy) fp->_IO_write_ptr - fp->_IO_write_base + 1); if (*mp->bufloc != NULL) { - (*mp->bufloc)[fp->_IO_write_ptr - fp->_IO_write_base] = '\0'; - *mp->sizeloc = fp->_IO_write_ptr - fp->_IO_write_base; + /* An '\0' should be appended iff a write operation ocurred. */ + if (update_bufsize (fp, mp->sizeloc)) + (*mp->bufloc)[*mp->sizeloc] = '\0'; fp->_IO_buf_base = NULL; } _IO_str_finish (fp, 0); } + +static off64_t +_IO_mem_seekoff (FILE *fp, off64_t offset, int dir, int mode) +{ + struct _IO_FILE_memstream *mp = (struct _IO_FILE_memstream *) fp; + if (fp->_IO_write_ptr != mp->seekwriteptr) + mp->prevwriteptr = fp->_IO_write_ptr; + off64_t ret = _IO_str_seekoff (fp, offset, dir, mode); + mp->seekwriteptr = fp->_IO_write_ptr; + return ret; +} diff --git a/libio/tst-memstream3.c b/libio/tst-memstream3.c index abb8ffe2cc..946bb256b7 100644 --- a/libio/tst-memstream3.c +++ b/libio/tst-memstream3.c @@ -126,15 +126,17 @@ do_test_bz20181 (void) if (fflush (fp) != 0) ERROR_RET1 ("fflush failed (errno = %d)\n", errno); - /* Avoid truncating the buffer on close. */ + /* fseek updates the internal buffer, but open_memstream should set the + size to smaller of the buffer size and number of bytes written. Since + it was written just character ('z') final size should be 1. */ if (fseek (fp, 3, SEEK_SET) != 0) ERROR_RET1 ("fseek failed (errno = %d)\n", errno); if (fclose (fp) != 0) ERROR_RET1 ("fclose failed (errno = %d\n", errno); - if (size != 3) - ERROR_RET1 ("size != 3\n"); + if (size != 1) + ERROR_RET1 ("size != 1 (got %zu)\n", size); if (buf[0] != W('z') || buf[1] != W('b') diff --git a/libio/tst-memstream5.c b/libio/tst-memstream5.c new file mode 100644 index 0000000000..b1862e8a3d --- /dev/null +++ b/libio/tst-memstream5.c @@ -0,0 +1,73 @@ +/* Test for open_memstream BZ #15298. + Copyright (C) 2019 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 "tst-memstream.h" + +static void +mcheck_abort (enum mcheck_status ev) +{ + FAIL_EXIT1 ("mecheck failed with status %d\n", (int) ev); +} + +static int +do_test (void) +{ + mcheck_pedantic (mcheck_abort); + + { + CHAR_T *buf; + size_t size; + + FILE *fp = OPEN_MEMSTREAM (&buf, &size); + TEST_VERIFY_EXIT (fp != NULL); + + /* Move internal position but do not write any bytes. Final size should + be 0. */ + TEST_VERIFY_EXIT (fseek (fp, 10, SEEK_SET) != -1); + TEST_VERIFY_EXIT (fseek (fp, 20, SEEK_CUR) != -1); + TEST_VERIFY_EXIT (fseek (fp, 30, SEEK_CUR) != -1); + TEST_VERIFY_EXIT (fflush (fp) != -1); + TEST_VERIFY (size == 0); + + /* Now write some bytes and change internal position. Final size should + be based on written bytes. */ + TEST_VERIFY_EXIT (fseek (fp, 0, SEEK_SET) != -1); + TEST_VERIFY_EXIT (FWRITE (W("abc"), 1, 3, fp) == 3); + TEST_VERIFY_EXIT (fseek (fp, 20, SEEK_CUR) != -1); + TEST_VERIFY_EXIT (fseek (fp, 30, SEEK_CUR) != -1); + TEST_VERIFY_EXIT (fflush (fp) != -1); + TEST_VERIFY (size == 3); + + /* Finally set position, write some bytes and change position again. + Final size should be based again on write position. */ + size_t offset = 2048; + TEST_VERIFY_EXIT (fseek (fp, offset, SEEK_SET) != -1); + TEST_VERIFY_EXIT (FWRITE (W("def"), 1, 3, fp) == 3); + TEST_VERIFY_EXIT (fseek (fp, 20, SEEK_CUR) != -1); + TEST_VERIFY_EXIT (fseek (fp, 20, SEEK_CUR) != -1); + TEST_VERIFY_EXIT (fflush (fp) != -1); + TEST_VERIFY (size == (offset + 3)); + + TEST_VERIFY_EXIT (fclose (fp) == 0); + free (buf); + } + + return 0; +} + +#include diff --git a/libio/tst-wmemstream5.c b/libio/tst-wmemstream5.c new file mode 100644 index 0000000000..f2462679f3 --- /dev/null +++ b/libio/tst-wmemstream5.c @@ -0,0 +1,20 @@ +/* Test for open_wmemstream BZ #15298. + Copyright (C) 2019 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 + . */ + +#define TEST_WCHAR +#include diff --git a/libio/wmemstream.c b/libio/wmemstream.c index 3c201ec8a2..0f40d884c7 100644 --- a/libio/wmemstream.c +++ b/libio/wmemstream.c @@ -27,11 +27,15 @@ struct _IO_FILE_wmemstream _IO_strfile _sf; wchar_t **bufloc; size_t *sizeloc; + wchar_t *prevwriteptr; + wchar_t *seekwriteptr; }; static int _IO_wmem_sync (FILE* fp) __THROW; static void _IO_wmem_finish (FILE* fp, int) __THROW; +static off64_t _IO_wmem_seekoff (FILE *fp, off64_t offset, + int dir, int mode) __THROW; static const struct _IO_jump_t _IO_wmem_jumps libio_vtable = @@ -44,7 +48,7 @@ static const struct _IO_jump_t _IO_wmem_jumps libio_vtable = JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail), JUMP_INIT (xsputn, _IO_wdefault_xsputn), JUMP_INIT (xsgetn, _IO_wdefault_xsgetn), - JUMP_INIT (seekoff, _IO_wstr_seekoff), + JUMP_INIT (seekoff, _IO_wmem_seekoff), JUMP_INIT (seekpos, _IO_default_seekpos), JUMP_INIT (setbuf, _IO_default_setbuf), JUMP_INIT (sync, _IO_wmem_sync), @@ -98,12 +102,47 @@ open_wmemstream (wchar_t **bufloc, size_t *sizeloc) new_f->fp.bufloc = bufloc; new_f->fp.sizeloc = sizeloc; + /* To correctly report the buffer size the implementation must track both + the buffer size and currently bytes are written. However, _IO_write_ptr + is updated on both write and seek operations (since some _IO_* function + access the pointer directly to optimize updates). So to track current + written bytes two fields are used: + + - prevwriteptr: track previous _IO_write_ptr before a seek operation on + the stream. + - seekwriteptr: track resulted _IO_write_ptr after a seek operation on + the stream. + + Also, prevwriteptr is only updated iff _IO_write_ptr changed over calls + (meaning that a write operation happened). + + So final buffer size is based on current _IO_write_ptr only if + its value is different than seekwriteptr. Otherwise, it uses the old + _IO_write_ptr value before seek operation (prevwriteptr). */ + new_f->fp.prevwriteptr = new_f->fp.seekwriteptr = + new_f->fp._sf._sbf._f._wide_data->_IO_write_ptr; + /* Disable single thread optimization. BZ 21735. */ new_f->fp._sf._sbf._f._flags2 |= _IO_FLAGS2_NEED_LOCK; return (FILE *) &new_f->fp._sf._sbf; } +/* Update FP with SIZE number of bytes written and return true if a write + operation has occurred. */ +static bool +update_bufsize (const FILE *fp, size_t *size) +{ + const struct _IO_FILE_wmemstream *mp = + (const struct _IO_FILE_wmemstream *) fp; + if (fp->_wide_data->_IO_write_ptr == mp->seekwriteptr) + { + *size = mp->prevwriteptr - fp->_wide_data->_IO_write_base; + return false; + } + *size = fp->_wide_data->_IO_write_ptr - fp->_wide_data->_IO_write_base; + return true; +} static int _IO_wmem_sync (FILE *fp) @@ -117,13 +156,11 @@ _IO_wmem_sync (FILE *fp) } *mp->bufloc = fp->_wide_data->_IO_write_base; - *mp->sizeloc = (fp->_wide_data->_IO_write_ptr - - fp->_wide_data->_IO_write_base); + update_bufsize (fp, mp->sizeloc); return 0; } - static void _IO_wmem_finish (FILE *fp, int dummy) { @@ -135,13 +172,22 @@ _IO_wmem_finish (FILE *fp, int dummy) * sizeof (wchar_t)); if (*mp->bufloc != NULL) { - size_t len = (fp->_wide_data->_IO_write_ptr - - fp->_wide_data->_IO_write_base); - (*mp->bufloc)[len] = '\0'; - *mp->sizeloc = len; + if (update_bufsize (fp, mp->sizeloc)) + (*mp->bufloc)[*mp->sizeloc] = L'\0'; fp->_wide_data->_IO_buf_base = NULL; } _IO_wstr_finish (fp, 0); } + +static off64_t +_IO_wmem_seekoff (FILE *fp, off64_t offset, int dir, int mode) +{ + struct _IO_FILE_wmemstream *mp = (struct _IO_FILE_wmemstream *) fp; + if (fp->_wide_data->_IO_write_ptr != mp->seekwriteptr) + mp->prevwriteptr = fp->_wide_data->_IO_write_ptr; + off64_t ret = _IO_wstr_seekoff (fp, offset, dir, mode); + mp->seekwriteptr = fp->_wide_data->_IO_write_ptr; + return ret; +}