From patchwork Wed Apr 27 14:57:01 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 615703 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3qw33N5wTGz9syq for ; Thu, 28 Apr 2016 00:57:36 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b=GoBRPVrB; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id; q=dns; s= default; b=RTYLBZlVZXf3KzptvjTatMYNL2cGJ9fjHiypUn7yoN+7CDa85MCp8 Aj3G9c/xLiQtozn5kXLQEpwIAItJSIETz330NM4TdnP8yIEfaLbMh5L2g64Zi4EP U0VQYmPHa9jeTWdJIyPMTaaJBzX60xHn5emmxYzgsi5v4SQc/3wYnk= 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=z5UffvKtkhd54sRK9YfnQa12JJg=; b=GoBRPVrBs40GAaOzHE2IGQ/P8dL4 3w5yxfG7dWIhT3hYZfObeJjO5HFvCuwK+jvVlqIeWLZV0yUQgAnR8TZikxw4gJ0C 2gKntHQvuSQVcaDNLKtU2nWrtVilpaqHZmn0nBDJpBBEE5sJxY6YBgehcCxQbQpY pTGxQE/tZ/3OX2k= Received: (qmail 56061 invoked by alias); 27 Apr 2016 14:57:28 -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 56048 invoked by uid 89); 27 Apr 2016 14:57:28 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=5014 X-HELO: mail-yw0-f179.google.com X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id; bh=xej5UVxX1Q0Zolq6UGp1ujwtofxfN7VCvthHh+SsFsw=; b=JyewYWv+K2eB8BR4ZYSGpe3Gg1RniE259HXTAA4AO/vYAZQirwNrtP5/ZkpLu5SXhQ ggSzGEthdSA5Tx0zc6pqCfqPi9hSGL3wkDMhr82mKVrmc8ol+5ME545Dl2vepYPi5jMf Lpre3iiu7V5sg2YK+kiB02H9J8B3ulvUY5r15LH2YuDy7/L96awG4XVYABEl23Vge4JH B8Soc3SJCkbzRQj0WCAq7bbHM0BFmsXtx1u37vOInBQsPZl6JCgb0AESuua9owWAOmlS 4sV4+hArCyzPq56CFgoCefFnz1Pv3abW7BNVUNjZIwBl7pkj8LbhdXUlzfNTv3RwhW8Z XoyQ== X-Gm-Message-State: AOPr4FURxgkH1POZhb86NPCrWCsMHp12bODzqcF9wEdCYtAnSyQsubTNiiL/Vo0WBqAMy+XV X-Received: by 10.129.38.2 with SMTP id m2mr4906108ywm.128.1461769035945; Wed, 27 Apr 2016 07:57:15 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH] libio: Fix fmemopen append mode failure (BZ# 20005) Date: Wed, 27 Apr 2016 11:57:01 -0300 Message-Id: <1461769021-3707-1-git-send-email-adhemerval.zanella@linaro.org> Based on previous issue pointed out by Andreas Schwab, I noted fmemopen with append mode is showing some issue. The implementation does not account the file position correctly. The following example shows the failure: --- int main () { char buf[10] = "test"; FILE *fp = fmemopen (buf, 10, "a+"); fseek (fp, 0, SEEK_SET); int gr; if ((gr = getc (fp)) != 't' || (gr = getc (fp)) != 'e' || (gr = getc (fp)) != 's' || (gr = getc (fp)) != 't' || (gr = getc (fp)) != EOF) { printf ("%s: getc failed returned %i\n", __FUNCTION__, gr); return 1; } return 0; } --- This is due both how read and write operation update the buffer position, taking in consideration buffer lenght instead of maximum position defined by the open mode. This patch fixes it and also fixes fseek not returning EINVAL for invalid whence modes. Tested on x86_64 and i686. [BZ #20012] * libio/fmemopen.c (fmemopen_read): Use buffer maximum position, not length to calculate the buffer to read. (fmemopen_write): Set the buffer position based on bytes written. (fmemopen_seek): Return EINVAL for invalid whence modes. --- ChangeLog | 8 ++++ libio/fmemopen.c | 15 +++---- stdio-common/tst-fmemopen3.c | 93 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index f1084ee..712be81 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2016-04-27 Adhemerval Zanella + + [BZ #20012] + * libio/fmemopen.c (fmemopen_read): Use buffer maximum position, not + length to calculate the buffer to read. + (fmemopen_write): Set the buffer position based on bytes written. + (fmemopen_seek): Return EINVAL for invalid whence modes. + 2016-04-27 Florian Weimer [BZ #19831] diff --git a/libio/fmemopen.c b/libio/fmemopen.c index 9264b72..5097ca5 100644 --- a/libio/fmemopen.c +++ b/libio/fmemopen.c @@ -50,16 +50,14 @@ fmemopen_read (void *cookie, char *b, size_t s) if (c->pos + s > c->maxpos) { - if ((size_t) c->pos == c->maxpos) - return 0; - s = c->size - c->pos; + s = c->maxpos - c->pos; + if ((size_t) c->pos > c->maxpos) + s = 0; } memcpy (b, &(c->buffer[c->pos]), s); c->pos += s; - if ((size_t) c->pos > c->maxpos) - c->maxpos = c->pos; return s; } @@ -86,7 +84,7 @@ fmemopen_write (void *cookie, const char *b, size_t s) memcpy (&(c->buffer[pos]), b, s); - c->pos += s; + c->pos = pos + s; if ((size_t) c->pos > c->maxpos) { c->maxpos = c->pos; @@ -123,7 +121,10 @@ fmemopen_seek (void *cookie, _IO_off64_t *p, int w) } if (np < 0 || (size_t) np > c->size) - return -1; + { + __set_errno (EINVAL); + return -1; + } *p = c->pos = np; diff --git a/stdio-common/tst-fmemopen3.c b/stdio-common/tst-fmemopen3.c index 250f9ec..af11f20 100644 --- a/stdio-common/tst-fmemopen3.c +++ b/stdio-common/tst-fmemopen3.c @@ -186,6 +186,97 @@ do_test_read_seek_negative (void) } static int +do_test_write_append_2 (void) +{ + char buf[10] = "test"; + FILE *fp = fmemopen (buf, 10, "a+"); + size_t r = ftell (fp); + size_t e = strlen (buf); + if (r != e) + { + printf ("%s: ftell returned %zu, expected %zu\n", __FUNCTION__, r, e); + return 1; + } + + if (fseek (fp, 0, SEEK_SET) == -1) + { + printf ("%s: fseek returned -1\n", __FUNCTION__); + return 1; + } + + int gr; + if ((gr = getc (fp)) != 't' || + (gr = getc (fp)) != 'e' || + (gr = getc (fp)) != 's' || + (gr = getc (fp)) != 't' || + (gr = getc (fp)) != EOF) + { + printf ("%s: getc failed returned %i\n", __FUNCTION__, gr); + return 1; + } + + if (fseek (fp, e+1, SEEK_SET) == -1) + { + printf ("%s: fseek returned -1\n", __FUNCTION__); + return 1; + } + + if ((r = ftell (fp)) != e+1) + { + printf ("%s: ftell returned %zu, expected %zu\n", __FUNCTION__, r, e+1); + return 1; + } + + if ((gr = getc (fp)) != EOF) + { + printf ("%s: getc failed returned %i\n", __FUNCTION__, gr); + return 1; + } + + /* Check if internal position is not changed with a getc returning EOF. */ + if ((r = ftell (fp)) != e+1) + { + printf ("%s: ftell returned %zu, expected %zu\n", __FUNCTION__, r, e+1); + return 1; + } + + if (fseek (fp, 0, SEEK_CUR) == -1) + { + printf ("%s: fseek returned -1\n", __FUNCTION__); + return 1; + } + + /* This should be overwritten by fprintf + fflush. */ + buf[e+2] = 'X'; + + if ((r = fprintf (fp, "%d", 101)) != 3) + { + printf ("%s: fprintf returned %zu, expected %d\n", __FUNCTION__, r, 3); + return 1; + } + + fflush (fp); + + /* Check if internal position is changed by 3 (strlen of '101'). */ + if ((r = ftell (fp)) != e+3) + { + printf ("%s: ftell returned %zu, expected %zu\n", __FUNCTION__, r, e+3); + return 1; + } + + const char exp[] = "test101"; + if (strcmp (buf, exp) != 0) + { + printf ("%s: check failed: %s != %s\n", __FUNCTION__, buf, exp); + return 1; + } + + fclose(fp); + + return 0; +} + +static int do_test (void) { int ret = 0; @@ -199,6 +290,8 @@ do_test (void) ret += do_test_read_seek_negative (); + ret += do_test_write_append_2 (); + return ret; }