From patchwork Fri May 12 02:10:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238636 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 76962C7EE26 for ; Fri, 12 May 2023 02:11:36 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFE-0004hA-06; Thu, 11 May 2023 22:10:56 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFC-0004h1-3k for qemu-devel@nongnu.org; Thu, 11 May 2023 22:10:54 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIF0-0000MK-5Q for qemu-devel@nongnu.org; Thu, 11 May 2023 22:10:53 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857439; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=YPMPGQpEod/YHmBoNdjSM0dqQcQ9/jUKV+oAMZmeuSw=; b=dMIxHAgKeDwnRL0OE2vv2WybOpxqMIChRWDzt1NgzcM0gps+DS+jFE3cb5ZELpQ0ywmWZX KQ5KZ0Mc1nyB895rvu68+4AyumB4DD6/+ZR7ILyjmVXjF9dNGDnAa3T2iIZ5S6TE6QGg5J zKBqPS2jq/zsDtMfdi/YL/bwQRNaBb8= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-619-6TE6NgnbOYa3WSTcpBu20Q-1; Thu, 11 May 2023 22:10:37 -0400 X-MC-Unique: 6TE6NgnbOYa3WSTcpBu20Q-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 34796185A7A2; Fri, 12 May 2023 02:10:37 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id A9CDA2026D16; Fri, 12 May 2023 02:10:36 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 01/19] test-cutils: Avoid g_assert in unit tests Date: Thu, 11 May 2023 21:10:15 -0500 Message-Id: <20230512021033.1378730-2-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.129.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org glib documentation[1] is clear: g_assert() should be avoided in unit tests because it is ineffective if G_DISABLE_ASSERT is defined; unit tests should stick to constructs based on g_assert_true() instead. Note that since commit 262a69f428, we intentionally state that you cannot define G_DISABLE_ASSERT that while building qemu; but our code can be copied to other projects without that restriction, so we should be consistent. For most of the replacements in this patch, using g_assert_cmpstr() would be a regression in quality - although it would helpfully display the string contents of both pointers on test failure, here, we really do care about pointer equality, not just string content equality. But when a NULL pointer is expected, g_assert_null works fine. [1] https://libsoup.org/glib/glib-Testing.html#g-assert Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek Reviewed-by: Philippe Mathieu-Daudé --- tests/unit/test-cutils.c | 324 +++++++++++++++++++-------------------- 1 file changed, 162 insertions(+), 162 deletions(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 3c4f8754202..0202ac0d5b3 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -1,7 +1,7 @@ /* * cutils.c unit-tests * - * Copyright (C) 2013 Red Hat Inc. + * Copyright Red Hat * * Authors: * Eduardo Habkost @@ -40,7 +40,7 @@ static void test_parse_uint_null(void) g_assert_cmpint(r, ==, -EINVAL); g_assert_cmpint(i, ==, 0); - g_assert(endptr == NULL); + g_assert_null(endptr); } static void test_parse_uint_empty(void) @@ -55,7 +55,7 @@ static void test_parse_uint_empty(void) g_assert_cmpint(r, ==, -EINVAL); g_assert_cmpint(i, ==, 0); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_parse_uint_whitespace(void) @@ -70,7 +70,7 @@ static void test_parse_uint_whitespace(void) g_assert_cmpint(r, ==, -EINVAL); g_assert_cmpint(i, ==, 0); - g_assert(endptr == str); + g_assert_true(endptr == str); } @@ -86,7 +86,7 @@ static void test_parse_uint_invalid(void) g_assert_cmpint(r, ==, -EINVAL); g_assert_cmpint(i, ==, 0); - g_assert(endptr == str); + g_assert_true(endptr == str); } @@ -102,7 +102,7 @@ static void test_parse_uint_trailing(void) g_assert_cmpint(r, ==, 0); g_assert_cmpint(i, ==, 123); - g_assert(endptr == str + 3); + g_assert_true(endptr == str + 3); } static void test_parse_uint_correct(void) @@ -117,7 +117,7 @@ static void test_parse_uint_correct(void) g_assert_cmpint(r, ==, 0); g_assert_cmpint(i, ==, 123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_parse_uint_octal(void) @@ -132,7 +132,7 @@ static void test_parse_uint_octal(void) g_assert_cmpint(r, ==, 0); g_assert_cmpint(i, ==, 0123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_parse_uint_decimal(void) @@ -147,7 +147,7 @@ static void test_parse_uint_decimal(void) g_assert_cmpint(r, ==, 0); g_assert_cmpint(i, ==, 123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } @@ -163,7 +163,7 @@ static void test_parse_uint_llong_max(void) g_assert_cmpint(r, ==, 0); g_assert_cmpint(i, ==, (unsigned long long)LLONG_MAX + 1); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); g_free(str); } @@ -180,7 +180,7 @@ static void test_parse_uint_overflow(void) g_assert_cmpint(r, ==, -ERANGE); g_assert_cmpint(i, ==, ULLONG_MAX); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_parse_uint_negative(void) @@ -195,7 +195,7 @@ static void test_parse_uint_negative(void) g_assert_cmpint(r, ==, -ERANGE); g_assert_cmpint(i, ==, 0); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } @@ -235,7 +235,7 @@ static void test_qemu_strtoi_correct(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 12345); - g_assert(endptr == str + 5); + g_assert_true(endptr == str + 5); } static void test_qemu_strtoi_null(void) @@ -248,7 +248,7 @@ static void test_qemu_strtoi_null(void) err = qemu_strtoi(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == NULL); + g_assert_null(endptr); } static void test_qemu_strtoi_empty(void) @@ -262,7 +262,7 @@ static void test_qemu_strtoi_empty(void) err = qemu_strtoi(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtoi_whitespace(void) @@ -276,7 +276,7 @@ static void test_qemu_strtoi_whitespace(void) err = qemu_strtoi(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtoi_invalid(void) @@ -290,7 +290,7 @@ static void test_qemu_strtoi_invalid(void) err = qemu_strtoi(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtoi_trailing(void) @@ -305,7 +305,7 @@ static void test_qemu_strtoi_trailing(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 123); - g_assert(endptr == str + 3); + g_assert_true(endptr == str + 3); } static void test_qemu_strtoi_octal(void) @@ -320,7 +320,7 @@ static void test_qemu_strtoi_octal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); res = 999; endptr = &f; @@ -328,7 +328,7 @@ static void test_qemu_strtoi_octal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoi_decimal(void) @@ -343,7 +343,7 @@ static void test_qemu_strtoi_decimal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "123"; res = 999; @@ -352,7 +352,7 @@ static void test_qemu_strtoi_decimal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoi_hex(void) @@ -367,7 +367,7 @@ static void test_qemu_strtoi_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "0x123"; res = 999; @@ -376,7 +376,7 @@ static void test_qemu_strtoi_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "0x"; res = 999; @@ -385,7 +385,7 @@ static void test_qemu_strtoi_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0); - g_assert(endptr == str + 1); + g_assert_true(endptr == str + 1); } static void test_qemu_strtoi_max(void) @@ -400,7 +400,7 @@ static void test_qemu_strtoi_max(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, INT_MAX); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); g_free(str); } @@ -416,7 +416,7 @@ static void test_qemu_strtoi_overflow(void) g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpint(res, ==, INT_MAX); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); g_free(str); } @@ -432,7 +432,7 @@ static void test_qemu_strtoi_underflow(void) g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpint(res, ==, INT_MIN); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); g_free(str); } @@ -448,7 +448,7 @@ static void test_qemu_strtoi_negative(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, -321); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoi_full_correct(void) @@ -473,7 +473,7 @@ static void test_qemu_strtoi_full_null(void) err = qemu_strtoi(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == NULL); + g_assert_null(endptr); } static void test_qemu_strtoi_full_empty(void) @@ -535,7 +535,7 @@ static void test_qemu_strtoui_correct(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 12345); - g_assert(endptr == str + 5); + g_assert_true(endptr == str + 5); } static void test_qemu_strtoui_null(void) @@ -548,7 +548,7 @@ static void test_qemu_strtoui_null(void) err = qemu_strtoui(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == NULL); + g_assert_null(endptr); } static void test_qemu_strtoui_empty(void) @@ -562,7 +562,7 @@ static void test_qemu_strtoui_empty(void) err = qemu_strtoui(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtoui_whitespace(void) @@ -576,7 +576,7 @@ static void test_qemu_strtoui_whitespace(void) err = qemu_strtoui(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtoui_invalid(void) @@ -590,7 +590,7 @@ static void test_qemu_strtoui_invalid(void) err = qemu_strtoui(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtoui_trailing(void) @@ -605,7 +605,7 @@ static void test_qemu_strtoui_trailing(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 123); - g_assert(endptr == str + 3); + g_assert_true(endptr == str + 3); } static void test_qemu_strtoui_octal(void) @@ -620,7 +620,7 @@ static void test_qemu_strtoui_octal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 0123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); res = 999; endptr = &f; @@ -628,7 +628,7 @@ static void test_qemu_strtoui_octal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 0123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoui_decimal(void) @@ -643,7 +643,7 @@ static void test_qemu_strtoui_decimal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "123"; res = 999; @@ -652,7 +652,7 @@ static void test_qemu_strtoui_decimal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoui_hex(void) @@ -667,7 +667,7 @@ static void test_qemu_strtoui_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, 0x123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "0x123"; res = 999; @@ -676,7 +676,7 @@ static void test_qemu_strtoui_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, 0x123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "0x"; res = 999; @@ -685,7 +685,7 @@ static void test_qemu_strtoui_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, 0); - g_assert(endptr == str + 1); + g_assert_true(endptr == str + 1); } static void test_qemu_strtoui_max(void) @@ -700,7 +700,7 @@ static void test_qemu_strtoui_max(void) g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, UINT_MAX); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); g_free(str); } @@ -716,7 +716,7 @@ static void test_qemu_strtoui_overflow(void) g_assert_cmpint(err, ==, -ERANGE); g_assert_cmphex(res, ==, UINT_MAX); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); g_free(str); } @@ -732,7 +732,7 @@ static void test_qemu_strtoui_underflow(void) g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpuint(res, ==, (unsigned int)-1); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); g_free(str); } @@ -748,7 +748,7 @@ static void test_qemu_strtoui_negative(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, (unsigned int)-321); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoui_full_correct(void) @@ -830,7 +830,7 @@ static void test_qemu_strtol_correct(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 12345); - g_assert(endptr == str + 5); + g_assert_true(endptr == str + 5); } static void test_qemu_strtol_null(void) @@ -843,7 +843,7 @@ static void test_qemu_strtol_null(void) err = qemu_strtol(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == NULL); + g_assert_null(endptr); } static void test_qemu_strtol_empty(void) @@ -857,7 +857,7 @@ static void test_qemu_strtol_empty(void) err = qemu_strtol(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtol_whitespace(void) @@ -871,7 +871,7 @@ static void test_qemu_strtol_whitespace(void) err = qemu_strtol(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtol_invalid(void) @@ -885,7 +885,7 @@ static void test_qemu_strtol_invalid(void) err = qemu_strtol(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtol_trailing(void) @@ -900,7 +900,7 @@ static void test_qemu_strtol_trailing(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 123); - g_assert(endptr == str + 3); + g_assert_true(endptr == str + 3); } static void test_qemu_strtol_octal(void) @@ -915,7 +915,7 @@ static void test_qemu_strtol_octal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); res = 999; endptr = &f; @@ -923,7 +923,7 @@ static void test_qemu_strtol_octal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtol_decimal(void) @@ -938,7 +938,7 @@ static void test_qemu_strtol_decimal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "123"; res = 999; @@ -947,7 +947,7 @@ static void test_qemu_strtol_decimal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtol_hex(void) @@ -962,7 +962,7 @@ static void test_qemu_strtol_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "0x123"; res = 999; @@ -971,7 +971,7 @@ static void test_qemu_strtol_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "0x"; res = 999; @@ -980,7 +980,7 @@ static void test_qemu_strtol_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0); - g_assert(endptr == str + 1); + g_assert_true(endptr == str + 1); } static void test_qemu_strtol_max(void) @@ -995,7 +995,7 @@ static void test_qemu_strtol_max(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, LONG_MAX); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); g_free(str); } @@ -1011,7 +1011,7 @@ static void test_qemu_strtol_overflow(void) g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpint(res, ==, LONG_MAX); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtol_underflow(void) @@ -1026,7 +1026,7 @@ static void test_qemu_strtol_underflow(void) g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpint(res, ==, LONG_MIN); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtol_negative(void) @@ -1041,7 +1041,7 @@ static void test_qemu_strtol_negative(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, -321); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtol_full_correct(void) @@ -1066,7 +1066,7 @@ static void test_qemu_strtol_full_null(void) err = qemu_strtol(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == NULL); + g_assert_null(endptr); } static void test_qemu_strtol_full_empty(void) @@ -1128,7 +1128,7 @@ static void test_qemu_strtoul_correct(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 12345); - g_assert(endptr == str + 5); + g_assert_true(endptr == str + 5); } static void test_qemu_strtoul_null(void) @@ -1141,7 +1141,7 @@ static void test_qemu_strtoul_null(void) err = qemu_strtoul(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == NULL); + g_assert_null(endptr); } static void test_qemu_strtoul_empty(void) @@ -1155,7 +1155,7 @@ static void test_qemu_strtoul_empty(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtoul_whitespace(void) @@ -1169,7 +1169,7 @@ static void test_qemu_strtoul_whitespace(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtoul_invalid(void) @@ -1183,7 +1183,7 @@ static void test_qemu_strtoul_invalid(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtoul_trailing(void) @@ -1198,7 +1198,7 @@ static void test_qemu_strtoul_trailing(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 123); - g_assert(endptr == str + 3); + g_assert_true(endptr == str + 3); } static void test_qemu_strtoul_octal(void) @@ -1213,7 +1213,7 @@ static void test_qemu_strtoul_octal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 0123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); res = 999; endptr = &f; @@ -1221,7 +1221,7 @@ static void test_qemu_strtoul_octal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 0123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoul_decimal(void) @@ -1236,7 +1236,7 @@ static void test_qemu_strtoul_decimal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "123"; res = 999; @@ -1245,7 +1245,7 @@ static void test_qemu_strtoul_decimal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoul_hex(void) @@ -1260,7 +1260,7 @@ static void test_qemu_strtoul_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, 0x123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "0x123"; res = 999; @@ -1269,7 +1269,7 @@ static void test_qemu_strtoul_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, 0x123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "0x"; res = 999; @@ -1278,7 +1278,7 @@ static void test_qemu_strtoul_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, 0); - g_assert(endptr == str + 1); + g_assert_true(endptr == str + 1); } static void test_qemu_strtoul_max(void) @@ -1293,7 +1293,7 @@ static void test_qemu_strtoul_max(void) g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, ULONG_MAX); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); g_free(str); } @@ -1309,7 +1309,7 @@ static void test_qemu_strtoul_overflow(void) g_assert_cmpint(err, ==, -ERANGE); g_assert_cmphex(res, ==, ULONG_MAX); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoul_underflow(void) @@ -1324,7 +1324,7 @@ static void test_qemu_strtoul_underflow(void) g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpuint(res, ==, -1ul); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoul_negative(void) @@ -1339,7 +1339,7 @@ static void test_qemu_strtoul_negative(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, -321ul); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoul_full_correct(void) @@ -1421,7 +1421,7 @@ static void test_qemu_strtoi64_correct(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 12345); - g_assert(endptr == str + 5); + g_assert_true(endptr == str + 5); } static void test_qemu_strtoi64_null(void) @@ -1434,7 +1434,7 @@ static void test_qemu_strtoi64_null(void) err = qemu_strtoi64(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == NULL); + g_assert_null(endptr); } static void test_qemu_strtoi64_empty(void) @@ -1448,7 +1448,7 @@ static void test_qemu_strtoi64_empty(void) err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtoi64_whitespace(void) @@ -1462,7 +1462,7 @@ static void test_qemu_strtoi64_whitespace(void) err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtoi64_invalid(void) @@ -1476,7 +1476,7 @@ static void test_qemu_strtoi64_invalid(void) err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtoi64_trailing(void) @@ -1491,7 +1491,7 @@ static void test_qemu_strtoi64_trailing(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 123); - g_assert(endptr == str + 3); + g_assert_true(endptr == str + 3); } static void test_qemu_strtoi64_octal(void) @@ -1506,7 +1506,7 @@ static void test_qemu_strtoi64_octal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); endptr = &f; res = 999; @@ -1514,7 +1514,7 @@ static void test_qemu_strtoi64_octal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoi64_decimal(void) @@ -1529,7 +1529,7 @@ static void test_qemu_strtoi64_decimal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "123"; endptr = &f; @@ -1538,7 +1538,7 @@ static void test_qemu_strtoi64_decimal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoi64_hex(void) @@ -1553,7 +1553,7 @@ static void test_qemu_strtoi64_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "0x123"; endptr = &f; @@ -1562,7 +1562,7 @@ static void test_qemu_strtoi64_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "0x"; endptr = &f; @@ -1571,7 +1571,7 @@ static void test_qemu_strtoi64_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0); - g_assert(endptr == str + 1); + g_assert_true(endptr == str + 1); } static void test_qemu_strtoi64_max(void) @@ -1586,7 +1586,7 @@ static void test_qemu_strtoi64_max(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, LLONG_MAX); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); g_free(str); } @@ -1602,7 +1602,7 @@ static void test_qemu_strtoi64_overflow(void) g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpint(res, ==, LLONG_MAX); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoi64_underflow(void) @@ -1617,7 +1617,7 @@ static void test_qemu_strtoi64_underflow(void) g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpint(res, ==, LLONG_MIN); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoi64_negative(void) @@ -1632,7 +1632,7 @@ static void test_qemu_strtoi64_negative(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, -321); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoi64_full_correct(void) @@ -1717,7 +1717,7 @@ static void test_qemu_strtou64_correct(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 12345); - g_assert(endptr == str + 5); + g_assert_true(endptr == str + 5); } static void test_qemu_strtou64_null(void) @@ -1730,7 +1730,7 @@ static void test_qemu_strtou64_null(void) err = qemu_strtou64(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == NULL); + g_assert_null(endptr); } static void test_qemu_strtou64_empty(void) @@ -1744,7 +1744,7 @@ static void test_qemu_strtou64_empty(void) err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtou64_whitespace(void) @@ -1758,7 +1758,7 @@ static void test_qemu_strtou64_whitespace(void) err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtou64_invalid(void) @@ -1772,7 +1772,7 @@ static void test_qemu_strtou64_invalid(void) err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtou64_trailing(void) @@ -1787,7 +1787,7 @@ static void test_qemu_strtou64_trailing(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 123); - g_assert(endptr == str + 3); + g_assert_true(endptr == str + 3); } static void test_qemu_strtou64_octal(void) @@ -1802,7 +1802,7 @@ static void test_qemu_strtou64_octal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 0123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); endptr = &f; res = 999; @@ -1810,7 +1810,7 @@ static void test_qemu_strtou64_octal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 0123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtou64_decimal(void) @@ -1825,7 +1825,7 @@ static void test_qemu_strtou64_decimal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "123"; endptr = &f; @@ -1834,7 +1834,7 @@ static void test_qemu_strtou64_decimal(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtou64_hex(void) @@ -1849,7 +1849,7 @@ static void test_qemu_strtou64_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, 0x123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "0x123"; endptr = &f; @@ -1858,7 +1858,7 @@ static void test_qemu_strtou64_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, 0x123); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); str = "0x"; endptr = &f; @@ -1867,7 +1867,7 @@ static void test_qemu_strtou64_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, 0); - g_assert(endptr == str + 1); + g_assert_true(endptr == str + 1); } static void test_qemu_strtou64_max(void) @@ -1882,7 +1882,7 @@ static void test_qemu_strtou64_max(void) g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, ULLONG_MAX); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); g_free(str); } @@ -1898,7 +1898,7 @@ static void test_qemu_strtou64_overflow(void) g_assert_cmpint(err, ==, -ERANGE); g_assert_cmphex(res, ==, ULLONG_MAX); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtou64_underflow(void) @@ -1913,7 +1913,7 @@ static void test_qemu_strtou64_underflow(void) g_assert_cmpint(err, ==, -ERANGE); g_assert_cmphex(res, ==, -1ull); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtou64_negative(void) @@ -1928,7 +1928,7 @@ static void test_qemu_strtou64_negative(void) g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, -321ull); - g_assert(endptr == str + strlen(str)); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtou64_full_correct(void) @@ -2013,7 +2013,7 @@ static void test_qemu_strtosz_simple(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0); - g_assert(endptr == str + 1); + g_assert_true(endptr == str + 1); /* Leading 0 gives decimal results, not octal */ str = "08"; @@ -2022,7 +2022,7 @@ static void test_qemu_strtosz_simple(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 8); - g_assert(endptr == str + 2); + g_assert_true(endptr == str + 2); /* Leading space is ignored */ str = " 12345"; @@ -2031,7 +2031,7 @@ static void test_qemu_strtosz_simple(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 12345); - g_assert(endptr == str + 6); + g_assert_true(endptr == str + 6); res = 0xbaadf00d; err = qemu_strtosz(str, NULL, &res); @@ -2044,7 +2044,7 @@ static void test_qemu_strtosz_simple(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x1fffffffffffff); - g_assert(endptr == str + 16); + g_assert_true(endptr == str + 16); str = "9007199254740992"; /* 2^53 */ endptr = str; @@ -2052,7 +2052,7 @@ static void test_qemu_strtosz_simple(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x20000000000000); - g_assert(endptr == str + 16); + g_assert_true(endptr == str + 16); str = "9007199254740993"; /* 2^53+1 */ endptr = str; @@ -2060,7 +2060,7 @@ static void test_qemu_strtosz_simple(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x20000000000001); - g_assert(endptr == str + 16); + g_assert_true(endptr == str + 16); str = "18446744073709549568"; /* 0xfffffffffffff800 (53 msbs set) */ endptr = str; @@ -2068,7 +2068,7 @@ static void test_qemu_strtosz_simple(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0xfffffffffffff800); - g_assert(endptr == str + 20); + g_assert_true(endptr == str + 20); str = "18446744073709550591"; /* 0xfffffffffffffbff */ endptr = str; @@ -2076,7 +2076,7 @@ static void test_qemu_strtosz_simple(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0xfffffffffffffbff); - g_assert(endptr == str + 20); + g_assert_true(endptr == str + 20); str = "18446744073709551615"; /* 0xffffffffffffffff */ endptr = str; @@ -2084,7 +2084,7 @@ static void test_qemu_strtosz_simple(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0xffffffffffffffff); - g_assert(endptr == str + 20); + g_assert_true(endptr == str + 20); } static void test_qemu_strtosz_hex(void) @@ -2100,7 +2100,7 @@ static void test_qemu_strtosz_hex(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0); - g_assert(endptr == str + 3); + g_assert_true(endptr == str + 3); str = "0xab"; endptr = str; @@ -2108,7 +2108,7 @@ static void test_qemu_strtosz_hex(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 171); - g_assert(endptr == str + 4); + g_assert_true(endptr == str + 4); str = "0xae"; endptr = str; @@ -2116,7 +2116,7 @@ static void test_qemu_strtosz_hex(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 174); - g_assert(endptr == str + 4); + g_assert_true(endptr == str + 4); } static void test_qemu_strtosz_units(void) @@ -2139,56 +2139,56 @@ static void test_qemu_strtosz_units(void) err = qemu_strtosz_MiB(none, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, MiB); - g_assert(endptr == none + 1); + g_assert_true(endptr == none + 1); endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(b, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 1); - g_assert(endptr == b + 2); + g_assert_true(endptr == b + 2); endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(k, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, KiB); - g_assert(endptr == k + 2); + g_assert_true(endptr == k + 2); endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(m, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, MiB); - g_assert(endptr == m + 2); + g_assert_true(endptr == m + 2); endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(g, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, GiB); - g_assert(endptr == g + 2); + g_assert_true(endptr == g + 2); endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(t, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, TiB); - g_assert(endptr == t + 2); + g_assert_true(endptr == t + 2); endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(p, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, PiB); - g_assert(endptr == p + 2); + g_assert_true(endptr == p + 2); endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(e, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, EiB); - g_assert(endptr == e + 2); + g_assert_true(endptr == e + 2); } static void test_qemu_strtosz_float(void) @@ -2204,7 +2204,7 @@ static void test_qemu_strtosz_float(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, EiB / 2); - g_assert(endptr == str + 4); + g_assert_true(endptr == str + 4); /* For convenience, a fraction of 0 is tolerated even on bytes */ str = "1.0B"; @@ -2213,7 +2213,7 @@ static void test_qemu_strtosz_float(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 1); - g_assert(endptr == str + 4); + g_assert_true(endptr == str + 4); /* An empty fraction is tolerated */ str = "1.k"; @@ -2222,7 +2222,7 @@ static void test_qemu_strtosz_float(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 1024); - g_assert(endptr == str + 3); + g_assert_true(endptr == str + 3); /* For convenience, we permit values that are not byte-exact */ str = "12.345M"; @@ -2231,7 +2231,7 @@ static void test_qemu_strtosz_float(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, (uint64_t) (12.345 * MiB + 0.5)); - g_assert(endptr == str + 7); + g_assert_true(endptr == str + 7); } static void test_qemu_strtosz_invalid(void) @@ -2246,35 +2246,35 @@ static void test_qemu_strtosz_invalid(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert_cmpint(res, ==, 0xbaadf00d); - g_assert(endptr == str); + g_assert_true(endptr == str); str = " \t "; endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert_cmpint(res, ==, 0xbaadf00d); - g_assert(endptr == str); + g_assert_true(endptr == str); str = "crap"; endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert_cmpint(res, ==, 0xbaadf00d); - g_assert(endptr == str); + g_assert_true(endptr == str); str = "inf"; endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert_cmpint(res, ==, 0xbaadf00d); - g_assert(endptr == str); + g_assert_true(endptr == str); str = "NaN"; endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert_cmpint(res, ==, 0xbaadf00d); - g_assert(endptr == str); + g_assert_true(endptr == str); /* Fractional values require scale larger than bytes */ str = "1.1B"; @@ -2282,14 +2282,14 @@ static void test_qemu_strtosz_invalid(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert_cmpint(res, ==, 0xbaadf00d); - g_assert(endptr == str); + g_assert_true(endptr == str); str = "1.1"; endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert_cmpint(res, ==, 0xbaadf00d); - g_assert(endptr == str); + g_assert_true(endptr == str); /* No floating point exponents */ str = "1.5e1k"; @@ -2297,14 +2297,14 @@ static void test_qemu_strtosz_invalid(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert_cmpint(res, ==, 0xbaadf00d); - g_assert(endptr == str); + g_assert_true(endptr == str); str = "1.5E+0k"; endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert_cmpint(res, ==, 0xbaadf00d); - g_assert(endptr == str); + g_assert_true(endptr == str); /* No hex fractions */ str = "0x1.8k"; @@ -2312,7 +2312,7 @@ static void test_qemu_strtosz_invalid(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert_cmpint(res, ==, 0xbaadf00d); - g_assert(endptr == str); + g_assert_true(endptr == str); /* No suffixes */ str = "0x18M"; @@ -2320,7 +2320,7 @@ static void test_qemu_strtosz_invalid(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert_cmpint(res, ==, 0xbaadf00d); - g_assert(endptr == str); + g_assert_true(endptr == str); /* No negative values */ str = "-0"; @@ -2328,14 +2328,14 @@ static void test_qemu_strtosz_invalid(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert_cmpint(res, ==, 0xbaadf00d); - g_assert(endptr == str); + g_assert_true(endptr == str); str = "-1"; endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert_cmpint(res, ==, 0xbaadf00d); - g_assert(endptr == str); + g_assert_true(endptr == str); } static void test_qemu_strtosz_trailing(void) @@ -2351,7 +2351,7 @@ static void test_qemu_strtosz_trailing(void) err = qemu_strtosz_MiB(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 123 * MiB); - g_assert(endptr == str + 3); + g_assert_true(endptr == str + 3); res = 0xbaadf00d; err = qemu_strtosz(str, NULL, &res); @@ -2364,7 +2364,7 @@ static void test_qemu_strtosz_trailing(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 1024); - g_assert(endptr == str + 2); + g_assert_true(endptr == str + 2); res = 0xbaadf00d; err = qemu_strtosz(str, NULL, &res); @@ -2377,7 +2377,7 @@ static void test_qemu_strtosz_trailing(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0); - g_assert(endptr == str + 1); + g_assert_true(endptr == str + 1); res = 0xbaadf00d; err = qemu_strtosz(str, NULL, &res); @@ -2390,7 +2390,7 @@ static void test_qemu_strtosz_trailing(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0); - g_assert(endptr == str + 2); + g_assert_true(endptr == str + 2); res = 0xbaadf00d; err = qemu_strtosz(str, NULL, &res); @@ -2403,7 +2403,7 @@ static void test_qemu_strtosz_trailing(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 123); - g_assert(endptr == str + 3); + g_assert_true(endptr == str + 3); res = 0xbaadf00d; err = qemu_strtosz(str, NULL, &res); @@ -2423,14 +2423,14 @@ static void test_qemu_strtosz_erange(void) err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpint(res, ==, 0xbaadf00d); - g_assert(endptr == str + 20); + g_assert_true(endptr == str + 20); str = "20E"; endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpint(res, ==, 0xbaadf00d); - g_assert(endptr == str + 3); + g_assert_true(endptr == str + 3); } static void test_qemu_strtosz_metric(void) @@ -2446,7 +2446,7 @@ static void test_qemu_strtosz_metric(void) err = qemu_strtosz_metric(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 12345000); - g_assert(endptr == str + 6); + g_assert_true(endptr == str + 6); str = "12.345M"; endptr = str; @@ -2454,7 +2454,7 @@ static void test_qemu_strtosz_metric(void) err = qemu_strtosz_metric(str, &endptr, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 12345000); - g_assert(endptr == str + 7); + g_assert_true(endptr == str + 7); } static void test_freq_to_str(void) From patchwork Fri May 12 02:10:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238635 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id EF483C7EE22 for ; Fri, 12 May 2023 02:11:35 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFG-0004hs-8V; Thu, 11 May 2023 22:10:58 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFE-0004hQ-TV for qemu-devel@nongnu.org; Thu, 11 May 2023 22:10:57 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIF2-0000O0-53 for qemu-devel@nongnu.org; Thu, 11 May 2023 22:10:56 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857441; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DnE5yLigiX1fw/dmNhgD7Ngi+RE5sDYe9MFcSHBcs9g=; b=GCSaKJF2b1SyH4Su5/ZtcsZCBo/99bwv118OgBa5kUd5h1gmHVDPBbaen5zNs1R8xAjGXQ DhabXgthhfmhsyBcJSPRLluOH2g2quCxCkpqkLfsp97qIk3D0nw2megfqCuX5bHX2u7nEb VEIlFxjFZmn9uKw7Sp8ftOuF4Vk4t0c= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-584-HOT6ulQHNM-ikUkGQ0cY-g-1; Thu, 11 May 2023 22:10:38 -0400 X-MC-Unique: HOT6ulQHNM-ikUkGQ0cY-g-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id CC5D1101A552; Fri, 12 May 2023 02:10:37 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id 684272026D16; Fri, 12 May 2023 02:10:37 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 02/19] test-cutils: Use g_assert_cmpuint where appropriate Date: Thu, 11 May 2023 21:10:16 -0500 Message-Id: <20230512021033.1378730-3-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -16 X-Spam_score: -1.7 X-Spam_bar: - X-Spam_report: (-1.7 / 5.0 requ) BAYES_00=-1.9, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org When debugging test failures, seeing unsigned values as large positive values rather than negative values matters (assuming glib 2.78+; given that I just fixed a bug in glib 2.76 [1] where g_assert_cmpuint displays signed instead of unsigned values). No impact when the test is passing, but using a consistent style will matter more in upcoming test additions. Also, some tests are better with cmphex. While at it, fix some spacing and minor typing issues spotted nearby. [1] https://gitlab.gnome.org/GNOME/glib/-/issues/2997 Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek --- tests/unit/test-cutils.c | 148 +++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 0202ac0d5b3..38bd3990207 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -39,7 +39,7 @@ static void test_parse_uint_null(void) r = parse_uint(NULL, &i, &endptr, 0); g_assert_cmpint(r, ==, -EINVAL); - g_assert_cmpint(i, ==, 0); + g_assert_cmpuint(i, ==, 0); g_assert_null(endptr); } @@ -54,7 +54,7 @@ static void test_parse_uint_empty(void) r = parse_uint(str, &i, &endptr, 0); g_assert_cmpint(r, ==, -EINVAL); - g_assert_cmpint(i, ==, 0); + g_assert_cmpuint(i, ==, 0); g_assert_true(endptr == str); } @@ -69,7 +69,7 @@ static void test_parse_uint_whitespace(void) r = parse_uint(str, &i, &endptr, 0); g_assert_cmpint(r, ==, -EINVAL); - g_assert_cmpint(i, ==, 0); + g_assert_cmpuint(i, ==, 0); g_assert_true(endptr == str); } @@ -85,7 +85,7 @@ static void test_parse_uint_invalid(void) r = parse_uint(str, &i, &endptr, 0); g_assert_cmpint(r, ==, -EINVAL); - g_assert_cmpint(i, ==, 0); + g_assert_cmpuint(i, ==, 0); g_assert_true(endptr == str); } @@ -101,7 +101,7 @@ static void test_parse_uint_trailing(void) r = parse_uint(str, &i, &endptr, 0); g_assert_cmpint(r, ==, 0); - g_assert_cmpint(i, ==, 123); + g_assert_cmpuint(i, ==, 123); g_assert_true(endptr == str + 3); } @@ -116,7 +116,7 @@ static void test_parse_uint_correct(void) r = parse_uint(str, &i, &endptr, 0); g_assert_cmpint(r, ==, 0); - g_assert_cmpint(i, ==, 123); + g_assert_cmpuint(i, ==, 123); g_assert_true(endptr == str + strlen(str)); } @@ -131,7 +131,7 @@ static void test_parse_uint_octal(void) r = parse_uint(str, &i, &endptr, 0); g_assert_cmpint(r, ==, 0); - g_assert_cmpint(i, ==, 0123); + g_assert_cmpuint(i, ==, 0123); g_assert_true(endptr == str + strlen(str)); } @@ -146,7 +146,7 @@ static void test_parse_uint_decimal(void) r = parse_uint(str, &i, &endptr, 10); g_assert_cmpint(r, ==, 0); - g_assert_cmpint(i, ==, 123); + g_assert_cmpuint(i, ==, 123); g_assert_true(endptr == str + strlen(str)); } @@ -162,7 +162,7 @@ static void test_parse_uint_llong_max(void) r = parse_uint(str, &i, &endptr, 0); g_assert_cmpint(r, ==, 0); - g_assert_cmpint(i, ==, (unsigned long long)LLONG_MAX + 1); + g_assert_cmpuint(i, ==, (unsigned long long)LLONG_MAX + 1); g_assert_true(endptr == str + strlen(str)); g_free(str); @@ -179,7 +179,7 @@ static void test_parse_uint_overflow(void) r = parse_uint(str, &i, &endptr, 0); g_assert_cmpint(r, ==, -ERANGE); - g_assert_cmpint(i, ==, ULLONG_MAX); + g_assert_cmpuint(i, ==, ULLONG_MAX); g_assert_true(endptr == str + strlen(str)); } @@ -194,7 +194,7 @@ static void test_parse_uint_negative(void) r = parse_uint(str, &i, &endptr, 0); g_assert_cmpint(r, ==, -ERANGE); - g_assert_cmpint(i, ==, 0); + g_assert_cmpuint(i, ==, 0); g_assert_true(endptr == str + strlen(str)); } @@ -208,7 +208,7 @@ static void test_parse_uint_full_trailing(void) r = parse_uint_full(str, &i, 0); g_assert_cmpint(r, ==, -EINVAL); - g_assert_cmpint(i, ==, 0); + g_assert_cmpuint(i, ==, 0); } static void test_parse_uint_full_correct(void) @@ -220,7 +220,7 @@ static void test_parse_uint_full_correct(void) r = parse_uint_full(str, &i, 0); g_assert_cmpint(r, ==, 0); - g_assert_cmpint(i, ==, 123); + g_assert_cmpuint(i, ==, 123); } static void test_qemu_strtoi_correct(void) @@ -428,7 +428,7 @@ static void test_qemu_strtoi_underflow(void) int res = 999; int err; - err = qemu_strtoi(str, &endptr, 0, &res); + err = qemu_strtoi(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpint(res, ==, INT_MIN); @@ -479,10 +479,10 @@ static void test_qemu_strtoi_full_null(void) static void test_qemu_strtoi_full_empty(void) { const char *str = ""; - int res = 999L; + int res = 999; int err; - err = qemu_strtoi(str, NULL, 0, &res); + err = qemu_strtoi(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); } @@ -728,7 +728,7 @@ static void test_qemu_strtoui_underflow(void) unsigned int res = 999; int err; - err = qemu_strtoui(str, &endptr, 0, &res); + err = qemu_strtoui(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpuint(res, ==, (unsigned int)-1); @@ -1022,7 +1022,7 @@ static void test_qemu_strtol_underflow(void) long res = 999; int err; - err = qemu_strtol(str, &endptr, 0, &res); + err = qemu_strtol(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpint(res, ==, LONG_MIN); @@ -1075,7 +1075,7 @@ static void test_qemu_strtol_full_empty(void) long res = 999L; int err; - err = qemu_strtol(str, NULL, 0, &res); + err = qemu_strtol(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); } @@ -1320,7 +1320,7 @@ static void test_qemu_strtoul_underflow(void) unsigned long res = 999; int err; - err = qemu_strtoul(str, &endptr, 0, &res); + err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpuint(res, ==, -1ul); @@ -1613,7 +1613,7 @@ static void test_qemu_strtoi64_underflow(void) int64_t res = 999; int err; - err = qemu_strtoi64(str, &endptr, 0, &res); + err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpint(res, ==, LLONG_MIN); @@ -1909,7 +1909,7 @@ static void test_qemu_strtou64_underflow(void) uint64_t res = 999; int err; - err = qemu_strtou64(str, &endptr, 0, &res); + err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); g_assert_cmphex(res, ==, -1ull); @@ -2012,7 +2012,7 @@ static void test_qemu_strtosz_simple(void) res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0); + g_assert_cmpuint(res, ==, 0); g_assert_true(endptr == str + 1); /* Leading 0 gives decimal results, not octal */ @@ -2021,7 +2021,7 @@ static void test_qemu_strtosz_simple(void) res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 8); + g_assert_cmpuint(res, ==, 8); g_assert_true(endptr == str + 2); /* Leading space is ignored */ @@ -2030,20 +2030,20 @@ static void test_qemu_strtosz_simple(void) res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 12345); + g_assert_cmpuint(res, ==, 12345); g_assert_true(endptr == str + 6); res = 0xbaadf00d; err = qemu_strtosz(str, NULL, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 12345); + g_assert_cmpuint(res, ==, 12345); str = "9007199254740991"; /* 2^53-1 */ endptr = str; res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0x1fffffffffffff); + g_assert_cmphex(res, ==, 0x1fffffffffffffULL); g_assert_true(endptr == str + 16); str = "9007199254740992"; /* 2^53 */ @@ -2051,7 +2051,7 @@ static void test_qemu_strtosz_simple(void) res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0x20000000000000); + g_assert_cmphex(res, ==, 0x20000000000000ULL); g_assert_true(endptr == str + 16); str = "9007199254740993"; /* 2^53+1 */ @@ -2059,7 +2059,7 @@ static void test_qemu_strtosz_simple(void) res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0x20000000000001); + g_assert_cmphex(res, ==, 0x20000000000001ULL); g_assert_true(endptr == str + 16); str = "18446744073709549568"; /* 0xfffffffffffff800 (53 msbs set) */ @@ -2067,7 +2067,7 @@ static void test_qemu_strtosz_simple(void) res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0xfffffffffffff800); + g_assert_cmphex(res, ==, 0xfffffffffffff800ULL); g_assert_true(endptr == str + 20); str = "18446744073709550591"; /* 0xfffffffffffffbff */ @@ -2075,7 +2075,7 @@ static void test_qemu_strtosz_simple(void) res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0xfffffffffffffbff); + g_assert_cmphex(res, ==, 0xfffffffffffffbffULL); g_assert_true(endptr == str + 20); str = "18446744073709551615"; /* 0xffffffffffffffff */ @@ -2083,7 +2083,7 @@ static void test_qemu_strtosz_simple(void) res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0xffffffffffffffff); + g_assert_cmphex(res, ==, 0xffffffffffffffffULL); g_assert_true(endptr == str + 20); } @@ -2099,7 +2099,7 @@ static void test_qemu_strtosz_hex(void) res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0); + g_assert_cmpuint(res, ==, 0); g_assert_true(endptr == str + 3); str = "0xab"; @@ -2107,7 +2107,7 @@ static void test_qemu_strtosz_hex(void) res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 171); + g_assert_cmpuint(res, ==, 171); g_assert_true(endptr == str + 4); str = "0xae"; @@ -2115,7 +2115,7 @@ static void test_qemu_strtosz_hex(void) res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 174); + g_assert_cmpuint(res, ==, 174); g_assert_true(endptr == str + 4); } @@ -2138,56 +2138,56 @@ static void test_qemu_strtosz_units(void) res = 0xbaadf00d; err = qemu_strtosz_MiB(none, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, MiB); + g_assert_cmpuint(res, ==, MiB); g_assert_true(endptr == none + 1); endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(b, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 1); + g_assert_cmpuint(res, ==, 1); g_assert_true(endptr == b + 2); endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(k, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, KiB); + g_assert_cmpuint(res, ==, KiB); g_assert_true(endptr == k + 2); endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(m, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, MiB); + g_assert_cmpuint(res, ==, MiB); g_assert_true(endptr == m + 2); endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(g, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, GiB); + g_assert_cmpuint(res, ==, GiB); g_assert_true(endptr == g + 2); endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(t, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, TiB); + g_assert_cmpuint(res, ==, TiB); g_assert_true(endptr == t + 2); endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(p, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, PiB); + g_assert_cmpuint(res, ==, PiB); g_assert_true(endptr == p + 2); endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(e, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, EiB); + g_assert_cmpuint(res, ==, EiB); g_assert_true(endptr == e + 2); } @@ -2203,7 +2203,7 @@ static void test_qemu_strtosz_float(void) res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, EiB / 2); + g_assert_cmpuint(res, ==, EiB / 2); g_assert_true(endptr == str + 4); /* For convenience, a fraction of 0 is tolerated even on bytes */ @@ -2212,7 +2212,7 @@ static void test_qemu_strtosz_float(void) res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 1); + g_assert_cmpuint(res, ==, 1); g_assert_true(endptr == str + 4); /* An empty fraction is tolerated */ @@ -2221,7 +2221,7 @@ static void test_qemu_strtosz_float(void) res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 1024); + g_assert_cmpuint(res, ==, 1024); g_assert_true(endptr == str + 3); /* For convenience, we permit values that are not byte-exact */ @@ -2230,7 +2230,7 @@ static void test_qemu_strtosz_float(void) res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, (uint64_t) (12.345 * MiB + 0.5)); + g_assert_cmpuint(res, ==, (uint64_t) (12.345 * MiB + 0.5)); g_assert_true(endptr == str + 7); } @@ -2245,35 +2245,35 @@ static void test_qemu_strtosz_invalid(void) endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); g_assert_true(endptr == str); str = " \t "; endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); g_assert_true(endptr == str); str = "crap"; endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); g_assert_true(endptr == str); str = "inf"; endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); g_assert_true(endptr == str); str = "NaN"; endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); g_assert_true(endptr == str); /* Fractional values require scale larger than bytes */ @@ -2281,14 +2281,14 @@ static void test_qemu_strtosz_invalid(void) endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); g_assert_true(endptr == str); str = "1.1"; endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); g_assert_true(endptr == str); /* No floating point exponents */ @@ -2296,14 +2296,14 @@ static void test_qemu_strtosz_invalid(void) endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); g_assert_true(endptr == str); str = "1.5E+0k"; endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); g_assert_true(endptr == str); /* No hex fractions */ @@ -2311,7 +2311,7 @@ static void test_qemu_strtosz_invalid(void) endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); g_assert_true(endptr == str); /* No suffixes */ @@ -2319,7 +2319,7 @@ static void test_qemu_strtosz_invalid(void) endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); g_assert_true(endptr == str); /* No negative values */ @@ -2327,14 +2327,14 @@ static void test_qemu_strtosz_invalid(void) endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); g_assert_true(endptr == str); str = "-1"; endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); g_assert_true(endptr == str); } @@ -2350,65 +2350,65 @@ static void test_qemu_strtosz_trailing(void) res = 0xbaadf00d; err = qemu_strtosz_MiB(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 123 * MiB); + g_assert_cmpuint(res, ==, 123 * MiB); g_assert_true(endptr == str + 3); res = 0xbaadf00d; err = qemu_strtosz(str, NULL, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); str = "1kiB"; endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 1024); + g_assert_cmpuint(res, ==, 1024); g_assert_true(endptr == str + 2); res = 0xbaadf00d; err = qemu_strtosz(str, NULL, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); str = "0x"; endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0); + g_assert_cmpuint(res, ==, 0); g_assert_true(endptr == str + 1); res = 0xbaadf00d; err = qemu_strtosz(str, NULL, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); str = "0.NaN"; endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0); + g_assert_cmpuint(res, ==, 0); g_assert_true(endptr == str + 2); res = 0xbaadf00d; err = qemu_strtosz(str, NULL, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); str = "123-45"; endptr = NULL; res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 123); + g_assert_cmpuint(res, ==, 123); g_assert_true(endptr == str + 3); res = 0xbaadf00d; err = qemu_strtosz(str, NULL, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); } static void test_qemu_strtosz_erange(void) @@ -2422,14 +2422,14 @@ static void test_qemu_strtosz_erange(void) endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); g_assert_true(endptr == str + 20); str = "20E"; endptr = NULL; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert_cmphex(res, ==, 0xbaadf00d); g_assert_true(endptr == str + 3); } @@ -2445,7 +2445,7 @@ static void test_qemu_strtosz_metric(void) res = 0xbaadf00d; err = qemu_strtosz_metric(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 12345000); + g_assert_cmpuint(res, ==, 12345000); g_assert_true(endptr == str + 6); str = "12.345M"; @@ -2453,7 +2453,7 @@ static void test_qemu_strtosz_metric(void) res = 0xbaadf00d; err = qemu_strtosz_metric(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 12345000); + g_assert_cmpuint(res, ==, 12345000); g_assert_true(endptr == str + 7); } From patchwork Fri May 12 02:10:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238649 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C9422C77B7C for ; Fri, 12 May 2023 02:13:14 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFI-0004i3-SQ; Thu, 11 May 2023 22:11:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFG-0004ht-TD for qemu-devel@nongnu.org; Thu, 11 May 2023 22:10:58 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIF0-0000NN-H5 for qemu-devel@nongnu.org; Thu, 11 May 2023 22:10:58 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857440; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nhsLlMaxknRGiYfn6lVrP9agyv+1xGnzMMqI/FvOVw4=; b=Pzu7Fbzk6pjRFcMAOBWC1EcBclCutzeGsR1HGdhcyUm+D4VLDUZ/ABYU5MuCJzHqovvkaW 0QsW0cHOIXWdi6/9HNs/VG4dSKvHvMVpOJe1la1A31X8zCQ5TMxle203jwkdrrHERvuMkA BMy86AxH8nAaFRRDfieCG3nKMVdi900= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-640-B5XmMHHoOuy759fUNLB6dA-1; Thu, 11 May 2023 22:10:38 -0400 X-MC-Unique: B5XmMHHoOuy759fUNLB6dA-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 675B03C10246; Fri, 12 May 2023 02:10:38 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id 04E932026D16; Fri, 12 May 2023 02:10:37 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 03/19] test-cutils: Test integral qemu_strto* value on failures Date: Thu, 11 May 2023 21:10:17 -0500 Message-Id: <20230512021033.1378730-4-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org We are inconsistent on the contents of *value after a strto* parse failure. I found the following behaviors: - parse_uint() and parse_uint_full(), which document that *value is slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE failures, and has unit tests for that (note that parse_uint requires non-NULL endptr, and does not fail with EINVAL for trailing junk) - qemu_strtosz(), which leaves *value untouched on all failures (both EINVAL and ERANGE), and has unit tests but not documentation for that - qemu_strtoi() and other integral friends, which document *value on ERANGE failures but is unspecified on EINVAL (other than implicitly by comparison to libc strto*); there, *value is untouched for NULL string, slammed to 0 on no conversion, and left at the prefix value on NULL endptr; unit tests do not consistently check the value - qemu_strtod(), which documents *value on ERANGE failures but is unspecified on EINVAL; there, *value is untouched for NULL string, slammed to 0.0 for no conversion, and left at the prefix value on NULL endptr; there are no unit tests (other than indirectly through qemu_strtosz) - qemu_strtod_finite(), which documents *value on ERANGE failures but is unspecified on EINVAL; there, *value is left at the prefix for 'inf' or 'nan' and untouched in all other cases; there are no unit tests (other than indirectly through qemu_strtosz) Upcoming patches will change behaviors for consistency, but it's best to first have more unit test coverage to see the impact of those changes. Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek --- tests/unit/test-cutils.c | 58 +++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 38bd3990207..1eeaf21ae22 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -248,6 +248,7 @@ static void test_qemu_strtoi_null(void) err = qemu_strtoi(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 999); g_assert_null(endptr); } @@ -262,6 +263,7 @@ static void test_qemu_strtoi_empty(void) err = qemu_strtoi(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 0); g_assert_true(endptr == str); } @@ -276,6 +278,7 @@ static void test_qemu_strtoi_whitespace(void) err = qemu_strtoi(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 0); g_assert_true(endptr == str); } @@ -290,6 +293,7 @@ static void test_qemu_strtoi_invalid(void) err = qemu_strtoi(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 0); g_assert_true(endptr == str); } @@ -473,6 +477,7 @@ static void test_qemu_strtoi_full_null(void) err = qemu_strtoi(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 999); g_assert_null(endptr); } @@ -485,6 +490,7 @@ static void test_qemu_strtoi_full_empty(void) err = qemu_strtoi(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 0); } static void test_qemu_strtoi_full_negative(void) @@ -502,18 +508,19 @@ static void test_qemu_strtoi_full_negative(void) static void test_qemu_strtoi_full_trailing(void) { const char *str = "123xxx"; - int res; + int res = 999; int err; err = qemu_strtoi(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 123); } static void test_qemu_strtoi_full_max(void) { char *str = g_strdup_printf("%d", INT_MAX); - int res; + int res = 999; int err; err = qemu_strtoi(str, NULL, 0, &res); @@ -548,6 +555,7 @@ static void test_qemu_strtoui_null(void) err = qemu_strtoui(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 999); g_assert_null(endptr); } @@ -562,6 +570,7 @@ static void test_qemu_strtoui_empty(void) err = qemu_strtoui(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 0); g_assert_true(endptr == str); } @@ -576,6 +585,7 @@ static void test_qemu_strtoui_whitespace(void) err = qemu_strtoui(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 0); g_assert_true(endptr == str); } @@ -590,6 +600,7 @@ static void test_qemu_strtoui_invalid(void) err = qemu_strtoui(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 0); g_assert_true(endptr == str); } @@ -771,6 +782,7 @@ static void test_qemu_strtoui_full_null(void) err = qemu_strtoui(NULL, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 999); } static void test_qemu_strtoui_full_empty(void) @@ -782,7 +794,9 @@ static void test_qemu_strtoui_full_empty(void) err = qemu_strtoui(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 0); } + static void test_qemu_strtoui_full_negative(void) { const char *str = " \t -321"; @@ -797,12 +811,13 @@ static void test_qemu_strtoui_full_negative(void) static void test_qemu_strtoui_full_trailing(void) { const char *str = "123xxx"; - unsigned int res; + unsigned int res = 999; int err; err = qemu_strtoui(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 123); } static void test_qemu_strtoui_full_max(void) @@ -843,6 +858,7 @@ static void test_qemu_strtol_null(void) err = qemu_strtol(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 999); g_assert_null(endptr); } @@ -857,6 +873,7 @@ static void test_qemu_strtol_empty(void) err = qemu_strtol(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 0); g_assert_true(endptr == str); } @@ -871,6 +888,7 @@ static void test_qemu_strtol_whitespace(void) err = qemu_strtol(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 0); g_assert_true(endptr == str); } @@ -885,6 +903,7 @@ static void test_qemu_strtol_invalid(void) err = qemu_strtol(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 0); g_assert_true(endptr == str); } @@ -1066,6 +1085,7 @@ static void test_qemu_strtol_full_null(void) err = qemu_strtol(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 999); g_assert_null(endptr); } @@ -1078,6 +1098,7 @@ static void test_qemu_strtol_full_empty(void) err = qemu_strtol(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 0); } static void test_qemu_strtol_full_negative(void) @@ -1095,18 +1116,19 @@ static void test_qemu_strtol_full_negative(void) static void test_qemu_strtol_full_trailing(void) { const char *str = "123xxx"; - long res; + long res = 999; int err; err = qemu_strtol(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 123); } static void test_qemu_strtol_full_max(void) { char *str = g_strdup_printf("%ld", LONG_MAX); - long res; + long res = 999; int err; err = qemu_strtol(str, NULL, 0, &res); @@ -1141,6 +1163,7 @@ static void test_qemu_strtoul_null(void) err = qemu_strtoul(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 999); g_assert_null(endptr); } @@ -1155,6 +1178,7 @@ static void test_qemu_strtoul_empty(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 0); g_assert_true(endptr == str); } @@ -1169,6 +1193,7 @@ static void test_qemu_strtoul_whitespace(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 0); g_assert_true(endptr == str); } @@ -1183,6 +1208,7 @@ static void test_qemu_strtoul_invalid(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 0); g_assert_true(endptr == str); } @@ -1362,6 +1388,7 @@ static void test_qemu_strtoul_full_null(void) err = qemu_strtoul(NULL, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 999); } static void test_qemu_strtoul_full_empty(void) @@ -1373,7 +1400,9 @@ static void test_qemu_strtoul_full_empty(void) err = qemu_strtoul(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 0); } + static void test_qemu_strtoul_full_negative(void) { const char *str = " \t -321"; @@ -1388,12 +1417,13 @@ static void test_qemu_strtoul_full_negative(void) static void test_qemu_strtoul_full_trailing(void) { const char *str = "123xxx"; - unsigned long res; + unsigned long res = 999; int err; err = qemu_strtoul(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 123); } static void test_qemu_strtoul_full_max(void) @@ -1434,6 +1464,7 @@ static void test_qemu_strtoi64_null(void) err = qemu_strtoi64(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 999); g_assert_null(endptr); } @@ -1448,6 +1479,7 @@ static void test_qemu_strtoi64_empty(void) err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 0); g_assert_true(endptr == str); } @@ -1462,6 +1494,7 @@ static void test_qemu_strtoi64_whitespace(void) err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 0); g_assert_true(endptr == str); } @@ -1476,6 +1509,7 @@ static void test_qemu_strtoi64_invalid(void) err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 0); g_assert_true(endptr == str); } @@ -1655,6 +1689,7 @@ static void test_qemu_strtoi64_full_null(void) err = qemu_strtoi64(NULL, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 999); } static void test_qemu_strtoi64_full_empty(void) @@ -1666,6 +1701,7 @@ static void test_qemu_strtoi64_full_empty(void) err = qemu_strtoi64(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 0); } static void test_qemu_strtoi64_full_negative(void) @@ -1689,13 +1725,14 @@ static void test_qemu_strtoi64_full_trailing(void) err = qemu_strtoi64(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 123); } static void test_qemu_strtoi64_full_max(void) { char *str = g_strdup_printf("%lld", LLONG_MAX); - int64_t res; + int64_t res = 999; int err; err = qemu_strtoi64(str, NULL, 0, &res); @@ -1730,6 +1767,7 @@ static void test_qemu_strtou64_null(void) err = qemu_strtou64(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 999); g_assert_null(endptr); } @@ -1744,6 +1782,7 @@ static void test_qemu_strtou64_empty(void) err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 0); g_assert_true(endptr == str); } @@ -1758,6 +1797,7 @@ static void test_qemu_strtou64_whitespace(void) err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 0); g_assert_true(endptr == str); } @@ -1772,6 +1812,7 @@ static void test_qemu_strtou64_invalid(void) err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 0); g_assert_true(endptr == str); } @@ -1951,6 +1992,7 @@ static void test_qemu_strtou64_full_null(void) err = qemu_strtou64(NULL, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 999); } static void test_qemu_strtou64_full_empty(void) @@ -1962,6 +2004,7 @@ static void test_qemu_strtou64_full_empty(void) err = qemu_strtou64(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 0); } static void test_qemu_strtou64_full_negative(void) @@ -1985,6 +2028,7 @@ static void test_qemu_strtou64_full_trailing(void) err = qemu_strtou64(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpuint(res, ==, 18446744073709551614ULL); } static void test_qemu_strtou64_full_max(void) From patchwork Fri May 12 02:10:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238639 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D0554C7EE22 for ; Fri, 12 May 2023 02:12:26 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFL-0004j8-NY; Thu, 11 May 2023 22:11:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFK-0004iR-8i for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:02 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIF3-0000Oz-LF for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857443; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=G7JOgw1GzLEI/LRmKtQDebo61nRuJzYIt9xvMaci4zY=; b=MOXf+BlVnfJn+Sh/lI90tsJjoYxqogI419v8UdtxotdNqH2ewrVEWncyLVU7KXTWfePCPR K/lSFQd0qSMoubBEIgLaqJX80zQStDJ1+oIh3w0APgznuFtWGdAFqhRFHJxoxlFE3n3RqI qKiZfnV5MO7/EfJTYdXsP/bMABs3bgs= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-588-892EhZBXOvKFVhJ-fP437w-1; Thu, 11 May 2023 22:10:39 -0400 X-MC-Unique: 892EhZBXOvKFVhJ-fP437w-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 1654D871CA0; Fri, 12 May 2023 02:10:39 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id 97FC42026D16; Fri, 12 May 2023 02:10:38 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 04/19] test-cutils: Test more integer corner cases Date: Thu, 11 May 2023 21:10:18 -0500 Message-Id: <20230512021033.1378730-5-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org We have quite a few undertested and underdocumented integer parsing corner cases. To ensure that any changes we make in the code are intentional rather than accidental semantic changes, it is time to add more unit tests of existing behavior. In particular, this demonstrates that parse_uint() and qemu_strtou64() behave differently. For "-0", it's hard to argue why parse_uint needs to reject it (it's not a negative integer), but the documentation sort of mentions it; but it is intentional that all other negative values are treated as ERANGE with value 0 (compared to qemu_strtou64() treating "-2" as success and UINT64_MAX-1, for example). Also, when mixing overflow/underflow with a check for no trailing junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]* favor EINVAL. This behavior is outside the C standard, so we can pick whatever we want, but it would be nice to be consistent. Note that C requires that "9223372036854775808" fail strtoll() with ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we weren't testing this. For strtol(), the behavior depends on whether long is 32- or 64-bits (the cutoff point either being the same as strtoll() or at "-2147483648"). Meanwhile, C is clear that "-18446744073709551615" pass stroull() (but not strtoll) with value 1, even though we want it to fail parse_uint(). And although qemu_strtoui() has no C counterpart, it makes more sense if we design it like 32-bit strtoul() (that is, where "-4294967296" be an alternate acceptable spelling for "1". We aren't there yet, so some of the tests added in this patch have FIXME comments. Signed-off-by: Eric Blake --- tests/unit/test-cutils.c | 799 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 738 insertions(+), 61 deletions(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 1eeaf21ae22..89c10f5307a 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -150,7 +150,6 @@ static void test_parse_uint_decimal(void) g_assert_true(endptr == str + strlen(str)); } - static void test_parse_uint_llong_max(void) { unsigned long long i = 999; @@ -168,16 +167,51 @@ static void test_parse_uint_llong_max(void) g_free(str); } +static void test_parse_uint_max(void) +{ + unsigned long long i = 999; + char f = 'X'; + char *endptr = &f; + char *str = g_strdup_printf("%llu", ULLONG_MAX); + int r; + + r = parse_uint(str, &i, &endptr, 0); + + g_assert_cmpint(r, ==, 0); + g_assert_cmpuint(i, ==, ULLONG_MAX); + g_assert_true(endptr == str + strlen(str)); + + g_free(str); +} + static void test_parse_uint_overflow(void) { - unsigned long long i = 999; + unsigned long long i; char f = 'X'; - char *endptr = &f; - const char *str = "99999999999999999999999999999999999999"; + char *endptr; + const char *str; int r; + i = 999; + endptr = &f; + str = "99999999999999999999999999999999999999"; r = parse_uint(str, &i, &endptr, 0); + g_assert_cmpint(r, ==, -ERANGE); + g_assert_cmpuint(i, ==, ULLONG_MAX); + g_assert_true(endptr == str + strlen(str)); + i = 999; + endptr = &f; + str = "0x10000000000000000"; /* 65 bits, 64-bit sign bit clear */ + r = parse_uint(str, &i, &endptr, 0); + g_assert_cmpint(r, ==, -ERANGE); + g_assert_cmpuint(i, ==, ULLONG_MAX); + g_assert_true(endptr == str + strlen(str)); + + i = 999; + endptr = &f; + str = "0x18000000080000000"; /* 65 bits, 64-bit sign bit set */ + r = parse_uint(str, &i, &endptr, 0); g_assert_cmpint(r, ==, -ERANGE); g_assert_cmpuint(i, ==, ULLONG_MAX); g_assert_true(endptr == str + strlen(str)); @@ -198,6 +232,20 @@ static void test_parse_uint_negative(void) g_assert_true(endptr == str + strlen(str)); } +static void test_parse_uint_negzero(void) +{ + unsigned long long i = 999; + char f = 'X'; + char *endptr = &f; + const char *str = " -0"; + int r; + + r = parse_uint(str, &i, &endptr, 0); + + g_assert_cmpint(r, ==, -ERANGE); + g_assert_cmpuint(i, ==, 0); + g_assert_true(endptr == str + strlen(str)); +} static void test_parse_uint_full_trailing(void) { @@ -223,6 +271,19 @@ static void test_parse_uint_full_correct(void) g_assert_cmpuint(i, ==, 123); } +static void test_parse_uint_full_erange_junk(void) +{ + /* FIXME - inconsistent with qemu_strto* which favors EINVAL */ + unsigned long long i = 999; + const char *str = "-2junk"; + int r; + + r = parse_uint_full(str, &i, 0); + + g_assert_cmpint(r, ==, -ERANGE /* FIXME -EINVAL */); + g_assert_cmpuint(i, ==, 0); +} + static void test_qemu_strtoi_correct(void) { const char *str = "12345 foo"; @@ -410,7 +471,39 @@ static void test_qemu_strtoi_max(void) static void test_qemu_strtoi_overflow(void) { - char *str = g_strdup_printf("%lld", (long long)INT_MAX + 1ll); + const char *str; + const char *endptr; + int res; + int err; + + str = "2147483648"; /* INT_MAX + 1ll */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoi(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, INT_MAX); + g_assert_true(endptr == str + strlen(str)); + + str = "0x10000000000000000"; /* 65 bits, 32-bit sign bit clear */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoi(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, INT_MAX); + g_assert_true(endptr == str + strlen(str)); + + str = "0x18000000080000000"; /* 65 bits, 32-bit sign bit set */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoi(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, INT_MAX); + g_assert_true(endptr == str + strlen(str)); +} + +static void test_qemu_strtoi_min(void) +{ + char *str = g_strdup_printf("%d", INT_MIN); char f = 'X'; const char *endptr = &f; int res = 999; @@ -418,26 +511,50 @@ static void test_qemu_strtoi_overflow(void) err = qemu_strtoi(str, &endptr, 0, &res); - g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmpint(res, ==, INT_MAX); + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, INT_MIN); g_assert_true(endptr == str + strlen(str)); g_free(str); } static void test_qemu_strtoi_underflow(void) { - char *str = g_strdup_printf("%lld", (long long)INT_MIN - 1ll); - char f = 'X'; - const char *endptr = &f; - int res = 999; + const char *str; + const char *endptr; + int res; int err; + str = "-2147483649"; /* INT_MIN - 1ll */ + endptr = "somewhere"; + res = 999; err = qemu_strtoi(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, INT_MIN); + g_assert_true(endptr == str + strlen(str)); + + str = "-18446744073709551615"; /* -UINT64_MAX (not 1) */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoi(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, INT_MIN); + g_assert_true(endptr == str + strlen(str)); + str = "-0x10000000000000000"; /* 65 bits, 32-bit sign bit clear */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoi(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, INT_MIN); + g_assert_true(endptr == str + strlen(str)); + + str = "-0x18000000080000000"; /* 65 bits, 32-bit sign bit set */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoi(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpint(res, ==, INT_MIN); g_assert_true(endptr == str + strlen(str)); - g_free(str); } static void test_qemu_strtoi_negative(void) @@ -455,6 +572,21 @@ static void test_qemu_strtoi_negative(void) g_assert_true(endptr == str + strlen(str)); } +static void test_qemu_strtoi_negzero(void) +{ + const char *str = " -0"; + char f = 'X'; + const char *endptr = &f; + int res = 999; + int err; + + err = qemu_strtoi(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); + g_assert_true(endptr == str + strlen(str)); +} + static void test_qemu_strtoi_full_correct(void) { const char *str = "123"; @@ -505,6 +637,18 @@ static void test_qemu_strtoi_full_negative(void) g_assert_cmpint(res, ==, -321); } +static void test_qemu_strtoi_full_negzero(void) +{ + const char *str = " -0"; + int res = 999; + int err; + + err = qemu_strtoi(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); +} + static void test_qemu_strtoi_full_trailing(void) { const char *str = "123xxx"; @@ -530,6 +674,19 @@ static void test_qemu_strtoi_full_max(void) g_free(str); } +static void test_qemu_strtoi_full_erange_junk(void) +{ + /* EINVAL has priority over ERANGE */ + const char *str = "-9999999999junk"; + int res = 999; + int err; + + err = qemu_strtoi(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, INT_MIN); +} + static void test_qemu_strtoui_correct(void) { const char *str = "12345 foo"; @@ -699,6 +856,22 @@ static void test_qemu_strtoui_hex(void) g_assert_true(endptr == str + 1); } +static void test_qemu_strtoui_wrap(void) +{ + /* FIXME - wraparound should be consistent with 32-bit strtoul */ + const char *str = "-4294967295"; /* 1 mod 2^32 */ + char f = 'X'; + const char *endptr = &f; + unsigned int res = 999; + int err; + + err = qemu_strtoui(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE /* FIXME 0 */); + g_assert_cmphex(res, ==, UINT_MAX /* FIXME 1 */); + g_assert_true(endptr == str + strlen(str)); +} + static void test_qemu_strtoui_max(void) { char *str = g_strdup_printf("%u", UINT_MAX); @@ -717,34 +890,75 @@ static void test_qemu_strtoui_max(void) static void test_qemu_strtoui_overflow(void) { - char *str = g_strdup_printf("%lld", (long long)UINT_MAX + 1ll); - char f = 'X'; - const char *endptr = &f; - unsigned int res = 999; + const char *str; + const char *endptr; + unsigned int res; int err; + str = "4294967296"; /* UINT_MAX + 1ll */ + endptr = "somewhere"; + res = 999; err = qemu_strtoui(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, UINT_MAX); + g_assert_true(endptr == str + strlen(str)); + str = "0x10000000000000000"; /* 65 bits, 32-bit sign bit clear */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoui(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, UINT_MAX); + g_assert_true(endptr == str + strlen(str)); + + str = "0x18000000080000000"; /* 65 bits, 32-bit sign bit set */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoui(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmphex(res, ==, UINT_MAX); + g_assert_cmpint(res, ==, UINT_MAX); g_assert_true(endptr == str + strlen(str)); - g_free(str); } static void test_qemu_strtoui_underflow(void) { - char *str = g_strdup_printf("%lld", (long long)INT_MIN - 1ll); - char f = 'X'; - const char *endptr = &f; - unsigned int res = 999; + const char *str; + const char *endptr; + unsigned int res; int err; + str = "-4294967296"; /* -(long long)UINT_MAX - 1ll */ + endptr = "somewhere"; + res = 999; err = qemu_strtoui(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, UINT_MAX); + g_assert_true(endptr == str + strlen(str)); + + /* FIXME - overflow should be consistent with 32-bit strtoul */ + str = "-18446744073709551615"; /* -UINT64_MAX (not 1) */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoui(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, 0 /* FIXME -ERANGE */); + g_assert_cmpint(res, ==, 1 /* FIXME UINT_MAX */); + g_assert_true(endptr == str + strlen(str)); + str = "-0x10000000000000000"; /* 65 bits, 32-bit sign bit clear */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoui(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, UINT_MAX); + g_assert_true(endptr == str + strlen(str)); + + str = "-0x18000000080000000"; /* 65 bits, 32-bit sign bit set */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoui(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmpuint(res, ==, (unsigned int)-1); + g_assert_cmpint(res, ==, UINT_MAX); g_assert_true(endptr == str + strlen(str)); - g_free(str); } static void test_qemu_strtoui_negative(void) @@ -762,6 +976,21 @@ static void test_qemu_strtoui_negative(void) g_assert_true(endptr == str + strlen(str)); } +static void test_qemu_strtoui_negzero(void) +{ + const char *str = " -0"; + char f = 'X'; + const char *endptr = &f; + unsigned int res = 999; + int err; + + err = qemu_strtoui(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpuint(res, ==, 0); + g_assert_true(endptr == str + strlen(str)); +} + static void test_qemu_strtoui_full_correct(void) { const char *str = "123"; @@ -808,6 +1037,17 @@ static void test_qemu_strtoui_full_negative(void) g_assert_cmpuint(res, ==, (unsigned int)-321); } +static void test_qemu_strtoui_full_negzero(void) +{ + const char *str = " -0"; + unsigned int res = 999; + int err; + + err = qemu_strtoui(str, NULL, 0, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpuint(res, ==, 0); +} + static void test_qemu_strtoui_full_trailing(void) { const char *str = "123xxx"; @@ -833,6 +1073,19 @@ static void test_qemu_strtoui_full_max(void) g_free(str); } +static void test_qemu_strtoui_full_erange_junk(void) +{ + /* EINVAL has priority over ERANGE */ + const char *str = "-9999999999junk"; + unsigned int res = 999; + int err; + + err = qemu_strtoui(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, UINT_MAX); +} + static void test_qemu_strtol_correct(void) { const char *str = "12345 foo"; @@ -1020,7 +1273,40 @@ static void test_qemu_strtol_max(void) static void test_qemu_strtol_overflow(void) { - const char *str = "99999999999999999999999999999999999999999999"; + const char *str; + const char *endptr; + long res; + int err; + + /* 1 more than LONG_MAX */ + str = LONG_MAX == INT_MAX ? "2147483648" : "9223372036854775808"; + endptr = "somewhere"; + res = 999; + err = qemu_strtol(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, LONG_MAX); + g_assert_true(endptr == str + strlen(str)); + + str = "0x10000000000000000"; /* 65 bits, either sign bit position clear */ + endptr = "somewhere"; + res = 999; + err = qemu_strtol(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, LONG_MAX); + g_assert_true(endptr == str + strlen(str)); + + str = "0x18000000080000000"; /* 65 bits, either sign bit position set */ + endptr = "somewhere"; + res = 999; + err = qemu_strtol(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, LONG_MAX); + g_assert_true(endptr == str + strlen(str)); +} + +static void test_qemu_strtol_min(void) +{ + char *str = g_strdup_printf("%ld", LONG_MIN); char f = 'X'; const char *endptr = &f; long res = 999; @@ -1028,21 +1314,50 @@ static void test_qemu_strtol_overflow(void) err = qemu_strtol(str, &endptr, 0, &res); - g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmpint(res, ==, LONG_MAX); + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, LONG_MIN); g_assert_true(endptr == str + strlen(str)); + g_free(str); } static void test_qemu_strtol_underflow(void) { - const char *str = "-99999999999999999999999999999999999999999999"; - char f = 'X'; - const char *endptr = &f; - long res = 999; + const char *str; + const char *endptr; + long res; int err; + /* 1 less than LONG_MIN */ + str = LONG_MIN == INT_MIN ? "-2147483649" : "-9223372036854775809"; + endptr = "somewhere"; + res = 999; err = qemu_strtol(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, LONG_MIN); + g_assert_true(endptr == str + strlen(str)); + if (LONG_MAX == INT_MAX) { + str = "-18446744073709551615"; /* -UINT64_MAX (not 1) */ + endptr = "somewhere"; + res = 999; + err = qemu_strtol(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, LONG_MIN); + g_assert_true(endptr == str + strlen(str)); + } + + str = "-0x10000000000000000"; /* 65 bits, either sign bit position clear */ + endptr = "somewhere"; + res = 999; + err = qemu_strtol(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, LONG_MIN); + g_assert_true(endptr == str + strlen(str)); + + str = "-0x18000000080000000"; /* 65 bits, either sign bit position set */ + endptr = "somewhere"; + res = 999; + err = qemu_strtol(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpint(res, ==, LONG_MIN); g_assert_true(endptr == str + strlen(str)); @@ -1063,6 +1378,21 @@ static void test_qemu_strtol_negative(void) g_assert_true(endptr == str + strlen(str)); } +static void test_qemu_strtol_negzero(void) +{ + const char *str = " -0"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); + g_assert_true(endptr == str + strlen(str)); +} + static void test_qemu_strtol_full_correct(void) { const char *str = "123"; @@ -1113,6 +1443,18 @@ static void test_qemu_strtol_full_negative(void) g_assert_cmpint(res, ==, -321); } +static void test_qemu_strtol_full_negzero(void) +{ + const char *str = " -0"; + long res = 999; + int err; + + err = qemu_strtol(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); +} + static void test_qemu_strtol_full_trailing(void) { const char *str = "123xxx"; @@ -1138,6 +1480,19 @@ static void test_qemu_strtol_full_max(void) g_free(str); } +static void test_qemu_strtol_full_erange_junk(void) +{ + /* EINVAL has priority over ERANGE */ + const char *str = "-99999999999999999999junk"; + long res = 999; + int err; + + err = qemu_strtol(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, LONG_MIN); +} + static void test_qemu_strtoul_correct(void) { const char *str = "12345 foo"; @@ -1307,6 +1662,23 @@ static void test_qemu_strtoul_hex(void) g_assert_true(endptr == str + 1); } +static void test_qemu_strtoul_wrap(void) +{ + const char *str; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + /* 1 mod 2^(sizeof(long)*8) */ + str = LONG_MAX == INT_MAX ? "-4294967295" : "-18446744073709551615"; + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmphex(res, ==, 1); + g_assert_true(endptr == str + strlen(str)); +} + static void test_qemu_strtoul_max(void) { char *str = g_strdup_printf("%lu", ULONG_MAX); @@ -1325,31 +1697,67 @@ static void test_qemu_strtoul_max(void) static void test_qemu_strtoul_overflow(void) { - const char *str = "99999999999999999999999999999999999999999999"; - char f = 'X'; - const char *endptr = &f; - unsigned long res = 999; + const char *str; + const char *endptr; + unsigned long res; int err; + /* 1 more than ULONG_MAX */ + str = ULONG_MAX == UINT_MAX ? "4294967296" : "18446744073709551616"; + endptr = "somewhere"; + res = 999; err = qemu_strtoul(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, ULONG_MAX); + g_assert_true(endptr == str + strlen(str)); + str = "0x10000000000000000"; /* 65 bits, either sign bit position clear */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoul(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, ULONG_MAX); + g_assert_true(endptr == str + strlen(str)); + + str = "0x18000000080000000"; /* 65 bits, either sign bit position set */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmphex(res, ==, ULONG_MAX); + g_assert_cmpint(res, ==, ULONG_MAX); g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoul_underflow(void) { - const char *str = "-99999999999999999999999999999999999999999999"; - char f = 'X'; - const char *endptr = &f; - unsigned long res = 999; + const char *str; + const char *endptr; + unsigned long res; int err; + /* 1 less than -ULONG_MAX */ + str = ULONG_MAX == UINT_MAX ? "-4294967297" : "-18446744073709551617"; + endptr = "somewhere"; + res = 999; err = qemu_strtoul(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, ULONG_MAX); + g_assert_true(endptr == str + strlen(str)); + str = "-0x10000000000000000"; /* 65 bits, either sign bit position clear */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoul(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, ULONG_MAX); + g_assert_true(endptr == str + strlen(str)); + + str = "-0x18000000080000000"; /* 65 bits, either sign bit position set */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmpuint(res, ==, -1ul); + g_assert_cmpint(res, ==, ULONG_MAX); g_assert_true(endptr == str + strlen(str)); } @@ -1368,6 +1776,21 @@ static void test_qemu_strtoul_negative(void) g_assert_true(endptr == str + strlen(str)); } +static void test_qemu_strtoul_negzero(void) +{ + const char *str = " -0"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpuint(res, ==, 0); + g_assert_true(endptr == str + strlen(str)); +} + static void test_qemu_strtoul_full_correct(void) { const char *str = "123"; @@ -1414,6 +1837,17 @@ static void test_qemu_strtoul_full_negative(void) g_assert_cmpuint(res, ==, -321ul); } +static void test_qemu_strtoul_full_negzero(void) +{ + const char *str = " -0"; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, NULL, 0, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpuint(res, ==, 0); +} + static void test_qemu_strtoul_full_trailing(void) { const char *str = "123xxx"; @@ -1439,6 +1873,19 @@ static void test_qemu_strtoul_full_max(void) g_free(str); } +static void test_qemu_strtoul_full_erange_junk(void) +{ + /* EINVAL has priority over ERANGE */ + const char *str = "-99999999999999999999junk"; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, ULONG_MAX); +} + static void test_qemu_strtoi64_correct(void) { const char *str = "12345 foo"; @@ -1626,22 +2073,39 @@ static void test_qemu_strtoi64_max(void) static void test_qemu_strtoi64_overflow(void) { - const char *str = "99999999999999999999999999999999999999999999"; - char f = 'X'; - const char *endptr = &f; - int64_t res = 999; + const char *str; + const char *endptr; + int64_t res; int err; + str = "9223372036854775808"; /* 1 more than INT64_MAX */ + endptr = "somewhere"; + res = 999; err = qemu_strtoi64(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, INT64_MAX); + g_assert_true(endptr == str + strlen(str)); + str = "0x10000000000000000"; /* 65 bits, 64-bit sign bit clear */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoi64(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, INT64_MAX); + g_assert_true(endptr == str + strlen(str)); + + str = "0x18000000080000000"; /* 65 bits, 64-bit sign bit set */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmpint(res, ==, LLONG_MAX); + g_assert_cmpint(res, ==, INT64_MAX); g_assert_true(endptr == str + strlen(str)); } -static void test_qemu_strtoi64_underflow(void) +static void test_qemu_strtoi64_min(void) { - const char *str = "-99999999999999999999999999999999999999999999"; + char *str = g_strdup_printf("%lld", LLONG_MIN); char f = 'X'; const char *endptr = &f; int64_t res = 999; @@ -1649,9 +2113,42 @@ static void test_qemu_strtoi64_underflow(void) err = qemu_strtoi64(str, &endptr, 0, &res); - g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, LLONG_MIN); g_assert_true(endptr == str + strlen(str)); + g_free(str); +} + +static void test_qemu_strtoi64_underflow(void) +{ + const char *str; + const char *endptr; + int64_t res; + int err; + + str = "-9223372036854775809"; /* 1 less than INT64_MIN */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoi64(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, INT64_MIN); + g_assert_true(endptr == str + strlen(str)); + + str = "-0x10000000000000000"; /* 65 bits, 64-bit sign bit clear */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoi64(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, INT64_MIN); + g_assert_true(endptr == str + strlen(str)); + + str = "-0x18000000080000000"; /* 65 bits, 64-bit sign bit set */ + endptr = "somewhere"; + res = 999; + err = qemu_strtoi64(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, INT64_MIN); + g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtoi64_negative(void) @@ -1669,6 +2166,21 @@ static void test_qemu_strtoi64_negative(void) g_assert_true(endptr == str + strlen(str)); } +static void test_qemu_strtoi64_negzero(void) +{ + const char *str = " -0"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoi64(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); + g_assert_true(endptr == str + strlen(str)); +} + static void test_qemu_strtoi64_full_correct(void) { const char *str = "123"; @@ -1716,6 +2228,18 @@ static void test_qemu_strtoi64_full_negative(void) g_assert_cmpint(res, ==, -321); } +static void test_qemu_strtoi64_full_negzero(void) +{ + const char *str = " -0"; + int64_t res = 999; + int err; + + err = qemu_strtoi64(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); +} + static void test_qemu_strtoi64_full_trailing(void) { const char *str = "123xxx"; @@ -1742,6 +2266,19 @@ static void test_qemu_strtoi64_full_max(void) g_free(str); } +static void test_qemu_strtoi64_full_erange_junk(void) +{ + /* EINVAL has priority over ERANGE */ + const char *str = "-99999999999999999999junk"; + int64_t res = 999; + int err; + + err = qemu_strtoi64(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, INT64_MIN); +} + static void test_qemu_strtou64_correct(void) { const char *str = "12345 foo"; @@ -1911,6 +2448,21 @@ static void test_qemu_strtou64_hex(void) g_assert_true(endptr == str + 1); } +static void test_qemu_strtou64_wrap(void) +{ + const char *str = "-18446744073709551615"; /* 1 mod 2^64 */ + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtou64(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpuint(res, ==, 1); + g_assert_true(endptr == str + strlen(str)); +} + static void test_qemu_strtou64_max(void) { char *str = g_strdup_printf("%llu", ULLONG_MAX); @@ -1929,31 +2481,65 @@ static void test_qemu_strtou64_max(void) static void test_qemu_strtou64_overflow(void) { - const char *str = "99999999999999999999999999999999999999999999"; - char f = 'X'; - const char *endptr = &f; - uint64_t res = 999; + const char *str; + const char *endptr; + uint64_t res; int err; + str = "18446744073709551616"; /* 1 more than UINT64_MAX */ + endptr = "somewhere"; + res = 999; err = qemu_strtou64(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, UINT64_MAX); + g_assert_true(endptr == str + strlen(str)); + str = "0x10000000000000000"; /* 65 bits, 64-bit sign bit clear */ + endptr = "somewhere"; + res = 999; + err = qemu_strtou64(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, UINT64_MAX); + g_assert_true(endptr == str + strlen(str)); + + str = "0x18000000080000000"; /* 65 bits, 64-bit sign bit set */ + endptr = "somewhere"; + res = 999; + err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmphex(res, ==, ULLONG_MAX); + g_assert_cmpint(res, ==, UINT64_MAX); g_assert_true(endptr == str + strlen(str)); } static void test_qemu_strtou64_underflow(void) { - const char *str = "-99999999999999999999999999999999999999999999"; - char f = 'X'; - const char *endptr = &f; - uint64_t res = 999; + const char *str; + const char *endptr; + uint64_t res; int err; + str = "-99999999999999999999999999999999999999999999"; + endptr = "somewhere"; + res = 999; err = qemu_strtou64(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, UINT64_MAX); + g_assert_true(endptr == str + strlen(str)); + str = "-0x10000000000000000"; /* 65 bits, 64-bit sign bit clear */ + endptr = "somewhere"; + res = 999; + err = qemu_strtou64(str, &endptr, 0, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, UINT64_MAX); + g_assert_true(endptr == str + strlen(str)); + + str = "-0x18000000080000000"; /* 65 bits, 64-bit sign bit set */ + endptr = "somewhere"; + res = 999; + err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmphex(res, ==, -1ull); + g_assert_cmpint(res, ==, UINT64_MAX); g_assert_true(endptr == str + strlen(str)); } @@ -1972,6 +2558,21 @@ static void test_qemu_strtou64_negative(void) g_assert_true(endptr == str + strlen(str)); } +static void test_qemu_strtou64_negzero(void) +{ + const char *str = " -0"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtou64(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpuint(res, ==, 0); + g_assert_true(endptr == str + strlen(str)); +} + static void test_qemu_strtou64_full_correct(void) { const char *str = "18446744073709551614"; @@ -2019,6 +2620,18 @@ static void test_qemu_strtou64_full_negative(void) g_assert_cmpuint(res, ==, -321ull); } +static void test_qemu_strtou64_full_negzero(void) +{ + const char *str = " -0"; + uint64_t res = 999; + int err; + + err = qemu_strtou64(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpuint(res, ==, 0); +} + static void test_qemu_strtou64_full_trailing(void) { const char *str = "18446744073709551614xxxxxx"; @@ -2044,6 +2657,19 @@ static void test_qemu_strtou64_full_max(void) g_free(str); } +static void test_qemu_strtou64_full_erange_junk(void) +{ + /* EINVAL has priority over ERANGE */ + const char *str = "-99999999999999999999junk"; + uint64_t res = 999; + int err; + + err = qemu_strtou64(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, UINT64_MAX); +} + static void test_qemu_strtosz_simple(void) { const char *str; @@ -2585,12 +3211,16 @@ int main(int argc, char **argv) g_test_add_func("/cutils/parse_uint/octal", test_parse_uint_octal); g_test_add_func("/cutils/parse_uint/decimal", test_parse_uint_decimal); g_test_add_func("/cutils/parse_uint/llong_max", test_parse_uint_llong_max); + g_test_add_func("/cutils/parse_uint/max", test_parse_uint_max); g_test_add_func("/cutils/parse_uint/overflow", test_parse_uint_overflow); g_test_add_func("/cutils/parse_uint/negative", test_parse_uint_negative); + g_test_add_func("/cutils/parse_uint/negzero", test_parse_uint_negzero); g_test_add_func("/cutils/parse_uint_full/trailing", test_parse_uint_full_trailing); g_test_add_func("/cutils/parse_uint_full/correct", test_parse_uint_full_correct); + g_test_add_func("/cutils/parse_uint_full/erange_junk", + test_parse_uint_full_erange_junk); /* qemu_strtoi() tests */ g_test_add_func("/cutils/qemu_strtoi/correct", @@ -2615,10 +3245,14 @@ int main(int argc, char **argv) test_qemu_strtoi_max); g_test_add_func("/cutils/qemu_strtoi/overflow", test_qemu_strtoi_overflow); + g_test_add_func("/cutils/qemu_strtoi/min", + test_qemu_strtoi_min); g_test_add_func("/cutils/qemu_strtoi/underflow", test_qemu_strtoi_underflow); g_test_add_func("/cutils/qemu_strtoi/negative", test_qemu_strtoi_negative); + g_test_add_func("/cutils/qemu_strtoi/negzero", + test_qemu_strtoi_negzero); g_test_add_func("/cutils/qemu_strtoi_full/correct", test_qemu_strtoi_full_correct); g_test_add_func("/cutils/qemu_strtoi_full/null", @@ -2627,10 +3261,14 @@ int main(int argc, char **argv) test_qemu_strtoi_full_empty); g_test_add_func("/cutils/qemu_strtoi_full/negative", test_qemu_strtoi_full_negative); + g_test_add_func("/cutils/qemu_strtoi_full/negzero", + test_qemu_strtoi_full_negzero); g_test_add_func("/cutils/qemu_strtoi_full/trailing", test_qemu_strtoi_full_trailing); g_test_add_func("/cutils/qemu_strtoi_full/max", test_qemu_strtoi_full_max); + g_test_add_func("/cutils/qemu_strtoi_full/erange_junk", + test_qemu_strtoi_full_erange_junk); /* qemu_strtoui() tests */ g_test_add_func("/cutils/qemu_strtoui/correct", @@ -2651,6 +3289,8 @@ int main(int argc, char **argv) test_qemu_strtoui_decimal); g_test_add_func("/cutils/qemu_strtoui/hex", test_qemu_strtoui_hex); + g_test_add_func("/cutils/qemu_strtoui/wrap", + test_qemu_strtoui_wrap); g_test_add_func("/cutils/qemu_strtoui/max", test_qemu_strtoui_max); g_test_add_func("/cutils/qemu_strtoui/overflow", @@ -2659,6 +3299,8 @@ int main(int argc, char **argv) test_qemu_strtoui_underflow); g_test_add_func("/cutils/qemu_strtoui/negative", test_qemu_strtoui_negative); + g_test_add_func("/cutils/qemu_strtoui/negzero", + test_qemu_strtoui_negzero); g_test_add_func("/cutils/qemu_strtoui_full/correct", test_qemu_strtoui_full_correct); g_test_add_func("/cutils/qemu_strtoui_full/null", @@ -2667,10 +3309,14 @@ int main(int argc, char **argv) test_qemu_strtoui_full_empty); g_test_add_func("/cutils/qemu_strtoui_full/negative", test_qemu_strtoui_full_negative); + g_test_add_func("/cutils/qemu_strtoui_full/negzero", + test_qemu_strtoui_full_negzero); g_test_add_func("/cutils/qemu_strtoui_full/trailing", test_qemu_strtoui_full_trailing); g_test_add_func("/cutils/qemu_strtoui_full/max", test_qemu_strtoui_full_max); + g_test_add_func("/cutils/qemu_strtoui_full/erange_junk", + test_qemu_strtoui_full_erange_junk); /* qemu_strtol() tests */ g_test_add_func("/cutils/qemu_strtol/correct", @@ -2695,10 +3341,14 @@ int main(int argc, char **argv) test_qemu_strtol_max); g_test_add_func("/cutils/qemu_strtol/overflow", test_qemu_strtol_overflow); + g_test_add_func("/cutils/qemu_strtol/min", + test_qemu_strtol_min); g_test_add_func("/cutils/qemu_strtol/underflow", test_qemu_strtol_underflow); g_test_add_func("/cutils/qemu_strtol/negative", test_qemu_strtol_negative); + g_test_add_func("/cutils/qemu_strtol/negzero", + test_qemu_strtol_negzero); g_test_add_func("/cutils/qemu_strtol_full/correct", test_qemu_strtol_full_correct); g_test_add_func("/cutils/qemu_strtol_full/null", @@ -2707,10 +3357,14 @@ int main(int argc, char **argv) test_qemu_strtol_full_empty); g_test_add_func("/cutils/qemu_strtol_full/negative", test_qemu_strtol_full_negative); + g_test_add_func("/cutils/qemu_strtol_full/negzero", + test_qemu_strtol_full_negzero); g_test_add_func("/cutils/qemu_strtol_full/trailing", test_qemu_strtol_full_trailing); g_test_add_func("/cutils/qemu_strtol_full/max", test_qemu_strtol_full_max); + g_test_add_func("/cutils/qemu_strtol_full/erange_junk", + test_qemu_strtol_full_erange_junk); /* qemu_strtoul() tests */ g_test_add_func("/cutils/qemu_strtoul/correct", @@ -2731,6 +3385,8 @@ int main(int argc, char **argv) test_qemu_strtoul_decimal); g_test_add_func("/cutils/qemu_strtoul/hex", test_qemu_strtoul_hex); + g_test_add_func("/cutils/qemu_strtoul/wrap", + test_qemu_strtoul_wrap); g_test_add_func("/cutils/qemu_strtoul/max", test_qemu_strtoul_max); g_test_add_func("/cutils/qemu_strtoul/overflow", @@ -2739,6 +3395,8 @@ int main(int argc, char **argv) test_qemu_strtoul_underflow); g_test_add_func("/cutils/qemu_strtoul/negative", test_qemu_strtoul_negative); + g_test_add_func("/cutils/qemu_strtoul/negzero", + test_qemu_strtoul_negzero); g_test_add_func("/cutils/qemu_strtoul_full/correct", test_qemu_strtoul_full_correct); g_test_add_func("/cutils/qemu_strtoul_full/null", @@ -2747,10 +3405,14 @@ int main(int argc, char **argv) test_qemu_strtoul_full_empty); g_test_add_func("/cutils/qemu_strtoul_full/negative", test_qemu_strtoul_full_negative); + g_test_add_func("/cutils/qemu_strtoul_full/negzero", + test_qemu_strtoul_full_negzero); g_test_add_func("/cutils/qemu_strtoul_full/trailing", test_qemu_strtoul_full_trailing); g_test_add_func("/cutils/qemu_strtoul_full/max", test_qemu_strtoul_full_max); + g_test_add_func("/cutils/qemu_strtoul_full/erange_junk", + test_qemu_strtoul_full_erange_junk); /* qemu_strtoi64() tests */ g_test_add_func("/cutils/qemu_strtoi64/correct", @@ -2761,8 +3423,7 @@ int main(int argc, char **argv) test_qemu_strtoi64_empty); g_test_add_func("/cutils/qemu_strtoi64/whitespace", test_qemu_strtoi64_whitespace); - g_test_add_func("/cutils/qemu_strtoi64/invalid" - , + g_test_add_func("/cutils/qemu_strtoi64/invalid", test_qemu_strtoi64_invalid); g_test_add_func("/cutils/qemu_strtoi64/trailing", test_qemu_strtoi64_trailing); @@ -2776,10 +3437,14 @@ int main(int argc, char **argv) test_qemu_strtoi64_max); g_test_add_func("/cutils/qemu_strtoi64/overflow", test_qemu_strtoi64_overflow); + g_test_add_func("/cutils/qemu_strtoi64/min", + test_qemu_strtoi64_min); g_test_add_func("/cutils/qemu_strtoi64/underflow", test_qemu_strtoi64_underflow); g_test_add_func("/cutils/qemu_strtoi64/negative", test_qemu_strtoi64_negative); + g_test_add_func("/cutils/qemu_strtoi64/negzero", + test_qemu_strtoi64_negzero); g_test_add_func("/cutils/qemu_strtoi64_full/correct", test_qemu_strtoi64_full_correct); g_test_add_func("/cutils/qemu_strtoi64_full/null", @@ -2788,10 +3453,14 @@ int main(int argc, char **argv) test_qemu_strtoi64_full_empty); g_test_add_func("/cutils/qemu_strtoi64_full/negative", test_qemu_strtoi64_full_negative); + g_test_add_func("/cutils/qemu_strtoi64_full/negzero", + test_qemu_strtoi64_full_negzero); g_test_add_func("/cutils/qemu_strtoi64_full/trailing", test_qemu_strtoi64_full_trailing); g_test_add_func("/cutils/qemu_strtoi64_full/max", test_qemu_strtoi64_full_max); + g_test_add_func("/cutils/qemu_strtoi64_full/erange_junk", + test_qemu_strtoi64_full_erange_junk); /* qemu_strtou64() tests */ g_test_add_func("/cutils/qemu_strtou64/correct", @@ -2812,6 +3481,8 @@ int main(int argc, char **argv) test_qemu_strtou64_decimal); g_test_add_func("/cutils/qemu_strtou64/hex", test_qemu_strtou64_hex); + g_test_add_func("/cutils/qemu_strtou64/wrap", + test_qemu_strtou64_wrap); g_test_add_func("/cutils/qemu_strtou64/max", test_qemu_strtou64_max); g_test_add_func("/cutils/qemu_strtou64/overflow", @@ -2820,6 +3491,8 @@ int main(int argc, char **argv) test_qemu_strtou64_underflow); g_test_add_func("/cutils/qemu_strtou64/negative", test_qemu_strtou64_negative); + g_test_add_func("/cutils/qemu_strtou64/negzero", + test_qemu_strtou64_negzero); g_test_add_func("/cutils/qemu_strtou64_full/correct", test_qemu_strtou64_full_correct); g_test_add_func("/cutils/qemu_strtou64_full/null", @@ -2828,10 +3501,14 @@ int main(int argc, char **argv) test_qemu_strtou64_full_empty); g_test_add_func("/cutils/qemu_strtou64_full/negative", test_qemu_strtou64_full_negative); + g_test_add_func("/cutils/qemu_strtou64_full/negzero", + test_qemu_strtou64_full_negzero); g_test_add_func("/cutils/qemu_strtou64_full/trailing", test_qemu_strtou64_full_trailing); g_test_add_func("/cutils/qemu_strtou64_full/max", test_qemu_strtou64_full_max); + g_test_add_func("/cutils/qemu_strtou64_full/erange_junk", + test_qemu_strtou64_full_erange_junk); g_test_add_func("/cutils/strtosz/simple", test_qemu_strtosz_simple); From patchwork Fri May 12 02:10:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238642 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id CC4A5C7EE22 for ; Fri, 12 May 2023 02:12:49 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFM-0004ji-Pg; Thu, 11 May 2023 22:11:04 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFL-0004j4-HT for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:03 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIF6-0000PC-Pu for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:03 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857443; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fnvkrMuUpglPotfSIHcayGPS5JFevaH1n4AoJYzF5o8=; b=NJY8VuM5DrKoonaQb6Gz864V//zT0+L/0jrN+onYbUHd0QVdoUsQJ67WmBGA34vAWOOPfH IkJeVvFpfbCPagK0pct0D+dcaC7xQHYGykzwRr4QxPuqmkblBrDztM6zn+zUcfTshWXBwX 1l9UYzFbhbSF0kgl2tJAqtoQDSYPels= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-594-cqLJHI-GO_KVujywABGCIA-1; Thu, 11 May 2023 22:10:39 -0400 X-MC-Unique: cqLJHI-GO_KVujywABGCIA-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id A4604185A7A4; Fri, 12 May 2023 02:10:39 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id 419B02026D16; Fri, 12 May 2023 02:10:39 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 05/19] cutils: Fix wraparound parsing in qemu_strtoui Date: Thu, 11 May 2023 21:10:19 -0500 Message-Id: <20230512021033.1378730-6-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org While we were matching 32-bit strtol in qemu_strtoi, our use of a 64-bit parse was leaking through for some inaccurate answers in qemu_strtoui in comparison to a 32-bit strtoul. Fix those, and update the testsuite now that our bounds checks are correct. Our int wrappers would be a lot easier to write if libc had a guaranteed 32-bit parser even on platforms with 64-bit long. Fixes: 473a2a331e ("cutils: add qemu_strtoi & qemu_strtoui parsers for int/unsigned int types", v2.12.0) Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek --- tests/unit/test-cutils.c | 11 +++++------ util/cutils.c | 14 ++++++++++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 89c10f5307a..08989d1d3ac 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -858,7 +858,7 @@ static void test_qemu_strtoui_hex(void) static void test_qemu_strtoui_wrap(void) { - /* FIXME - wraparound should be consistent with 32-bit strtoul */ + /* wraparound is consistent with 32-bit strtoul */ const char *str = "-4294967295"; /* 1 mod 2^32 */ char f = 'X'; const char *endptr = &f; @@ -867,8 +867,8 @@ static void test_qemu_strtoui_wrap(void) err = qemu_strtoui(str, &endptr, 0, &res); - g_assert_cmpint(err, ==, -ERANGE /* FIXME 0 */); - g_assert_cmphex(res, ==, UINT_MAX /* FIXME 1 */); + g_assert_cmpint(err, ==, 0); + g_assert_cmphex(res, ==, 1); g_assert_true(endptr == str + strlen(str)); } @@ -935,13 +935,12 @@ static void test_qemu_strtoui_underflow(void) g_assert_cmpint(res, ==, UINT_MAX); g_assert_true(endptr == str + strlen(str)); - /* FIXME - overflow should be consistent with 32-bit strtoul */ str = "-18446744073709551615"; /* -UINT64_MAX (not 1) */ endptr = "somewhere"; res = 999; err = qemu_strtoui(str, &endptr, 0, &res); - g_assert_cmpint(err, ==, 0 /* FIXME -ERANGE */); - g_assert_cmpint(res, ==, 1 /* FIXME UINT_MAX */); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, UINT_MAX); g_assert_true(endptr == str + strlen(str)); str = "-0x10000000000000000"; /* 65 bits, 32-bit sign bit clear */ diff --git a/util/cutils.c b/util/cutils.c index 5887e744140..997ddcd09e5 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -466,10 +466,16 @@ int qemu_strtoui(const char *nptr, const char **endptr, int base, if (errno == ERANGE) { *result = -1; } else { - if (lresult > UINT_MAX) { - *result = UINT_MAX; - errno = ERANGE; - } else if (lresult < INT_MIN) { + /* + * Note that platforms with 32-bit strtoul accept input in the + * range [-4294967295, 4294967295]; but we used 64-bit + * strtoull which wraps -18446744073709551615 to 1. Reject + * positive values that contain '-', and wrap all valid + * negative values. + */ + if (lresult > UINT_MAX || + lresult < -(long long)UINT_MAX || + (lresult > 0 && memchr(nptr, '-', ep - nptr))) { *result = UINT_MAX; errno = ERANGE; } else { From patchwork Fri May 12 02:10:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238638 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5204AC77B7C for ; Fri, 12 May 2023 02:12:02 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFU-0004nk-BK; Thu, 11 May 2023 22:11:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFS-0004mg-HQ for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:10 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIF4-0000PJ-AI for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:10 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857444; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3ADMzvxVFAhrRzx7srC/lISUsKFPDMRDermJvO5d3Ps=; b=BDxoCsW4p8Zc7pxQnT6X05kmQypuae1IEgA/Zkte8H7KjTM2Fat3LiJv6JhitnjII1Pmvk W4JzrUherKBOEFA/JqZ86Fwq5FD3scnkFLHAPew3/iIFiqtdxHQaS56CFbiHm+jgVI07bf arLKSSADeHuekm3xmA5tmrJZigaK1dw= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-606-E91JYrQ5PWObxvuw6cAJ9A-1; Thu, 11 May 2023 22:10:40 -0400 X-MC-Unique: E91JYrQ5PWObxvuw6cAJ9A-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 3B71085A588; Fri, 12 May 2023 02:10:40 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id CD1BF2026D16; Fri, 12 May 2023 02:10:39 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 06/19] cutils: Document differences between parse_uint and qemu_strtou64 Date: Thu, 11 May 2023 21:10:20 -0500 Message-Id: <20230512021033.1378730-7-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -16 X-Spam_score: -1.7 X-Spam_bar: - X-Spam_report: (-1.7 / 5.0 requ) BAYES_00=-1.9, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org These two functions are subtly different, and not just because of swapped parameter order. It took me adding better unit tests to figure out why. Document the differences to make it more obvious to developers trying to pick which one to use, as well as to aid in upcoming semantic changes. While touching the documentation, adjust a mis-statement: parse_uint does not return -EINVAL on invalid base, but assert()s, like all the other qemu_strto* functions that take a base argument. Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek --- util/cutils.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/util/cutils.c b/util/cutils.c index 997ddcd09e5..4e3cc6e3605 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -604,6 +604,8 @@ int qemu_strtoi64(const char *nptr, const char **endptr, int base, * Convert string @nptr to an uint64_t. * * Works like qemu_strtoul(), except it stores UINT64_MAX on overflow. + * (If you want to prohibit negative numbers that wrap around to + * positive, use parse_uint()). */ int qemu_strtou64(const char *nptr, const char **endptr, int base, uint64_t *result) @@ -714,7 +716,8 @@ const char *qemu_strchrnul(const char *s, int c) * * @s: String to parse * @value: Destination for parsed integer value - * @endptr: Destination for pointer to first character not consumed + * @endptr: Destination for pointer to first character not consumed, must + * not be %NULL * @base: integer base, between 2 and 36 inclusive, or 0 * * Parse unsigned integer @@ -722,15 +725,16 @@ const char *qemu_strchrnul(const char *s, int c) * Parsed syntax is like strtoull()'s: arbitrary whitespace, a single optional * '+' or '-', an optional "0x" if @base is 0 or 16, one or more digits. * - * If @s is null, or @base is invalid, or @s doesn't start with an - * integer in the syntax above, set *@value to 0, *@endptr to @s, and - * return -EINVAL. + * If @s is null, or @s doesn't start with an integer in the syntax + * above, set *@value to 0, *@endptr to @s, and return -EINVAL. * * Set *@endptr to point right beyond the parsed integer (even if the integer * overflows or is negative, all digits will be parsed and *@endptr will * point right beyond them). * * If the integer is negative, set *@value to 0, and return -ERANGE. + * (If you want to allow negative numbers that wrap around within + * bounds, use qemu_strtou64()). * * If the integer overflows unsigned long long, set *@value to * ULLONG_MAX, and return -ERANGE. @@ -787,10 +791,10 @@ out: * * Parse unsigned integer from entire string * - * Have the same behavior of parse_uint(), but with an additional check - * for additional data after the parsed number. If extra characters are present - * after the parsed number, the function will return -EINVAL, and *@v will - * be set to 0. + * Have the same behavior of parse_uint(), but with an additional + * check for additional data after the parsed number. If extra + * characters are present after a non-overflowing parsed number, the + * function will return -EINVAL, and *@v will be set to 0. */ int parse_uint_full(const char *s, unsigned long long *value, int base) { From patchwork Fri May 12 02:10:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238647 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id CBDF1C7EE23 for ; Fri, 12 May 2023 02:13:09 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFO-0004kR-4V; Thu, 11 May 2023 22:11:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFM-0004jj-TM for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:04 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIF8-0000PZ-A2 for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:04 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857445; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fQR+FOZA32p1znugSx8zNND9uGtI1VPofyOEVhiNns4=; b=BM+zY5BFnYgu0wBv4W5yKQh58/J3QVUU9dm+S/a3x+HC5Fd5l1bU02lUpq2n5vThRdotSt Y2HnW7Qk5BjEcfvDbu889xVZUqpE9OZTxeY3cOgJPewaVq43WqBqxEkpUMtvJjYpTIQLPr N+08G7BRcPc0DJOidkrb/MeRAERJNIY= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-634-djdYE6PbN-CmLanYdlVm5w-1; Thu, 11 May 2023 22:10:42 -0400 X-MC-Unique: djdYE6PbN-CmLanYdlVm5w-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id A2F9C871CA3; Fri, 12 May 2023 02:10:41 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8ACDA2026D16; Fri, 12 May 2023 02:10:40 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org, Gerd Hoffmann , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , Kevin Wolf , Peter Lieven , Michael Roth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , qemu-block@nongnu.org (open list:GLUSTER), integration@gluster.org (open list:GLUSTER) Subject: [PATCH v2 07/19] cutils: Adjust signature of parse_uint[_full] Date: Thu, 11 May 2023 21:10:21 -0500 Message-Id: <20230512021033.1378730-8-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org It's already confusing that we have two very similar functions for wrapping the parse of a 64-bit unsigned value, differing mainly on whether they permit leading '-'. Adjust the signature of parse_uint() and parse_uint_full() to be like all of qemu_strto*(): put the result parameter last, use the same types (uint64_t is not always the same as unsigned long long, and mark endptr const (only latter affects the rare caller of parse_uint). Adjust all callers in the tree. Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek --- include/qemu/cutils.h | 5 +- audio/audio_legacy.c | 4 +- block/gluster.c | 4 +- block/nfs.c | 4 +- blockdev.c | 4 +- contrib/ivshmem-server/main.c | 4 +- qapi/opts-visitor.c | 10 +-- tests/unit/test-cutils.c | 113 +++++++++++++++------------------- ui/vnc.c | 4 +- util/cutils.c | 13 ++-- util/guest-random.c | 4 +- util/qemu-sockets.c | 10 +-- 12 files changed, 82 insertions(+), 97 deletions(-) diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h index 92c436d8c70..92c927a6a35 100644 --- a/include/qemu/cutils.h +++ b/include/qemu/cutils.h @@ -163,9 +163,8 @@ int qemu_strtou64(const char *nptr, const char **endptr, int base, int qemu_strtod(const char *nptr, const char **endptr, double *result); int qemu_strtod_finite(const char *nptr, const char **endptr, double *result); -int parse_uint(const char *s, unsigned long long *value, char **endptr, - int base); -int parse_uint_full(const char *s, unsigned long long *value, int base); +int parse_uint(const char *s, const char **endptr, int base, uint64_t *value); +int parse_uint_full(const char *s, int base, uint64_t *value); int qemu_strtosz(const char *nptr, const char **end, uint64_t *result); int qemu_strtosz_MiB(const char *nptr, const char **end, uint64_t *result); diff --git a/audio/audio_legacy.c b/audio/audio_legacy.c index b848001ff70..dc72ba55e9a 100644 --- a/audio/audio_legacy.c +++ b/audio/audio_legacy.c @@ -35,8 +35,8 @@ static uint32_t toui32(const char *str) { - unsigned long long ret; - if (parse_uint_full(str, &ret, 10) || ret > UINT32_MAX) { + uint64_t ret; + if (parse_uint_full(str, 10, &ret) || ret > UINT32_MAX) { dolog("Invalid integer value `%s'\n", str); exit(1); } diff --git a/block/gluster.c b/block/gluster.c index 185a83e5e53..ad5fadbe793 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -424,7 +424,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf, int ret; int old_errno; SocketAddressList *server; - unsigned long long port; + uint64_t port; glfs = glfs_find_preopened(gconf->volume); if (glfs) { @@ -445,7 +445,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf, server->value->u.q_unix.path, 0); break; case SOCKET_ADDRESS_TYPE_INET: - if (parse_uint_full(server->value->u.inet.port, &port, 10) < 0 || + if (parse_uint_full(server->value->u.inet.port, 10, &port) < 0 || port > 65535) { error_setg(errp, "'%s' is not a valid port number", server->value->u.inet.port); diff --git a/block/nfs.c b/block/nfs.c index 006045d71a6..fabea0386a3 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -114,13 +114,13 @@ static int nfs_parse_uri(const char *filename, QDict *options, Error **errp) qdict_put_str(options, "path", uri->path); for (i = 0; i < qp->n; i++) { - unsigned long long val; + uint64_t val; if (!qp->p[i].value) { error_setg(errp, "Value for NFS parameter expected: %s", qp->p[i].name); goto out; } - if (parse_uint_full(qp->p[i].value, &val, 0)) { + if (parse_uint_full(qp->p[i].value, 0, &val)) { error_setg(errp, "Illegal value for NFS parameter: %s", qp->p[i].name); goto out; diff --git a/blockdev.c b/blockdev.c index d141ca7a2d5..162eaffae16 100644 --- a/blockdev.c +++ b/blockdev.c @@ -341,10 +341,10 @@ static bool parse_stats_intervals(BlockAcctStats *stats, QList *intervals, switch (qobject_type(entry->value)) { case QTYPE_QSTRING: { - unsigned long long length; + uint64_t length; const char *str = qstring_get_str(qobject_to(QString, entry->value)); - if (parse_uint_full(str, &length, 10) == 0 && + if (parse_uint_full(str, 10, &length) == 0 && length > 0 && length <= UINT_MAX) { block_acct_add_interval(stats, (unsigned) length); } else { diff --git a/contrib/ivshmem-server/main.c b/contrib/ivshmem-server/main.c index 224dbeb547e..5901f17707e 100644 --- a/contrib/ivshmem-server/main.c +++ b/contrib/ivshmem-server/main.c @@ -69,7 +69,7 @@ static void ivshmem_server_parse_args(IvshmemServerArgs *args, int argc, char *argv[]) { int c; - unsigned long long v; + uint64_t v; Error *err = NULL; while ((c = getopt(argc, argv, "hvFp:S:m:M:l:n:")) != -1) { @@ -112,7 +112,7 @@ ivshmem_server_parse_args(IvshmemServerArgs *args, int argc, char *argv[]) break; case 'n': /* number of vectors */ - if (parse_uint_full(optarg, &v, 0) < 0) { + if (parse_uint_full(optarg, 0, &v) < 0) { fprintf(stderr, "cannot parse n_vectors\n"); ivshmem_server_help(argv[0]); exit(1); diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c index 587f31baf6b..8812d23677a 100644 --- a/qapi/opts-visitor.c +++ b/qapi/opts-visitor.c @@ -454,8 +454,8 @@ opts_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) OptsVisitor *ov = to_ov(v); const QemuOpt *opt; const char *str; - unsigned long long val; - char *endptr; + uint64_t val; + const char *endptr; if (ov->list_mode == LM_UNSIGNED_INTERVAL) { *obj = ov->range_next.u; @@ -471,17 +471,17 @@ opts_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) /* we've gotten past lookup_scalar() */ assert(ov->list_mode == LM_NONE || ov->list_mode == LM_IN_PROGRESS); - if (parse_uint(str, &val, &endptr, 0) == 0 && val <= UINT64_MAX) { + if (parse_uint(str, &endptr, 0, &val) == 0 && val <= UINT64_MAX) { if (*endptr == '\0') { *obj = val; processed(ov, name); return true; } if (*endptr == '-' && ov->list_mode == LM_IN_PROGRESS) { - unsigned long long val2; + uint64_t val2; str = endptr + 1; - if (parse_uint_full(str, &val2, 0) == 0 && + if (parse_uint_full(str, 0, &val2) == 0 && val2 <= UINT64_MAX && val <= val2 && val2 - val < OPTS_VISITOR_RANGE_MAX) { ov->range_next.u = val; diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 08989d1d3ac..0c7d07b3297 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -31,12 +31,11 @@ static void test_parse_uint_null(void) { - unsigned long long i = 999; - char f = 'X'; - char *endptr = &f; + uint64_t i = 999; + const char *endptr = "somewhere"; int r; - r = parse_uint(NULL, &i, &endptr, 0); + r = parse_uint(NULL, &endptr, 0, &i); g_assert_cmpint(r, ==, -EINVAL); g_assert_cmpuint(i, ==, 0); @@ -45,13 +44,12 @@ static void test_parse_uint_null(void) static void test_parse_uint_empty(void) { - unsigned long long i = 999; - char f = 'X'; - char *endptr = &f; + uint64_t i = 999; + const char *endptr = "somewhere"; const char *str = ""; int r; - r = parse_uint(str, &i, &endptr, 0); + r = parse_uint(str, &endptr, 0, &i); g_assert_cmpint(r, ==, -EINVAL); g_assert_cmpuint(i, ==, 0); @@ -60,13 +58,12 @@ static void test_parse_uint_empty(void) static void test_parse_uint_whitespace(void) { - unsigned long long i = 999; - char f = 'X'; - char *endptr = &f; + uint64_t i = 999; + const char *endptr = "somewhere"; const char *str = " \t "; int r; - r = parse_uint(str, &i, &endptr, 0); + r = parse_uint(str, &endptr, 0, &i); g_assert_cmpint(r, ==, -EINVAL); g_assert_cmpuint(i, ==, 0); @@ -76,13 +73,12 @@ static void test_parse_uint_whitespace(void) static void test_parse_uint_invalid(void) { - unsigned long long i = 999; - char f = 'X'; - char *endptr = &f; + uint64_t i = 999; + const char *endptr = "somewhere"; const char *str = " \t xxx"; int r; - r = parse_uint(str, &i, &endptr, 0); + r = parse_uint(str, &endptr, 0, &i); g_assert_cmpint(r, ==, -EINVAL); g_assert_cmpuint(i, ==, 0); @@ -92,13 +88,12 @@ static void test_parse_uint_invalid(void) static void test_parse_uint_trailing(void) { - unsigned long long i = 999; - char f = 'X'; - char *endptr = &f; + uint64_t i = 999; + const char *endptr = "somewhere"; const char *str = "123xxx"; int r; - r = parse_uint(str, &i, &endptr, 0); + r = parse_uint(str, &endptr, 0, &i); g_assert_cmpint(r, ==, 0); g_assert_cmpuint(i, ==, 123); @@ -107,13 +102,12 @@ static void test_parse_uint_trailing(void) static void test_parse_uint_correct(void) { - unsigned long long i = 999; - char f = 'X'; - char *endptr = &f; + uint64_t i = 999; + const char *endptr = "somewhere"; const char *str = "123"; int r; - r = parse_uint(str, &i, &endptr, 0); + r = parse_uint(str, &endptr, 0, &i); g_assert_cmpint(r, ==, 0); g_assert_cmpuint(i, ==, 123); @@ -122,13 +116,12 @@ static void test_parse_uint_correct(void) static void test_parse_uint_octal(void) { - unsigned long long i = 999; - char f = 'X'; - char *endptr = &f; + uint64_t i = 999; + const char *endptr = "somewhere"; const char *str = "0123"; int r; - r = parse_uint(str, &i, &endptr, 0); + r = parse_uint(str, &endptr, 0, &i); g_assert_cmpint(r, ==, 0); g_assert_cmpuint(i, ==, 0123); @@ -137,13 +130,12 @@ static void test_parse_uint_octal(void) static void test_parse_uint_decimal(void) { - unsigned long long i = 999; - char f = 'X'; - char *endptr = &f; + uint64_t i = 999; + const char *endptr = "somewhere"; const char *str = "0123"; int r; - r = parse_uint(str, &i, &endptr, 10); + r = parse_uint(str, &endptr, 10, &i); g_assert_cmpint(r, ==, 0); g_assert_cmpuint(i, ==, 123); @@ -152,13 +144,12 @@ static void test_parse_uint_decimal(void) static void test_parse_uint_llong_max(void) { - unsigned long long i = 999; - char f = 'X'; - char *endptr = &f; + uint64_t i = 999; + const char *endptr = "somewhere"; char *str = g_strdup_printf("%llu", (unsigned long long)LLONG_MAX + 1); int r; - r = parse_uint(str, &i, &endptr, 0); + r = parse_uint(str, &endptr, 0, &i); g_assert_cmpint(r, ==, 0); g_assert_cmpuint(i, ==, (unsigned long long)LLONG_MAX + 1); @@ -169,13 +160,12 @@ static void test_parse_uint_llong_max(void) static void test_parse_uint_max(void) { - unsigned long long i = 999; - char f = 'X'; - char *endptr = &f; + uint64_t i = 999; + const char *endptr = "somewhere"; char *str = g_strdup_printf("%llu", ULLONG_MAX); int r; - r = parse_uint(str, &i, &endptr, 0); + r = parse_uint(str, &endptr, 0, &i); g_assert_cmpint(r, ==, 0); g_assert_cmpuint(i, ==, ULLONG_MAX); @@ -186,32 +176,31 @@ static void test_parse_uint_max(void) static void test_parse_uint_overflow(void) { - unsigned long long i; - char f = 'X'; - char *endptr; + uint64_t i; + const char *endptr = "somewhere"; const char *str; int r; i = 999; - endptr = &f; + endptr = "somewhere"; str = "99999999999999999999999999999999999999"; - r = parse_uint(str, &i, &endptr, 0); + r = parse_uint(str, &endptr, 0, &i); g_assert_cmpint(r, ==, -ERANGE); g_assert_cmpuint(i, ==, ULLONG_MAX); g_assert_true(endptr == str + strlen(str)); i = 999; - endptr = &f; + endptr = "somewhere"; str = "0x10000000000000000"; /* 65 bits, 64-bit sign bit clear */ - r = parse_uint(str, &i, &endptr, 0); + r = parse_uint(str, &endptr, 0, &i); g_assert_cmpint(r, ==, -ERANGE); g_assert_cmpuint(i, ==, ULLONG_MAX); g_assert_true(endptr == str + strlen(str)); i = 999; - endptr = &f; + endptr = "somewhere"; str = "0x18000000080000000"; /* 65 bits, 64-bit sign bit set */ - r = parse_uint(str, &i, &endptr, 0); + r = parse_uint(str, &endptr, 0, &i); g_assert_cmpint(r, ==, -ERANGE); g_assert_cmpuint(i, ==, ULLONG_MAX); g_assert_true(endptr == str + strlen(str)); @@ -219,13 +208,12 @@ static void test_parse_uint_overflow(void) static void test_parse_uint_negative(void) { - unsigned long long i = 999; - char f = 'X'; - char *endptr = &f; + uint64_t i = 999; + const char *endptr = "somewhere"; const char *str = " \t -321"; int r; - r = parse_uint(str, &i, &endptr, 0); + r = parse_uint(str, &endptr, 0, &i); g_assert_cmpint(r, ==, -ERANGE); g_assert_cmpuint(i, ==, 0); @@ -234,13 +222,12 @@ static void test_parse_uint_negative(void) static void test_parse_uint_negzero(void) { - unsigned long long i = 999; - char f = 'X'; - char *endptr = &f; + uint64_t i = 999; + const char *endptr = "somewhere"; const char *str = " -0"; int r; - r = parse_uint(str, &i, &endptr, 0); + r = parse_uint(str, &endptr, 0, &i); g_assert_cmpint(r, ==, -ERANGE); g_assert_cmpuint(i, ==, 0); @@ -249,11 +236,11 @@ static void test_parse_uint_negzero(void) static void test_parse_uint_full_trailing(void) { - unsigned long long i = 999; + uint64_t i = 999; const char *str = "123xxx"; int r; - r = parse_uint_full(str, &i, 0); + r = parse_uint_full(str, 0, &i); g_assert_cmpint(r, ==, -EINVAL); g_assert_cmpuint(i, ==, 0); @@ -261,11 +248,11 @@ static void test_parse_uint_full_trailing(void) static void test_parse_uint_full_correct(void) { - unsigned long long i = 999; + uint64_t i = 999; const char *str = "123"; int r; - r = parse_uint_full(str, &i, 0); + r = parse_uint_full(str, 0, &i); g_assert_cmpint(r, ==, 0); g_assert_cmpuint(i, ==, 123); @@ -274,11 +261,11 @@ static void test_parse_uint_full_correct(void) static void test_parse_uint_full_erange_junk(void) { /* FIXME - inconsistent with qemu_strto* which favors EINVAL */ - unsigned long long i = 999; + uint64_t i = 999; const char *str = "-2junk"; int r; - r = parse_uint_full(str, &i, 0); + r = parse_uint_full(str, 0, &i); g_assert_cmpint(r, ==, -ERANGE /* FIXME -EINVAL */); g_assert_cmpuint(i, ==, 0); diff --git a/ui/vnc.c b/ui/vnc.c index 9d8a24dd8a6..92964dcc0c0 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -3728,7 +3728,7 @@ static int vnc_display_get_address(const char *addrstr, } else { const char *port; size_t hostlen; - unsigned long long baseport = 0; + uint64_t baseport = 0; InetSocketAddress *inet; port = strrchr(addrstr, ':'); @@ -3776,7 +3776,7 @@ static int vnc_display_get_address(const char *addrstr, } } else { int offset = reverse ? 0 : 5900; - if (parse_uint_full(port, &baseport, 10) < 0) { + if (parse_uint_full(port, 10, &baseport) < 0) { error_setg(errp, "can't convert to a number: %s", port); goto cleanup; } diff --git a/util/cutils.c b/util/cutils.c index 4e3cc6e3605..8ab0cae5e75 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -715,10 +715,10 @@ const char *qemu_strchrnul(const char *s, int c) * parse_uint: * * @s: String to parse - * @value: Destination for parsed integer value * @endptr: Destination for pointer to first character not consumed, must * not be %NULL * @base: integer base, between 2 and 36 inclusive, or 0 + * @value: Destination for parsed integer value * * Parse unsigned integer * @@ -741,8 +741,7 @@ const char *qemu_strchrnul(const char *s, int c) * * Else, set *@value to the parsed integer, and return 0. */ -int parse_uint(const char *s, unsigned long long *value, char **endptr, - int base) +int parse_uint(const char *s, const char **endptr, int base, uint64_t *value) { int r = 0; char *endp = (char *)s; @@ -786,8 +785,8 @@ out: * parse_uint_full: * * @s: String to parse - * @value: Destination for parsed integer value * @base: integer base, between 2 and 36 inclusive, or 0 + * @value: Destination for parsed integer value * * Parse unsigned integer from entire string * @@ -796,12 +795,12 @@ out: * characters are present after a non-overflowing parsed number, the * function will return -EINVAL, and *@v will be set to 0. */ -int parse_uint_full(const char *s, unsigned long long *value, int base) +int parse_uint_full(const char *s, int base, uint64_t *value) { - char *endp; + const char *endp; int r; - r = parse_uint(s, value, &endp, base); + r = parse_uint(s, &endp, base, value); if (r < 0) { return r; } diff --git a/util/guest-random.c b/util/guest-random.c index a24d27624c6..9465dda085d 100644 --- a/util/guest-random.c +++ b/util/guest-random.c @@ -89,8 +89,8 @@ void qemu_guest_random_seed_thread_part2(uint64_t seed) int qemu_guest_random_seed_main(const char *optarg, Error **errp) { - unsigned long long seed; - if (parse_uint_full(optarg, &seed, 0)) { + uint64_t seed; + if (parse_uint_full(optarg, 0, &seed)) { error_setg(errp, "Invalid seed number: %s", optarg); return -1; } else { diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index c06a4dce77c..892d33f5e6b 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -249,12 +249,12 @@ static int inet_listen_saddr(InetSocketAddress *saddr, /* lookup */ if (port_offset) { - unsigned long long baseport; + uint64_t baseport; if (strlen(port) == 0) { error_setg(errp, "port not specified"); return -1; } - if (parse_uint_full(port, &baseport, 10) < 0) { + if (parse_uint_full(port, 10, &baseport) < 0) { error_setg(errp, "can't convert to a number: %s", port); return -1; } @@ -732,19 +732,19 @@ static bool vsock_parse_vaddr_to_sockaddr(const VsockSocketAddress *vaddr, struct sockaddr_vm *svm, Error **errp) { - unsigned long long val; + uint64_t val; memset(svm, 0, sizeof(*svm)); svm->svm_family = AF_VSOCK; - if (parse_uint_full(vaddr->cid, &val, 10) < 0 || + if (parse_uint_full(vaddr->cid, 10, &val) < 0 || val > UINT32_MAX) { error_setg(errp, "Failed to parse cid '%s'", vaddr->cid); return false; } svm->svm_cid = val; - if (parse_uint_full(vaddr->port, &val, 10) < 0 || + if (parse_uint_full(vaddr->port, 10, &val) < 0 || val > UINT32_MAX) { error_setg(errp, "Failed to parse port '%s'", vaddr->port); return false; From patchwork Fri May 12 02:10:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238648 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 33B98C7EE22 for ; Fri, 12 May 2023 02:13:14 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFL-0004j1-GY; Thu, 11 May 2023 22:11:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFJ-0004iJ-BI for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:01 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIF5-0000Pj-60 for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:01 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857446; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=OeThkWJtzwFFyeQiYrIHTjOVUdH6RCaM+PBhuJQ8CB4=; b=LXF19bwpdgragXBCwhUThE2ktOP8D7CzYorGrbkBN6OgKslHtdqBmDIjcwpYqcPCW2ARUe BtpDVN5epjloPcH0GS+N8tpGbLMUB/j9ZtDpq5TpftVdfrK6a4TJf1jW/XyugMeE7b0fLv jZr0pjpaVpK3xUumb2VkFoHwfiaZBtw= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-38-ykWxV1t3PAGnGkxZIfERrw-1; Thu, 11 May 2023 22:10:42 -0400 X-MC-Unique: ykWxV1t3PAGnGkxZIfERrw-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 3D35B101A554; Fri, 12 May 2023 02:10:42 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id CF5402027179; Fri, 12 May 2023 02:10:41 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 08/19] cutils: Allow NULL endptr in parse_uint() Date: Thu, 11 May 2023 21:10:22 -0500 Message-Id: <20230512021033.1378730-9-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org All the qemu_strto*() functions permit a NULL endptr, just like their libc counterparts, leaving parse_uint() as the oddball that caused SEGFAULT on NULL and required the user to call parse_uint_full() instead. Relax things for consistency, even though the testsuite is the only impacted caller. Add one more unit test to ensure even parse_uint_full(NULL, 0, &value) works. This also fixes our code to uniformly favor EINVAL over ERANGE when both apply. Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek --- tests/unit/test-cutils.c | 18 ++++++++++++++++-- util/cutils.c | 34 ++++++++++++---------------------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 0c7d07b3297..d3076c3fec1 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -260,14 +260,26 @@ static void test_parse_uint_full_correct(void) static void test_parse_uint_full_erange_junk(void) { - /* FIXME - inconsistent with qemu_strto* which favors EINVAL */ + /* EINVAL has priority over ERANGE */ uint64_t i = 999; const char *str = "-2junk"; int r; r = parse_uint_full(str, 0, &i); - g_assert_cmpint(r, ==, -ERANGE /* FIXME -EINVAL */); + g_assert_cmpint(r, ==, -EINVAL); + g_assert_cmpuint(i, ==, 0); +} + +static void test_parse_uint_full_null(void) +{ + uint64_t i = 999; + const char *str = NULL; + int r; + + r = parse_uint_full(str, 0, &i); + + g_assert_cmpint(r, ==, -EINVAL); g_assert_cmpuint(i, ==, 0); } @@ -3207,6 +3219,8 @@ int main(int argc, char **argv) test_parse_uint_full_correct); g_test_add_func("/cutils/parse_uint_full/erange_junk", test_parse_uint_full_erange_junk); + g_test_add_func("/cutils/parse_uint_full/null", + test_parse_uint_full_null); /* qemu_strtoi() tests */ g_test_add_func("/cutils/qemu_strtoi/correct", diff --git a/util/cutils.c b/util/cutils.c index 8ab0cae5e75..e599924a0c4 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -715,8 +715,7 @@ const char *qemu_strchrnul(const char *s, int c) * parse_uint: * * @s: String to parse - * @endptr: Destination for pointer to first character not consumed, must - * not be %NULL + * @endptr: Destination for pointer to first character not consumed * @base: integer base, between 2 and 36 inclusive, or 0 * @value: Destination for parsed integer value * @@ -730,7 +729,8 @@ const char *qemu_strchrnul(const char *s, int c) * * Set *@endptr to point right beyond the parsed integer (even if the integer * overflows or is negative, all digits will be parsed and *@endptr will - * point right beyond them). + * point right beyond them). If @endptr is %NULL, any trailing character + * instead causes a result of -EINVAL with *@value of 0. * * If the integer is negative, set *@value to 0, and return -ERANGE. * (If you want to allow negative numbers that wrap around within @@ -777,7 +777,12 @@ int parse_uint(const char *s, const char **endptr, int base, uint64_t *value) out: *value = val; - *endptr = endp; + if (endptr) { + *endptr = endp; + } else if (s && *endp) { + r = -EINVAL; + *value = 0; + } return r; } @@ -788,28 +793,13 @@ out: * @base: integer base, between 2 and 36 inclusive, or 0 * @value: Destination for parsed integer value * - * Parse unsigned integer from entire string + * Parse unsigned integer from entire string, rejecting any trailing slop. * - * Have the same behavior of parse_uint(), but with an additional - * check for additional data after the parsed number. If extra - * characters are present after a non-overflowing parsed number, the - * function will return -EINVAL, and *@v will be set to 0. + * Shorthand for parse_uint(s, NULL, base, value). */ int parse_uint_full(const char *s, int base, uint64_t *value) { - const char *endp; - int r; - - r = parse_uint(s, &endp, base, value); - if (r < 0) { - return r; - } - if (*endp) { - *value = 0; - return -EINVAL; - } - - return 0; + return parse_uint(s, NULL, base, value); } int qemu_parse_fd(const char *param) From patchwork Fri May 12 02:10:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238653 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2B9F2C7EE22 for ; Fri, 12 May 2023 02:13:45 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFQ-0004lZ-9b; Thu, 11 May 2023 22:11:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFP-0004ko-2I for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:07 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIF4-0000PU-Fm for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:06 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857444; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nLFAYMZTrs7UhC5UCNVkTIALW2wggwGPhMX4WnvcvVU=; b=BMDWH4FASW7Qi8kIREDN9npw0A73kKPYA+jviyeJD47Ls5Zi9VkSqsl2dJzJFc2Bx33zhe oNmGFZPYJFBKkmDb6EATEx28A4th02JjJWPC5m8Aw7vTHFNVflOKDr18rqlLM2qTGgsd9z IJu7yIlQjnI1MujfCDrBLQm2YP2NO34= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-433-2K-8XzBaMrOeMm_S2uwOwg-1; Thu, 11 May 2023 22:10:43 -0400 X-MC-Unique: 2K-8XzBaMrOeMm_S2uwOwg-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id CC86B80067D; Fri, 12 May 2023 02:10:42 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6904320268C4; Fri, 12 May 2023 02:10:42 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 09/19] test-cutils: Add coverage of qemu_strtod Date: Thu, 11 May 2023 21:10:23 -0500 Message-Id: <20230512021033.1378730-10-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.129.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org It's hard to tweak code for consistency if I can't prove what will or won't break from those tweaks. Time to add unit tests for qemu_strtod() and qemu_strtod_finite(). Among other things, I wrote a check whether we have C99 semantics for strtod("0x1") (which MUST parse hex numbers) rather than C89 (which must stop parsing at 'x'). These days, I suspect that is okay; but if it fails CI checks, knowing the difference will help us decide what we want to do about it. Note that C2x, while not final at the time of this patch, has been considering whether to make strtol("0b1") parse as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that decision may also bleed over to strtod(). But for now, I didn't think it worth adding unit tests on that front (to strtol or strtod) as things may still change. Likewise, there are plenty more corner cases of strtod proper that I don't explicitly test here, but there are enough unit tests added here that it covers all the branches reached in our wrappers. In particular, it demonstrates the difference on when *value is left uninitialized, which an upcoming patch will normalize. Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek --- v2: Added g_assert_false(signbit(res)) anywhere I used g_assert_cmpfloat(res,==,0.0); add a test for strtod() hex parsing and handling of junk after ERANGE, which is major enough that I dropped R-b --- tests/unit/test-cutils.c | 510 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 510 insertions(+) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index d3076c3fec1..1763839a157 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -25,6 +25,8 @@ * THE SOFTWARE. */ +#include + #include "qemu/osdep.h" #include "qemu/cutils.h" #include "qemu/units.h" @@ -2668,6 +2670,485 @@ static void test_qemu_strtou64_full_erange_junk(void) g_assert_cmpint(res, ==, UINT64_MAX); } +static void test_qemu_strtod_simple(void) +{ + const char *str; + const char *endptr; + int err; + double res; + + /* no radix or exponent */ + str = "1"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpfloat(res, ==, 1.0); + g_assert_true(endptr == str + 1); + + /* leading space and sign */ + str = " -0.0"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpfloat(res, ==, -0.0); + g_assert_true(signbit(res)); + g_assert_true(endptr == str + 5); + + /* fraction only */ + str = "+.5"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpfloat(res, ==, 0.5); + g_assert_true(endptr == str + 3); + + /* exponent */ + str = "1.e+1"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpfloat(res, ==, 10.0); + g_assert_true(endptr == str + 5); + + /* hex without radix */ + str = "0x10"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpfloat(res, ==, 16.0); + g_assert_true(endptr == str + 4); +} + +static void test_qemu_strtod_einval(void) +{ + const char *str; + const char *endptr; + int err; + double res; + + /* empty */ + str = ""; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 0.0); + g_assert_false(signbit(res)); + g_assert_true(endptr == str); + + /* NULL */ + str = NULL; + endptr = "random"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 999.0); + g_assert_null(endptr); + + /* not recognizable */ + str = " junk"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 0.0); + g_assert_false(signbit(res)); + g_assert_true(endptr == str); +} + +static void test_qemu_strtod_erange(void) +{ + const char *str; + const char *endptr; + int err; + double res; + + /* overflow */ + str = "9e999"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpfloat(res, ==, HUGE_VAL); + g_assert_true(endptr == str + 5); + + str = "-9e+999"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpfloat(res, ==, -HUGE_VAL); + g_assert_true(endptr == str + 7); + + /* underflow */ + str = "-9e-999"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpfloat(res, >=, -DBL_MIN); + g_assert_cmpfloat(res, <=, -0.0); + g_assert_true(signbit(res)); + g_assert_true(endptr == str + 7); +} + +static void test_qemu_strtod_nonfinite(void) +{ + const char *str; + const char *endptr; + int err; + double res; + + /* infinity */ + str = "inf"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_true(isinf(res)); + g_assert_false(signbit(res)); + g_assert_true(endptr == str + 3); + + str = "-infinity"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_true(isinf(res)); + g_assert_true(signbit(res)); + g_assert_true(endptr == str + 9); + + /* not a number */ + str = " NaN"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_true(isnan(res)); + g_assert_true(endptr == str + 4); +} + +static void test_qemu_strtod_trailing(void) +{ + const char *str; + const char *endptr; + int err; + double res; + + /* trailing whitespace */ + str = "1. "; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpfloat(res, ==, 1.0); + g_assert_true(endptr == str + 2); + + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, NULL, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 1.0); + + /* trailing e is not an exponent */ + str = ".5e"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpfloat(res, ==, 0.5); + g_assert_true(endptr == str + 2); + + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, NULL, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 0.5); + + /* trailing ( not part of long NaN */ + str = "nan("; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_true(isnan(res)); + g_assert_true(endptr == str + 3); + + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, NULL, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_true(isnan(res)); +} + +static void test_qemu_strtod_erange_junk(void) +{ + const char *str; + const char *endptr; + int err; + double res; + + /* EINVAL has priority over ERANGE */ + str = "1e-999junk"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpfloat(res, <=, DBL_MIN); + g_assert_cmpfloat(res, >=, 0.0); + g_assert_false(signbit(res)); + g_assert_true(endptr == str + 6); + + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, NULL, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 0.0); + g_assert_false(signbit(res)); +} + +static void test_qemu_strtod_finite_simple(void) +{ + const char *str; + const char *endptr; + int err; + double res; + + /* no radix or exponent */ + str = "1"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpfloat(res, ==, 1.0); + g_assert_true(endptr == str + 1); + + /* leading space and sign */ + str = " -0.0"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpfloat(res, ==, -0.0); + g_assert_true(signbit(res)); + g_assert_true(endptr == str + 5); + + /* fraction only */ + str = "+.5"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpfloat(res, ==, 0.5); + g_assert_true(endptr == str + 3); + + /* exponent */ + str = "1.e+1"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpfloat(res, ==, 10.0); + g_assert_true(endptr == str + 5); + + /* hex without radix */ + str = "0x10"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpfloat(res, ==, 16.0); + g_assert_true(endptr == str + 4); +} + +static void test_qemu_strtod_finite_einval(void) +{ + const char *str; + const char *endptr; + int err; + double res; + + /* empty */ + str = ""; + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 999.0); + g_assert_true(endptr == str); + + /* NULL */ + str = NULL; + endptr = "random"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 999.0); + g_assert_null(endptr); + + /* not recognizable */ + str = " junk"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 999.0); + g_assert_true(endptr == str); +} + +static void test_qemu_strtod_finite_erange(void) +{ + const char *str; + const char *endptr; + int err; + double res; + + /* overflow */ + str = "9e999"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpfloat(res, ==, HUGE_VAL); + g_assert_true(endptr == str + 5); + + str = "-9e+999"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpfloat(res, ==, -HUGE_VAL); + g_assert_true(endptr == str + 7); + + /* underflow */ + str = "-9e-999"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpfloat(res, >=, -DBL_MIN); + g_assert_cmpfloat(res, <=, -0.0); + g_assert_true(signbit(res)); + g_assert_true(endptr == str + 7); +} + +static void test_qemu_strtod_finite_nonfinite(void) +{ + const char *str; + const char *endptr; + int err; + double res; + + /* infinity */ + str = "inf"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 999.0); + g_assert_true(endptr == str); + + str = "-infinity"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 999.0); + g_assert_true(endptr == str); + + /* not a number */ + str = " NaN"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 999.0); + g_assert_true(endptr == str); +} + +static void test_qemu_strtod_finite_trailing(void) +{ + const char *str; + const char *endptr; + int err; + double res; + + /* trailing whitespace */ + str = "1. "; + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpfloat(res, ==, 1.0); + g_assert_true(endptr == str + 2); + + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, NULL, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 999.0); + + /* trailing e is not an exponent */ + str = ".5e"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpfloat(res, ==, 0.5); + g_assert_true(endptr == str + 2); + + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, NULL, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 999.0); + + /* trailing ( not part of long NaN */ + str = "nan("; + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 999.0); + g_assert_true(endptr == str); + + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, NULL, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 999.0); +} + +static void test_qemu_strtod_finite_erange_junk(void) +{ + const char *str; + const char *endptr; + int err; + double res; + + /* EINVAL has priority over ERANGE */ + str = "1e-999junk"; + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, &endptr, &res); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpfloat(res, <=, DBL_MIN); + g_assert_cmpfloat(res, >=, 0.0); + g_assert_false(signbit(res)); + g_assert_true(endptr == str + 6); + + endptr = "somewhere"; + res = 999; + err = qemu_strtod_finite(str, NULL, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 999.0); +} + static void test_qemu_strtosz_simple(void) { const char *str; @@ -3510,6 +3991,35 @@ int main(int argc, char **argv) g_test_add_func("/cutils/qemu_strtou64_full/erange_junk", test_qemu_strtou64_full_erange_junk); + /* qemu_strtod() tests */ + g_test_add_func("/cutils/qemu_strtod/simple", + test_qemu_strtod_simple); + g_test_add_func("/cutils/qemu_strtod/einval", + test_qemu_strtod_einval); + g_test_add_func("/cutils/qemu_strtod/erange", + test_qemu_strtod_erange); + g_test_add_func("/cutils/qemu_strtod/nonfinite", + test_qemu_strtod_nonfinite); + g_test_add_func("/cutils/qemu_strtod/trailing", + test_qemu_strtod_trailing); + g_test_add_func("/cutils/qemu_strtod/erange_junk", + test_qemu_strtod_erange_junk); + + /* qemu_strtod_finite() tests */ + g_test_add_func("/cutils/qemu_strtod_finite/simple", + test_qemu_strtod_finite_simple); + g_test_add_func("/cutils/qemu_strtod_finite/einval", + test_qemu_strtod_finite_einval); + g_test_add_func("/cutils/qemu_strtod_finite/erange", + test_qemu_strtod_finite_erange); + g_test_add_func("/cutils/qemu_strtod_finite/nonfinite", + test_qemu_strtod_finite_nonfinite); + g_test_add_func("/cutils/qemu_strtod_finite/trailing", + test_qemu_strtod_finite_trailing); + g_test_add_func("/cutils/qemu_strtod_finite/erange_junk", + test_qemu_strtod_finite_erange_junk); + + /* qemu_strtosz() tests */ g_test_add_func("/cutils/strtosz/simple", test_qemu_strtosz_simple); g_test_add_func("/cutils/strtosz/hex", From patchwork Fri May 12 02:10:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238641 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 19AB9C7EE22 for ; Fri, 12 May 2023 02:12:47 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFM-0004jG-5N; Thu, 11 May 2023 22:11:04 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFK-0004iZ-M1 for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:02 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIF7-0000Pp-DH for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857447; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VGvJUCJmp1bA+wDFc1AmlVQwvzMMZFyPER4qCdGgIsU=; b=ThjpZG7W5YmZ1qut2Snqn9s0ygUiHWj0aC7NR2kD35prs983j79ZfpVIbZnV8tiRRl4GJG 5fCNqzGceCyZ6VrL/q1Dix+KrkiA67ydn+3ULhd4Bv0InSZSH2KU2yp4i5W/TJttQSlJrv y7suVfhwJzn508CTLFiu/a+Pm+5ITqc= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-15-Afv7vAp9ONG962AOQZAjnA-1; Thu, 11 May 2023 22:10:43 -0400 X-MC-Unique: Afv7vAp9ONG962AOQZAjnA-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 6C6FB85A588; Fri, 12 May 2023 02:10:43 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id 095522028B5E; Fri, 12 May 2023 02:10:42 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 10/19] test-cutils: Prepare for upcoming semantic change in qemu_strtosz Date: Thu, 11 May 2023 21:10:24 -0500 Message-Id: <20230512021033.1378730-11-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.129.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org A quick search for 'qemu_strtosz' in the code base shows that outside of the testsuite, the ONLY place that passes a non-NULL pointer to @endptr of any variant of a size parser is in hmp.c (the 'o' parser of monitor_parse_arguments), and that particular caller warns of "extraneous characters at the end of line" unless the trailing bytes are purely whitespace. Thus, it makes no semantic difference at the high level whether we parse "1.5e1k" as "1" + ".5e1" + "k" (an attempt to use scientific notation in strtod with a scaling suffix of 'k' with no trailing junk, but which qemu_strtosz says should fail with EINVAL), or as "1.5e" + "1k" (a valid size with scaling suffix of 'e' for exabytes, followed by two junk bytes) - either way, any user passing such a string will get an error message about a parse failure. However, an upcoming patch to qemu_strtosz will fix other corner case bugs in handling the fractional portion of a size, and in doing so, it is easier to declare that qemu_strtosz() itself stops parsing at the first 'e' rather than blindly consuming whatever strtod() will recognize. Once that is fixed, the difference will be visible at the low level (getting a valid parse with trailing garbage when @endptr is non-NULL, while continuing to get -EINVAL when @endptr is NULL); this is easier to demonstrate by moving the affected strings from test_qemu_strtosz_invalid() (which declares them as always -EINVAL) to test_qemu_strtosz_trailing() (where @endptr affects behavior, for now with FIXME comments). Note that a similar argument could be made for having "0x1.5" or "0x1M" parse as 0x1 with ".5" or "M" as trailing junk, instead of blindly treating it as -EINVAL; however, as these cases do not suffer from the same problems as floating point, they are not worth changing at this time. Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek --- tests/unit/test-cutils.c | 42 ++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 1763839a157..fe9be690faf 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -3440,21 +3440,6 @@ static void test_qemu_strtosz_invalid(void) g_assert_cmphex(res, ==, 0xbaadf00d); g_assert_true(endptr == str); - /* No floating point exponents */ - str = "1.5e1k"; - endptr = NULL; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - g_assert_true(endptr == str); - - str = "1.5E+0k"; - endptr = NULL; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - g_assert_true(endptr == str); - /* No hex fractions */ str = "0x1.8k"; endptr = NULL; @@ -3558,6 +3543,33 @@ static void test_qemu_strtosz_trailing(void) err = qemu_strtosz(str, NULL, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert_cmphex(res, ==, 0xbaadf00d); + + /* FIXME should stop parse after 'e'. No floating point exponents */ + str = "1.5e1k"; + endptr = NULL; + res = 0xbaadf00d; + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, -EINVAL /* FIXME 0 */); + g_assert_cmphex(res, ==, 0xbaadf00d /* FIXME EiB * 1.5 */); + g_assert_true(endptr == str /* FIXME + 4 */); + + res = 0xbaadf00d; + err = qemu_strtosz(str, NULL, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 0xbaadf00d); + + str = "1.5E+0k"; + endptr = NULL; + res = 0xbaadf00d; + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, -EINVAL /* FIXME 0 */); + g_assert_cmphex(res, ==, 0xbaadf00d /* FIXME EiB * 1.5 */); + g_assert_true(endptr == str /* FIXME + 4 */); + + res = 0xbaadf00d; + err = qemu_strtosz(str, NULL, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmphex(res, ==, 0xbaadf00d); } static void test_qemu_strtosz_erange(void) From patchwork Fri May 12 02:10:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238646 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7D902C7EE22 for ; Fri, 12 May 2023 02:13:06 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFQ-0004lx-Tp; Thu, 11 May 2023 22:11:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFP-0004kp-5E for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:07 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIF8-0000Ps-LU for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:06 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857447; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=LlW6Fq0O05ptvhK7xYHPQUC6gRj2LzsvlCA42nzj0XY=; b=QA8nw8KIpCphUCNIDVF5k95nymKbvzXUd0YsjThrhy9OBJTk9w4tbIU7bM0jezxQSm/I85 /1zsjMEhq+Kk5e/sTDRBudptCGCcNbbbuiJ8FSxo0Ne61tSZNArNU6MDqKRScJtbS+0Ce/ 9cexwblDg6Rerdats0vcE/xYHyDFXrY= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-21-RPDPmVOrOyiNzgKrmpoRRw-1; Thu, 11 May 2023 22:10:44 -0400 X-MC-Unique: RPDPmVOrOyiNzgKrmpoRRw-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 08D2B101A551; Fri, 12 May 2023 02:10:44 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9932E2024CDC; Fri, 12 May 2023 02:10:43 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 11/19] test-cutils: Refactor qemu_strtosz tests for less boilerplate Date: Thu, 11 May 2023 21:10:25 -0500 Message-Id: <20230512021033.1378730-12-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.129.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org No need to copy-and-paste lots of boilerplate per string tested, when we can consolidate that behind helper functions. Plus, this adds a bit more coverage (we now test all strings both with and without endptr, whereas before some tests skipped the NULL endptr case), which exposed a SEGFAULT on qemu_strtosz(NULL, NULL, &val) that will be parsed in an upcoming patch. Note that duplicating boilerplate has one advantage lost here - a failed test tells you which line number failed; but a helper function does not show the call stack that reached the failure. Since we call the helper more than once within many of the "unit tests", even the unit test name doesn't point out which call is failing. But that only matters when tests fail (they normally pass); at which point I'm debugging the failures under gdb anyways, so I'm not too worried about it. Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek --- tests/unit/test-cutils.c | 503 ++++++++------------------------------- 1 file changed, 100 insertions(+), 403 deletions(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index fe9be690faf..5c9ed78be93 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -3149,473 +3149,170 @@ static void test_qemu_strtod_finite_erange_junk(void) g_assert_cmpfloat(res, ==, 999.0); } +typedef int (*qemu_strtosz_fn)(const char *, const char **, uint64_t *); +static void do_strtosz_full(const char *str, qemu_strtosz_fn fn, + int exp_ptr_ret, uint64_t exp_ptr_val, + size_t exp_ptr_offset, int exp_null_ret, + uint64_t exp_null_val) +{ + const char *endptr = "somewhere"; + uint64_t val = 0xbaadf00d; + int ret; + + ret = fn(str, &endptr, &val); + g_assert_cmpint(ret, ==, exp_ptr_ret); + g_assert_cmpuint(val, ==, exp_ptr_val); + g_assert_true(endptr == str + exp_ptr_offset); + + val = 0xbaadf00d; + ret = fn(str, NULL, &val); + g_assert_cmpint(ret, ==, exp_null_ret); + g_assert_cmpuint(val, ==, exp_null_val); +} + +static void do_strtosz(const char *str, int exp_ret, uint64_t exp_val, + size_t exp_offset) +{ + do_strtosz_full(str, qemu_strtosz, exp_ret, exp_val, exp_offset, + exp_ret, exp_val); +} + +static void do_strtosz_MiB(const char *str, int exp_ret, uint64_t exp_val, + size_t exp_offset) +{ + do_strtosz_full(str, qemu_strtosz_MiB, exp_ret, exp_val, exp_offset, + exp_ret, exp_val); +} + +static void do_strtosz_metric(const char *str, int exp_ret, uint64_t exp_val, + size_t exp_offset) +{ + do_strtosz_full(str, qemu_strtosz_metric, exp_ret, exp_val, exp_offset, + exp_ret, exp_val); +} + static void test_qemu_strtosz_simple(void) { - const char *str; - const char *endptr; - int err; - uint64_t res; - - str = "0"; - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 0); - g_assert_true(endptr == str + 1); + do_strtosz("0", 0, 0, 1); /* Leading 0 gives decimal results, not octal */ - str = "08"; - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 8); - g_assert_true(endptr == str + 2); + do_strtosz("08", 0, 8, 2); /* Leading space is ignored */ - str = " 12345"; - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 12345); - g_assert_true(endptr == str + 6); + do_strtosz(" 12345", 0, 12345, 6); - res = 0xbaadf00d; - err = qemu_strtosz(str, NULL, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 12345); + /* 2^53-1 */ + do_strtosz("9007199254740991", 0, 0x1fffffffffffffULL, 16); - str = "9007199254740991"; /* 2^53-1 */ - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmphex(res, ==, 0x1fffffffffffffULL); - g_assert_true(endptr == str + 16); + /* 2^53 */ + do_strtosz("9007199254740992", 0, 0x20000000000000ULL, 16); - str = "9007199254740992"; /* 2^53 */ - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmphex(res, ==, 0x20000000000000ULL); - g_assert_true(endptr == str + 16); + /* 2^53+1 */ + do_strtosz("9007199254740993", 0, 0x20000000000001ULL, 16); - str = "9007199254740993"; /* 2^53+1 */ - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmphex(res, ==, 0x20000000000001ULL); - g_assert_true(endptr == str + 16); + /* 0xfffffffffffff800 (53 msbs set) */ + do_strtosz("18446744073709549568", 0, 0xfffffffffffff800ULL, 20); - str = "18446744073709549568"; /* 0xfffffffffffff800 (53 msbs set) */ - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmphex(res, ==, 0xfffffffffffff800ULL); - g_assert_true(endptr == str + 20); + /* 0xfffffffffffffbff */ + do_strtosz("18446744073709550591", 0, 0xfffffffffffffbffULL, 20); - str = "18446744073709550591"; /* 0xfffffffffffffbff */ - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmphex(res, ==, 0xfffffffffffffbffULL); - g_assert_true(endptr == str + 20); - - str = "18446744073709551615"; /* 0xffffffffffffffff */ - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmphex(res, ==, 0xffffffffffffffffULL); - g_assert_true(endptr == str + 20); + /* 0xffffffffffffffff */ + do_strtosz("18446744073709551615", 0, 0xffffffffffffffffULL, 20); } static void test_qemu_strtosz_hex(void) { - const char *str; - const char *endptr; - int err; - uint64_t res; + do_strtosz("0x0", 0, 0, 3); - str = "0x0"; - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 0); - g_assert_true(endptr == str + 3); + do_strtosz("0xab", 0, 171, 4); - str = "0xab"; - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 171); - g_assert_true(endptr == str + 4); - - str = "0xae"; - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 174); - g_assert_true(endptr == str + 4); + do_strtosz("0xae", 0, 174, 4); } static void test_qemu_strtosz_units(void) { - const char *none = "1"; - const char *b = "1B"; - const char *k = "1K"; - const char *m = "1M"; - const char *g = "1G"; - const char *t = "1T"; - const char *p = "1P"; - const char *e = "1E"; - int err; - const char *endptr; - uint64_t res; - /* default is M */ - endptr = NULL; - res = 0xbaadf00d; - err = qemu_strtosz_MiB(none, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, MiB); - g_assert_true(endptr == none + 1); + do_strtosz_MiB("1", 0, MiB, 1); - endptr = NULL; - res = 0xbaadf00d; - err = qemu_strtosz(b, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 1); - g_assert_true(endptr == b + 2); + do_strtosz("1B", 0, 1, 2); - endptr = NULL; - res = 0xbaadf00d; - err = qemu_strtosz(k, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, KiB); - g_assert_true(endptr == k + 2); - - endptr = NULL; - res = 0xbaadf00d; - err = qemu_strtosz(m, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, MiB); - g_assert_true(endptr == m + 2); - - endptr = NULL; - res = 0xbaadf00d; - err = qemu_strtosz(g, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, GiB); - g_assert_true(endptr == g + 2); - - endptr = NULL; - res = 0xbaadf00d; - err = qemu_strtosz(t, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, TiB); - g_assert_true(endptr == t + 2); - - endptr = NULL; - res = 0xbaadf00d; - err = qemu_strtosz(p, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, PiB); - g_assert_true(endptr == p + 2); - - endptr = NULL; - res = 0xbaadf00d; - err = qemu_strtosz(e, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, EiB); - g_assert_true(endptr == e + 2); + do_strtosz("1K", 0, KiB, 2); + do_strtosz("1M", 0, MiB, 2); + do_strtosz("1G", 0, GiB, 2); + do_strtosz("1T", 0, TiB, 2); + do_strtosz("1P", 0, PiB, 2); + do_strtosz("1E", 0, EiB, 2); } static void test_qemu_strtosz_float(void) { - const char *str; - int err; - const char *endptr; - uint64_t res; - - str = "0.5E"; - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, EiB / 2); - g_assert_true(endptr == str + 4); + do_strtosz("0.5E", 0, EiB / 2, 4); /* For convenience, a fraction of 0 is tolerated even on bytes */ - str = "1.0B"; - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 1); - g_assert_true(endptr == str + 4); + do_strtosz("1.0B", 0, 1, 4); /* An empty fraction is tolerated */ - str = "1.k"; - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 1024); - g_assert_true(endptr == str + 3); + do_strtosz("1.k", 0, 1024, 3); /* For convenience, we permit values that are not byte-exact */ - str = "12.345M"; - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, (uint64_t) (12.345 * MiB + 0.5)); - g_assert_true(endptr == str + 7); + do_strtosz("12.345M", 0, (uint64_t) (12.345 * MiB + 0.5), 7); } static void test_qemu_strtosz_invalid(void) { - const char *str; - const char *endptr; - int err; - uint64_t res = 0xbaadf00d; - - str = ""; - endptr = NULL; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - g_assert_true(endptr == str); - - str = " \t "; - endptr = NULL; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - g_assert_true(endptr == str); - - str = "crap"; - endptr = NULL; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - g_assert_true(endptr == str); - - str = "inf"; - endptr = NULL; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - g_assert_true(endptr == str); - - str = "NaN"; - endptr = NULL; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - g_assert_true(endptr == str); + do_strtosz("", -EINVAL, 0xbaadf00d, 0); + do_strtosz(" \t ", -EINVAL, 0xbaadf00d, 0); + do_strtosz("crap", -EINVAL, 0xbaadf00d, 0); + do_strtosz("inf", -EINVAL, 0xbaadf00d, 0); + do_strtosz("NaN", -EINVAL, 0xbaadf00d, 0); /* Fractional values require scale larger than bytes */ - str = "1.1B"; - endptr = NULL; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - g_assert_true(endptr == str); - - str = "1.1"; - endptr = NULL; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - g_assert_true(endptr == str); + do_strtosz("1.1B", -EINVAL, 0xbaadf00d, 0); + do_strtosz("1.1", -EINVAL, 0xbaadf00d, 0); /* No hex fractions */ - str = "0x1.8k"; - endptr = NULL; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - g_assert_true(endptr == str); + do_strtosz("0x1.8k", -EINVAL, 0xbaadf00d, 0); /* No suffixes */ - str = "0x18M"; - endptr = NULL; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - g_assert_true(endptr == str); + do_strtosz("0x18M", -EINVAL, 0xbaadf00d, 0); /* No negative values */ - str = "-0"; - endptr = NULL; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - g_assert_true(endptr == str); - - str = "-1"; - endptr = NULL; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - g_assert_true(endptr == str); + do_strtosz("-0", -EINVAL, 0xbaadf00d, 0); + do_strtosz("-1", -EINVAL, 0xbaadf00d, 0); } static void test_qemu_strtosz_trailing(void) { - const char *str; - const char *endptr; - int err; - uint64_t res; + do_strtosz_full("123xxx", qemu_strtosz_MiB, 0, 123 * MiB, 3, + -EINVAL, 0xbaadf00d); - str = "123xxx"; - endptr = NULL; - res = 0xbaadf00d; - err = qemu_strtosz_MiB(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 123 * MiB); - g_assert_true(endptr == str + 3); - - res = 0xbaadf00d; - err = qemu_strtosz(str, NULL, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - - str = "1kiB"; - endptr = NULL; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 1024); - g_assert_true(endptr == str + 2); - - res = 0xbaadf00d; - err = qemu_strtosz(str, NULL, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - - str = "0x"; - endptr = NULL; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 0); - g_assert_true(endptr == str + 1); - - res = 0xbaadf00d; - err = qemu_strtosz(str, NULL, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - - str = "0.NaN"; - endptr = NULL; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 0); - g_assert_true(endptr == str + 2); - - res = 0xbaadf00d; - err = qemu_strtosz(str, NULL, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); - - str = "123-45"; - endptr = NULL; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 123); - g_assert_true(endptr == str + 3); - - res = 0xbaadf00d; - err = qemu_strtosz(str, NULL, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); + do_strtosz_full("1kiB", qemu_strtosz, 0, 1024, 2, -EINVAL, 0xbaadf00d); + do_strtosz_full("0x", qemu_strtosz, 0, 0, 1, -EINVAL, 0xbaadf00d); + do_strtosz_full("0.NaN", qemu_strtosz, 0, 0, 2, -EINVAL, 0xbaadf00d); + do_strtosz_full("123-45", qemu_strtosz, 0, 123, 3, -EINVAL, 0xbaadf00d); /* FIXME should stop parse after 'e'. No floating point exponents */ - str = "1.5e1k"; - endptr = NULL; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -EINVAL /* FIXME 0 */); - g_assert_cmphex(res, ==, 0xbaadf00d /* FIXME EiB * 1.5 */); - g_assert_true(endptr == str /* FIXME + 4 */); + do_strtosz_full("1.5e1k", qemu_strtosz, -EINVAL /* FIXME 0 */, + 0xbaadf00d /* FIXME EiB * 1.5 */, 0 /* FIXME 4 */, + -EINVAL, 0xbaadf00d); - res = 0xbaadf00d; - err = qemu_strtosz(str, NULL, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 0xbaadf00d); - - str = "1.5E+0k"; - endptr = NULL; - res = 0xbaadf00d; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -EINVAL /* FIXME 0 */); - g_assert_cmphex(res, ==, 0xbaadf00d /* FIXME EiB * 1.5 */); - g_assert_true(endptr == str /* FIXME + 4 */); - - res = 0xbaadf00d; - err = qemu_strtosz(str, NULL, &res); - g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmphex(res, ==, 0xbaadf00d); + do_strtosz_full("1.5E+0k", qemu_strtosz, -EINVAL /* FIXME 0 */, + 0xbaadf00d /* FIXME EiB * 1.5 */, 0 /* FIXME 4 */, + -EINVAL, 0xbaadf00d); } static void test_qemu_strtosz_erange(void) { - const char *str; - const char *endptr; - int err; - uint64_t res = 0xbaadf00d; + /* 2^64; see strtosz_simple for 2^64-1 */ + do_strtosz("18446744073709551616", -ERANGE, 0xbaadf00d, 20); - str = "18446744073709551616"; /* 2^64; see strtosz_simple for 2^64-1 */ - endptr = NULL; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmphex(res, ==, 0xbaadf00d); - g_assert_true(endptr == str + 20); - - str = "20E"; - endptr = NULL; - err = qemu_strtosz(str, &endptr, &res); - g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmphex(res, ==, 0xbaadf00d); - g_assert_true(endptr == str + 3); + do_strtosz("20E", -ERANGE, 0xbaadf00d, 3); } static void test_qemu_strtosz_metric(void) { - const char *str; - int err; - const char *endptr; - uint64_t res; - - str = "12345k"; - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz_metric(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 12345000); - g_assert_true(endptr == str + 6); - - str = "12.345M"; - endptr = str; - res = 0xbaadf00d; - err = qemu_strtosz_metric(str, &endptr, &res); - g_assert_cmpint(err, ==, 0); - g_assert_cmpuint(res, ==, 12345000); - g_assert_true(endptr == str + 7); + do_strtosz_metric("12345k", 0, 12345000, 6); + do_strtosz_metric("12.345M", 0, 12345000, 7); } static void test_freq_to_str(void) From patchwork Fri May 12 02:10:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238634 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id F1C0DC7EE23 for ; Fri, 12 May 2023 02:11:35 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFS-0004ml-VK; Thu, 11 May 2023 22:11:11 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFP-0004lR-U9 for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:07 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIF9-0000Q7-5o for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:07 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857448; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=gnWQxk7uaPyBjtV7rz/3P+R/jSo6CjVEF/x5fuKyeK8=; b=ZtJ3JX/b/Pi3SdlwPW4oRaAlSgpa4FBq12IPrbUTXk3Q9yX+FXZ9GQXpyt/yY85yFes9r1 DR1lF1JL940fYtP3omsRx/2dcMRwJ5O9W7/vGdflYHfOoXJDbkN8LY5GDOxTRK9p/lbgoe PwVhsO5Vi62g9HegPAuXJw5hPLZjPxA= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-612-lJcjhc_YO_6fg9-a9INcMA-1; Thu, 11 May 2023 22:10:45 -0400 X-MC-Unique: lJcjhc_YO_6fg9-a9INcMA-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id D90BE101A54F; Fri, 12 May 2023 02:10:44 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3A9942024CDC; Fri, 12 May 2023 02:10:44 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 12/19] cutils: Allow NULL str in qemu_strtosz Date: Thu, 11 May 2023 21:10:26 -0500 Message-Id: <20230512021033.1378730-13-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org All the other qemu_strto* and parse_uint allow a NULL str. Having qemu_strtosz crash on qemu_strtosz(NULL, NULL, &value) is an easy fix that adds some consistency between our string parsers. Signed-off-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Hanna Czenczek --- tests/unit/test-cutils.c | 3 +++ util/cutils.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 5c9ed78be93..1936c7b5795 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -3260,6 +3260,9 @@ static void test_qemu_strtosz_float(void) static void test_qemu_strtosz_invalid(void) { + do_strtosz(NULL, -EINVAL, 0xbaadf00d, 0); + + /* Must parse at least one digit */ do_strtosz("", -EINVAL, 0xbaadf00d, 0); do_strtosz(" \t ", -EINVAL, 0xbaadf00d, 0); do_strtosz("crap", -EINVAL, 0xbaadf00d, 0); diff --git a/util/cutils.c b/util/cutils.c index e599924a0c4..91c90673aba 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -306,7 +306,7 @@ static int do_strtosz(const char *nptr, const char **end, out: if (end) { *end = endptr; - } else if (*endptr) { + } else if (nptr && *endptr) { retval = -EINVAL; } if (retval == 0) { From patchwork Fri May 12 02:10:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238652 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2B49EC77B7C for ; Fri, 12 May 2023 02:13:46 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFZ-0004pv-25; Thu, 11 May 2023 22:11:17 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFT-0004nW-OX for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:11 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFB-0000QV-4o for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857451; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3xxclizjudtIsbsm0k6hE30L3R9CgF1/7JAe5RXVZHU=; b=jAiAWaE0x4+Hs/RiKSRCmBRZi1TzDrE+3GOCb1BR5AbeY86+bN4so2rWaOaMHzXaKo7day TI+A/37OhxJs+erbYFitGdyK51W7e/qWisA2v9AJ6cwcRb3arN8zrk2wyyClX+j2BLbJYM 8WBBCRaDK0xs/1/Oxv8RfAkqqmbwKe8= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-497-HMuQM0KWNledvZJm1TxFPw-1; Thu, 11 May 2023 22:10:46 -0400 X-MC-Unique: HMuQM0KWNledvZJm1TxFPw-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 5E3C7185A78B; Fri, 12 May 2023 02:10:46 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0FE682024CDC; Fri, 12 May 2023 02:10:44 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org, Eduardo Habkost , Marcel Apfelbaum , =?utf-8?q?Philippe_Mathieu-D?= =?utf-8?q?aud=C3=A9?= , Yanan Wang Subject: [PATCH v2 13/19] numa: Check for qemu_strtosz_MiB error Date: Thu, 11 May 2023 21:10:27 -0500 Message-Id: <20230512021033.1378730-14-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.129.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org As shown in the previous commit, qemu_strtosz_MiB sometimes leaves the result value untouched (we have to audit further to learn that in that case, the QAPI generator says that visit_type_NumaOptions() will have zero-initialized it), and sometimes leaves it with the value of a partial parse before -EINVAL occurs because of trailing garbage. Rather than blindly treating any string the user may throw at us as valid, we should check for parse failures. Fixes: cc001888 ("numa: fixup parsed NumaNodeOptions earlier", v2.11.0) Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek --- hw/core/numa.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/core/numa.c b/hw/core/numa.c index d8d36b16d80..f08956ddb0f 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -531,10 +531,17 @@ static int parse_numa(void *opaque, QemuOpts *opts, Error **errp) /* Fix up legacy suffix-less format */ if ((object->type == NUMA_OPTIONS_TYPE_NODE) && object->u.node.has_mem) { const char *mem_str = qemu_opt_get(opts, "mem"); - qemu_strtosz_MiB(mem_str, NULL, &object->u.node.mem); + int ret = qemu_strtosz_MiB(mem_str, NULL, &object->u.node.mem); + + if (ret < 0) { + error_setg_errno(&err, -ret, "could not parse memory size '%s'", + mem_str); + } } - set_numa_options(ms, object, &err); + if (!err) { + set_numa_options(ms, object, &err); + } qapi_free_NumaOptions(object); if (err) { From patchwork Fri May 12 02:10:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238637 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A7223C7EE22 for ; Fri, 12 May 2023 02:11:45 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFS-0004mf-Tq; Thu, 11 May 2023 22:11:11 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFQ-0004lg-NW for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:08 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIF9-0000QM-IY for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:08 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857450; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=oiCquS9amYZgxXY2U4FZH6nOCpQ2gbUNDDQdkCWMbhg=; b=WjKcBtpO39OImG5v148Tfi3dlgtRJw/pJYkm9XwHpuAeN2UPu1ZuqIPAUOSNoFlF8lRWOC VLssQWJh+B2XjYs2CfxYgGZQ7mH2rEeW5QrORNYfpLhY8WIok9PRVD2VlEt42mNpJ4nuMS SJfv+aoLB2Yj9orLe/JcyjEJ2qGUhzQ= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-115-MKdhgxkXPyefEixcOdNjxw-1; Thu, 11 May 2023 22:10:47 -0400 X-MC-Unique: MKdhgxkXPyefEixcOdNjxw-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id EB3F285A588; Fri, 12 May 2023 02:10:46 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id 87CA82026D16; Fri, 12 May 2023 02:10:46 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 14/19] test-cutils: Add more coverage to qemu_strtosz11; rgb:1e1e/1e1e/1e1e Date: Thu, 11 May 2023 21:10:28 -0500 Message-Id: <20230512021033.1378730-15-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.129.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add some more strings that the user might send our way. In particular, some of these additions include FIXME comments showing where our parser doesn't quite behave the way we want. Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek --- v2: even more tests added, pad a string to avoid out-of-bounds randomness [Hanna] --- tests/unit/test-cutils.c | 147 +++++++++++++++++++++++++++++++++++---- 1 file changed, 135 insertions(+), 12 deletions(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 1936c7b5795..7800caf9b0e 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -3162,7 +3162,12 @@ static void do_strtosz_full(const char *str, qemu_strtosz_fn fn, ret = fn(str, &endptr, &val); g_assert_cmpint(ret, ==, exp_ptr_ret); g_assert_cmpuint(val, ==, exp_ptr_val); - g_assert_true(endptr == str + exp_ptr_offset); + if (str) { + g_assert_true(endptr == str + exp_ptr_offset); + } else { + g_assert_cmpint(exp_ptr_offset, ==, 0); + g_assert_null(endptr); + } val = 0xbaadf00d; ret = fn(str, NULL, &val); @@ -3198,8 +3203,8 @@ static void test_qemu_strtosz_simple(void) /* Leading 0 gives decimal results, not octal */ do_strtosz("08", 0, 8, 2); - /* Leading space is ignored */ - do_strtosz(" 12345", 0, 12345, 6); + /* Leading space and + are ignored */ + do_strtosz(" +12345", 0, 12345, 7); /* 2^53-1 */ do_strtosz("9007199254740991", 0, 0x1fffffffffffffULL, 16); @@ -3226,17 +3231,27 @@ static void test_qemu_strtosz_hex(void) do_strtosz("0xab", 0, 171, 4); - do_strtosz("0xae", 0, 174, 4); + do_strtosz(" +0xae", 0, 174, 6); } static void test_qemu_strtosz_units(void) { - /* default is M */ + /* default scale depends on function */ + do_strtosz("1", 0, 1, 1); do_strtosz_MiB("1", 0, MiB, 1); + do_strtosz_metric("1", 0, 1, 1); + /* Explicit byte suffix works for all functions */ do_strtosz("1B", 0, 1, 2); + do_strtosz_MiB("1B", 0, 1, 2); + do_strtosz_metric("1B", 0, 1, 2); + /* Expose the scale */ do_strtosz("1K", 0, KiB, 2); + do_strtosz_MiB("1K", 0, KiB, 2); + do_strtosz_metric("1K", 0, 1000, 2); + + /* Other suffixes, see also test_qemu_strtosz_metric */ do_strtosz("1M", 0, MiB, 2); do_strtosz("1G", 0, GiB, 2); do_strtosz("1T", 0, TiB, 2); @@ -3248,14 +3263,37 @@ static void test_qemu_strtosz_float(void) { do_strtosz("0.5E", 0, EiB / 2, 4); + /* Implied M suffix okay */ + do_strtosz_MiB("0.5", 0, MiB / 2, 3); + /* For convenience, a fraction of 0 is tolerated even on bytes */ do_strtosz("1.0B", 0, 1, 4); - /* An empty fraction is tolerated */ + /* An empty fraction tail is tolerated */ do_strtosz("1.k", 0, 1024, 3); + /* FIXME An empty fraction head should be tolerated */ + do_strtosz(" .5k", -EINVAL /* FIXME 0 */, 0xbaadf00d /* FIXME 512 */, + 0 /* FIXME 4 */); + /* For convenience, we permit values that are not byte-exact */ do_strtosz("12.345M", 0, (uint64_t) (12.345 * MiB + 0.5), 7); + + /* FIXME Fraction tail should round correctly */ + do_strtosz("1.9999k", 0, 2048, 7); + do_strtosz("1.9999999999999999999999999999999999999999999999999999k", 0, + 1024 /* FIXME 2048 */, 55); + + /* FIXME ERANGE underflow in the fraction tail should not matter for 'k' */ + do_strtosz("1." + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "1k", 0, 1 /* FIXME 1024 */, 354); } static void test_qemu_strtosz_invalid(void) @@ -3265,57 +3303,142 @@ static void test_qemu_strtosz_invalid(void) /* Must parse at least one digit */ do_strtosz("", -EINVAL, 0xbaadf00d, 0); do_strtosz(" \t ", -EINVAL, 0xbaadf00d, 0); - do_strtosz("crap", -EINVAL, 0xbaadf00d, 0); + do_strtosz(".", -EINVAL, 0xbaadf00d, 0); + do_strtosz(" .", -EINVAL, 0xbaadf00d, 0); + do_strtosz(" .k", -EINVAL, 0xbaadf00d, 0); do_strtosz("inf", -EINVAL, 0xbaadf00d, 0); do_strtosz("NaN", -EINVAL, 0xbaadf00d, 0); + /* Lone suffix is not okay */ + do_strtosz("k", -EINVAL, 0xbaadf00d, 0); + do_strtosz(" M", -EINVAL, 0xbaadf00d, 0); + /* Fractional values require scale larger than bytes */ do_strtosz("1.1B", -EINVAL, 0xbaadf00d, 0); do_strtosz("1.1", -EINVAL, 0xbaadf00d, 0); + /* FIXME underflow in the fraction tail should matter for 'B' */ + do_strtosz("1.00001B", -EINVAL, 0xbaadf00d, 0); + do_strtosz("1.00000000000000000001B", 0 /* FIXME -EINVAL */, + 1 /* FIXME 0xbaadf00d */, 23 /* FIXME 0 */); + do_strtosz("1." + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "1B", 0 /* FIXME -EINVAL */, 1 /* FIXME 0xbaadf00d */, + 354 /* FIXME 0 */); + /* No hex fractions */ do_strtosz("0x1.8k", -EINVAL, 0xbaadf00d, 0); + do_strtosz("0x1.k", -EINVAL, 0xbaadf00d, 0); - /* No suffixes */ + /* No hex suffixes */ do_strtosz("0x18M", -EINVAL, 0xbaadf00d, 0); + do_strtosz("0x1p1", -EINVAL, 0xbaadf00d, 0); - /* No negative values */ - do_strtosz("-0", -EINVAL, 0xbaadf00d, 0); - do_strtosz("-1", -EINVAL, 0xbaadf00d, 0); + /* decimal in place of scaling suffix */ + do_strtosz("1.1.k", -EINVAL, 0xbaadf00d, 0); + do_strtosz("1.1.", -EINVAL, 0xbaadf00d, 0); } static void test_qemu_strtosz_trailing(void) { + /* Trailing whitespace */ + do_strtosz_full("1k ", qemu_strtosz, 0, 1024, 2, -EINVAL, 0xbaadf00d); + + /* Unknown suffix overrides even implied scale*/ + do_strtosz_full("123xxx", qemu_strtosz, 0, 123, 3, -EINVAL, 0xbaadf00d); + + /* Implied scale allows partial parse */ do_strtosz_full("123xxx", qemu_strtosz_MiB, 0, 123 * MiB, 3, -EINVAL, 0xbaadf00d); + do_strtosz_full("1.5.k", qemu_strtosz_MiB, 0, 1.5 * MiB, 3, + -EINVAL, 0xbaadf00d); + /* Junk after one-byte suffix */ do_strtosz_full("1kiB", qemu_strtosz, 0, 1024, 2, -EINVAL, 0xbaadf00d); + + /* Incomplete hex is an unknown suffix */ do_strtosz_full("0x", qemu_strtosz, 0, 0, 1, -EINVAL, 0xbaadf00d); + + /* Hex literals use only one leading zero */ + do_strtosz_full("00x1", qemu_strtosz, 0, 0, 2, -EINVAL, 0xbaadf00d); + + /* No support for binary literals; 'b' is valid suffix */ + do_strtosz_full("0b1000", qemu_strtosz, 0, 0, 2, -EINVAL, 0xbaadf00d); + + /* Junk after decimal */ do_strtosz_full("0.NaN", qemu_strtosz, 0, 0, 2, -EINVAL, 0xbaadf00d); + + /* Although negatives are invalid, '-' may be in trailing junk */ do_strtosz_full("123-45", qemu_strtosz, 0, 123, 3, -EINVAL, 0xbaadf00d); + do_strtosz_full(" 123 - 45", qemu_strtosz, 0, 123, 4, -EINVAL, 0xbaadf00d); /* FIXME should stop parse after 'e'. No floating point exponents */ do_strtosz_full("1.5e1k", qemu_strtosz, -EINVAL /* FIXME 0 */, 0xbaadf00d /* FIXME EiB * 1.5 */, 0 /* FIXME 4 */, -EINVAL, 0xbaadf00d); - do_strtosz_full("1.5E+0k", qemu_strtosz, -EINVAL /* FIXME 0 */, 0xbaadf00d /* FIXME EiB * 1.5 */, 0 /* FIXME 4 */, -EINVAL, 0xbaadf00d); + + /* + * FIXME overflow in fraction is so buggy it can read beyond bounds + * if we don't stuff extra \0 in our literal + */ + do_strtosz_full("1.5E999\0\0" /* FIXME 1.5E999" */, qemu_strtosz, + 0, 1 /* FIXME EiB * 1.5 */, 8 /* FIXME 4 */, + 0 /* FIXME -EINVAL */, 1 /* FIXME 0xbaadf00d */); } static void test_qemu_strtosz_erange(void) { + /* FIXME negative values fit better as ERANGE */ + do_strtosz(" -0", -EINVAL /* FIXME -ERANGE */, 0xbaadf00d, 0 /* FIXME 3 */); + do_strtosz("-1", -EINVAL /* FIXME -ERANGE */, 0xbaadf00d, 0 /* FIXME 2 */); + do_strtosz_full("-2M", qemu_strtosz, -EINVAL /* FIXME -ERANGE */, + 0xbaadf00d, 0 /* FIXME 2 */, -EINVAL, 0xbaadf00d); + do_strtosz(" -.0", -EINVAL /* FIXME -ERANGE */, 0xbaadf00d, + 0 /* FIXME 4 */); + do_strtosz_full("-.1k", qemu_strtosz, -EINVAL /* FIXME -ERANGE */, + 0xbaadf00d, 0 /* FIXME 3 */, -EINVAL, 0xbaadf00d); + do_strtosz_full(" -." + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "1M", qemu_strtosz, -EINVAL /* FIXME -ERANGE */, + 0xbaadf00d, 0 /* FIXME 354 */, -EINVAL, 0xbaadf00d); + /* 2^64; see strtosz_simple for 2^64-1 */ do_strtosz("18446744073709551616", -ERANGE, 0xbaadf00d, 20); do_strtosz("20E", -ERANGE, 0xbaadf00d, 3); + + /* FIXME Fraction tail can cause ERANGE overflow */ + do_strtosz("15.9999999999999999999999999999999999999999999999999999E", + 0 /* FIXME -ERANGE */, 15ULL * EiB /* FIXME 0xbaadf00d */, 56); + + /* EINVAL has priority over ERANGE */ + do_strtosz_full("100000Pjunk", qemu_strtosz, -ERANGE, 0xbaadf00d, 7, + -EINVAL, 0xbaadf00d); } static void test_qemu_strtosz_metric(void) { do_strtosz_metric("12345k", 0, 12345000, 6); do_strtosz_metric("12.345M", 0, 12345000, 7); + + /* Fraction is affected by floating-point rounding */ + /* This would be 0xfffffffffffffbff with infinite precision */ + do_strtosz_metric("18.446744073709550591E", 0, 0xfffffffffffffc0cULL, 22); } static void test_freq_to_str(void) From patchwork Fri May 12 02:10:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238644 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 8332DC77B7C for ; Fri, 12 May 2023 02:12:53 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFW-0004nz-GU; Thu, 11 May 2023 22:11:14 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFS-0004mk-Kv for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:10 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFB-0000QR-Um for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:10 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857451; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=eGg02HC5+uCjofumDX4xiUm9ng7yU78GRRc6NhZQPoo=; b=ToMjWWg4/Yf3z/ycuQlnKntMWa5V+1KtuCFx2MyPEeE32eGOVS0C17seVWqPvknMkUXC4I INCi/oDmyE3DKDIrG6n50K7UG8ct7RxtfsMBM4hH/rgNBZwAKnRwgMEfLj8XSII2kj/awQ XePcusDN0hE5YAK3NP8/Z797uz2An9I= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-54-0RDAIRkqP1C2HxFlir5z6g-1; Thu, 11 May 2023 22:10:47 -0400 X-MC-Unique: 0RDAIRkqP1C2HxFlir5z6g-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 85050185A790; Fri, 12 May 2023 02:10:47 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id 229182026D16; Fri, 12 May 2023 02:10:47 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 15/19] cutils: Set value in all qemu_strtosz* error paths Date: Thu, 11 May 2023 21:10:29 -0500 Message-Id: <20230512021033.1378730-16-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Making callers determine whether or not *value was populated on error is not nice for usability. Pre-patch, we have unit tests that check that *result is left unchanged on most EINVAL errors and set to 0 on many ERANGE errors. This is subtly different from libc strtoumax() behavior which returns UINT64_MAX on ERANGE errors, as well as different from our parse_uint() which slams to 0 on EINVAL on the grounds that we want our functions to be harder to mis-use than strtoumax(). Let's audit callers: - hw/core/numa.c:parse_numa() fixed in the previous patch to check for errors - migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(), monitor/hmp.c:monitor_parse_arguments(), qapi/opts-visitor.c:opts_type_size(), qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(), qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(), target/i386/cpu.c:x86_cpu_parse_featurestr(), and util/qemu-option.c:parse_option_size() appear to reject all failures (although some with distinct messages for ERANGE as opposed to EINVAL), so it doesn't matter what is in the value parameter on error. - All remaining callers are in the testsuite, where we can tweak our expectations to match our new desired behavior. Advancing to the end of the string parsed on overflow (ERANGE), while still returning 0, makes sense (UINT64_MAX as a size is unlikely to be useful); likewise, our size parsing code is complex enough that it's easier to always return 0 when endptr is NULL but trailing garbage was found, rather than trying to return the value of the prefix actually parsed (no current caller cared about the value of the prefix). Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek --- v2: cutils.c unchanged, but rebasing test suite is significant enough that I doropped Hanna's R-b --- tests/unit/test-cutils.c | 106 +++++++++++++++++++-------------------- util/cutils.c | 17 +++++-- 2 files changed, 63 insertions(+), 60 deletions(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 7800caf9b0e..4a1baf05ca6 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -3273,7 +3273,7 @@ static void test_qemu_strtosz_float(void) do_strtosz("1.k", 0, 1024, 3); /* FIXME An empty fraction head should be tolerated */ - do_strtosz(" .5k", -EINVAL /* FIXME 0 */, 0xbaadf00d /* FIXME 512 */, + do_strtosz(" .5k", -EINVAL /* FIXME 0 */, 0 /* FIXME 512 */, 0 /* FIXME 4 */); /* For convenience, we permit values that are not byte-exact */ @@ -3298,29 +3298,29 @@ static void test_qemu_strtosz_float(void) static void test_qemu_strtosz_invalid(void) { - do_strtosz(NULL, -EINVAL, 0xbaadf00d, 0); + do_strtosz(NULL, -EINVAL, 0, 0); /* Must parse at least one digit */ - do_strtosz("", -EINVAL, 0xbaadf00d, 0); - do_strtosz(" \t ", -EINVAL, 0xbaadf00d, 0); - do_strtosz(".", -EINVAL, 0xbaadf00d, 0); - do_strtosz(" .", -EINVAL, 0xbaadf00d, 0); - do_strtosz(" .k", -EINVAL, 0xbaadf00d, 0); - do_strtosz("inf", -EINVAL, 0xbaadf00d, 0); - do_strtosz("NaN", -EINVAL, 0xbaadf00d, 0); + do_strtosz("", -EINVAL, 0, 0); + do_strtosz(" \t ", -EINVAL, 0, 0); + do_strtosz(".", -EINVAL, 0, 0); + do_strtosz(" .", -EINVAL, 0, 0); + do_strtosz(" .k", -EINVAL, 0, 0); + do_strtosz("inf", -EINVAL, 0, 0); + do_strtosz("NaN", -EINVAL, 0, 0); /* Lone suffix is not okay */ - do_strtosz("k", -EINVAL, 0xbaadf00d, 0); - do_strtosz(" M", -EINVAL, 0xbaadf00d, 0); + do_strtosz("k", -EINVAL, 0, 0); + do_strtosz(" M", -EINVAL, 0, 0); /* Fractional values require scale larger than bytes */ - do_strtosz("1.1B", -EINVAL, 0xbaadf00d, 0); - do_strtosz("1.1", -EINVAL, 0xbaadf00d, 0); + do_strtosz("1.1B", -EINVAL, 0, 0); + do_strtosz("1.1", -EINVAL, 0, 0); /* FIXME underflow in the fraction tail should matter for 'B' */ - do_strtosz("1.00001B", -EINVAL, 0xbaadf00d, 0); + do_strtosz("1.00001B", -EINVAL, 0, 0); do_strtosz("1.00000000000000000001B", 0 /* FIXME -EINVAL */, - 1 /* FIXME 0xbaadf00d */, 23 /* FIXME 0 */); + 1 /* FIXME 0 */, 23 /* FIXME 0 */); do_strtosz("1." "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" @@ -3329,62 +3329,60 @@ static void test_qemu_strtosz_invalid(void) "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" - "1B", 0 /* FIXME -EINVAL */, 1 /* FIXME 0xbaadf00d */, + "1B", 0 /* FIXME -EINVAL */, 1 /* FIXME 0 */, 354 /* FIXME 0 */); /* No hex fractions */ - do_strtosz("0x1.8k", -EINVAL, 0xbaadf00d, 0); - do_strtosz("0x1.k", -EINVAL, 0xbaadf00d, 0); + do_strtosz("0x1.8k", -EINVAL, 0, 0); + do_strtosz("0x1.k", -EINVAL, 0, 0); /* No hex suffixes */ - do_strtosz("0x18M", -EINVAL, 0xbaadf00d, 0); - do_strtosz("0x1p1", -EINVAL, 0xbaadf00d, 0); + do_strtosz("0x18M", -EINVAL, 0, 0); + do_strtosz("0x1p1", -EINVAL, 0, 0); /* decimal in place of scaling suffix */ - do_strtosz("1.1.k", -EINVAL, 0xbaadf00d, 0); - do_strtosz("1.1.", -EINVAL, 0xbaadf00d, 0); + do_strtosz("1.1.k", -EINVAL, 0, 0); + do_strtosz("1.1.", -EINVAL, 0, 0); } static void test_qemu_strtosz_trailing(void) { /* Trailing whitespace */ - do_strtosz_full("1k ", qemu_strtosz, 0, 1024, 2, -EINVAL, 0xbaadf00d); + do_strtosz_full("1k ", qemu_strtosz, 0, 1024, 2, -EINVAL, 0); /* Unknown suffix overrides even implied scale*/ - do_strtosz_full("123xxx", qemu_strtosz, 0, 123, 3, -EINVAL, 0xbaadf00d); + do_strtosz_full("123xxx", qemu_strtosz, 0, 123, 3, -EINVAL, 0); /* Implied scale allows partial parse */ - do_strtosz_full("123xxx", qemu_strtosz_MiB, 0, 123 * MiB, 3, - -EINVAL, 0xbaadf00d); - do_strtosz_full("1.5.k", qemu_strtosz_MiB, 0, 1.5 * MiB, 3, - -EINVAL, 0xbaadf00d); + do_strtosz_full("123xxx", qemu_strtosz_MiB, 0, 123 * MiB, 3, -EINVAL, 0); + do_strtosz_full("1.5.k", qemu_strtosz_MiB, 0, 1.5 * MiB, 3, -EINVAL, 0); /* Junk after one-byte suffix */ - do_strtosz_full("1kiB", qemu_strtosz, 0, 1024, 2, -EINVAL, 0xbaadf00d); + do_strtosz_full("1kiB", qemu_strtosz, 0, 1024, 2, -EINVAL, 0); /* Incomplete hex is an unknown suffix */ - do_strtosz_full("0x", qemu_strtosz, 0, 0, 1, -EINVAL, 0xbaadf00d); + do_strtosz_full("0x", qemu_strtosz, 0, 0, 1, -EINVAL, 0); /* Hex literals use only one leading zero */ - do_strtosz_full("00x1", qemu_strtosz, 0, 0, 2, -EINVAL, 0xbaadf00d); + do_strtosz_full("00x1", qemu_strtosz, 0, 0, 2, -EINVAL, 0); /* No support for binary literals; 'b' is valid suffix */ - do_strtosz_full("0b1000", qemu_strtosz, 0, 0, 2, -EINVAL, 0xbaadf00d); + do_strtosz_full("0b1000", qemu_strtosz, 0, 0, 2, -EINVAL, 0); /* Junk after decimal */ - do_strtosz_full("0.NaN", qemu_strtosz, 0, 0, 2, -EINVAL, 0xbaadf00d); + do_strtosz_full("0.NaN", qemu_strtosz, 0, 0, 2, -EINVAL, 0); /* Although negatives are invalid, '-' may be in trailing junk */ - do_strtosz_full("123-45", qemu_strtosz, 0, 123, 3, -EINVAL, 0xbaadf00d); - do_strtosz_full(" 123 - 45", qemu_strtosz, 0, 123, 4, -EINVAL, 0xbaadf00d); + do_strtosz_full("123-45", qemu_strtosz, 0, 123, 3, -EINVAL, 0); + do_strtosz_full(" 123 - 45", qemu_strtosz, 0, 123, 4, -EINVAL, 0); /* FIXME should stop parse after 'e'. No floating point exponents */ do_strtosz_full("1.5e1k", qemu_strtosz, -EINVAL /* FIXME 0 */, - 0xbaadf00d /* FIXME EiB * 1.5 */, 0 /* FIXME 4 */, - -EINVAL, 0xbaadf00d); + 0 /* FIXME EiB * 1.5 */, 0 /* FIXME 4 */, + -EINVAL, 0); do_strtosz_full("1.5E+0k", qemu_strtosz, -EINVAL /* FIXME 0 */, - 0xbaadf00d /* FIXME EiB * 1.5 */, 0 /* FIXME 4 */, - -EINVAL, 0xbaadf00d); + 0 /* FIXME EiB * 1.5 */, 0 /* FIXME 4 */, + -EINVAL, 0); /* * FIXME overflow in fraction is so buggy it can read beyond bounds @@ -3392,20 +3390,19 @@ static void test_qemu_strtosz_trailing(void) */ do_strtosz_full("1.5E999\0\0" /* FIXME 1.5E999" */, qemu_strtosz, 0, 1 /* FIXME EiB * 1.5 */, 8 /* FIXME 4 */, - 0 /* FIXME -EINVAL */, 1 /* FIXME 0xbaadf00d */); + 0 /* FIXME -EINVAL */, 1 /* FIXME 0 */); } static void test_qemu_strtosz_erange(void) { /* FIXME negative values fit better as ERANGE */ - do_strtosz(" -0", -EINVAL /* FIXME -ERANGE */, 0xbaadf00d, 0 /* FIXME 3 */); - do_strtosz("-1", -EINVAL /* FIXME -ERANGE */, 0xbaadf00d, 0 /* FIXME 2 */); - do_strtosz_full("-2M", qemu_strtosz, -EINVAL /* FIXME -ERANGE */, - 0xbaadf00d, 0 /* FIXME 2 */, -EINVAL, 0xbaadf00d); - do_strtosz(" -.0", -EINVAL /* FIXME -ERANGE */, 0xbaadf00d, - 0 /* FIXME 4 */); - do_strtosz_full("-.1k", qemu_strtosz, -EINVAL /* FIXME -ERANGE */, - 0xbaadf00d, 0 /* FIXME 3 */, -EINVAL, 0xbaadf00d); + do_strtosz(" -0", -EINVAL /* FIXME -ERANGE */, 0, 0 /* FIXME 3 */); + do_strtosz("-1", -EINVAL /* FIXME -ERANGE */, 0, 0 /* FIXME 2 */); + do_strtosz_full("-2M", qemu_strtosz, -EINVAL /* FIXME -ERANGE */, 0, + 0 /* FIXME 2 */, -EINVAL, 0); + do_strtosz(" -.0", -EINVAL /* FIXME -ERANGE */, 0, 0 /* FIXME 4 */); + do_strtosz_full("-.1k", qemu_strtosz, -EINVAL /* FIXME -ERANGE */, 0, + 0 /* FIXME 3 */, -EINVAL, 0); do_strtosz_full(" -." "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" @@ -3414,21 +3411,20 @@ static void test_qemu_strtosz_erange(void) "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" - "1M", qemu_strtosz, -EINVAL /* FIXME -ERANGE */, - 0xbaadf00d, 0 /* FIXME 354 */, -EINVAL, 0xbaadf00d); + "1M", qemu_strtosz, -EINVAL /* FIXME -ERANGE */, 0, + 0 /* FIXME 354 */, -EINVAL, 0); /* 2^64; see strtosz_simple for 2^64-1 */ - do_strtosz("18446744073709551616", -ERANGE, 0xbaadf00d, 20); + do_strtosz("18446744073709551616", -ERANGE, 0, 20); - do_strtosz("20E", -ERANGE, 0xbaadf00d, 3); + do_strtosz("20E", -ERANGE, 0, 3); /* FIXME Fraction tail can cause ERANGE overflow */ do_strtosz("15.9999999999999999999999999999999999999999999999999999E", - 0 /* FIXME -ERANGE */, 15ULL * EiB /* FIXME 0xbaadf00d */, 56); + 0 /* FIXME -ERANGE */, 15ULL * EiB /* FIXME 0 */, 56); /* EINVAL has priority over ERANGE */ - do_strtosz_full("100000Pjunk", qemu_strtosz, -ERANGE, 0xbaadf00d, 7, - -EINVAL, 0xbaadf00d); + do_strtosz_full("100000Pjunk", qemu_strtosz, -ERANGE, 0, 7, -EINVAL, 0); } static void test_qemu_strtosz_metric(void) diff --git a/util/cutils.c b/util/cutils.c index 91c90673aba..24955d3ca94 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -205,13 +205,15 @@ static int64_t suffix_mul(char suffix, int64_t unit) * * The end pointer will be returned in *end, if not NULL. If there is * no fraction, the input can be decimal or hexadecimal; if there is a - * fraction, then the input must be decimal and there must be a suffix - * (possibly by @default_suffix) larger than Byte, and the fractional - * portion may suffer from precision loss or rounding. The input must - * be positive. + * non-zero fraction, then the input must be decimal and there must be + * a suffix (possibly by @default_suffix) larger than Byte, and the + * fractional portion may suffer from precision loss or rounding. The + * input must be positive. * * Return -ERANGE on overflow (with *@end advanced), and -EINVAL on - * other error (with *@end left unchanged). + * other error (with *@end at @nptr). Unlike strtoull, *@result is + * set to 0 on all errors, as returning UINT64_MAX on overflow is less + * likely to be usable as a size. */ static int do_strtosz(const char *nptr, const char **end, const char default_suffix, int64_t unit, @@ -311,6 +313,11 @@ out: } if (retval == 0) { *result = val; + } else { + *result = 0; + if (end && retval == -EINVAL) { + *end = nptr; + } } return retval; From patchwork Fri May 12 02:10:30 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238643 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 18F73C7EE22 for ; Fri, 12 May 2023 02:12:53 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFT-0004nU-Nj; Thu, 11 May 2023 22:11:11 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFQ-0004li-No for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:08 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIF9-0000QD-Ki for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:08 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857449; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Kdoj0V5KACWQSN+P7cT+mO2dib1yAMZJ1tRmr1YdFSQ=; b=bCBPuIvV1d8Jt+s5W1LN3HhrLpcVJF6iVyTeWj0vQxgMg1TOLIh9ihlesTiusQcNOo7lZn ej334EYPdn4oPClA1+mQph7MVzwpUWkDopB3ADT2KtCqxn2KmwIbhlckAgyosPsiLZTp9Y Qt3R/nWCycgVx76iWuGx/ZjPBA/HvhI= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-656-KaZObZpxMuWOfg3Kauxg5A-1; Thu, 11 May 2023 22:10:48 -0400 X-MC-Unique: KaZObZpxMuWOfg3Kauxg5A-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 20DD4185A78B; Fri, 12 May 2023 02:10:48 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id B2C312026D16; Fri, 12 May 2023 02:10:47 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 16/19] cutils: Set value in all integral qemu_strto* error paths Date: Thu, 11 May 2023 21:10:30 -0500 Message-Id: <20230512021033.1378730-17-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Our goal in writing qemu_strtoi() and friends is to have an interface harder to abuse than libc's strtol(). Leaving the return value uninitialized on some but not all error paths does not lend itself well to this goal; and our documentation wasn't helpful on what to expect. Note that the previous patch changed all qemu_strtosz() EINVAL error paths to slam value to 0 rather than stay uninitialized, even when the EINVAL eror occurs because of trailing junk. But for the remaining integral qemu_strto*, it's easier to return the parsed value than to force things back to zero, in part because of how check_strtox_error works; in part because people expect that from libc strto* (while there is no libc strtosz to compare to), and in part because doing so creates less churn in the testsuite. Here, the list of affected callers is much longer ('git grep "qemu_strto[ui]" *.c **/*.c | grep -v tests/ |wc -l' outputs 87, although a few of those are the implementation in in cutils.c), so touching as little as possible is the wisest course of action. Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek --- v2: commit message tweaked, but code unchanged, so R-b applied --- tests/unit/test-cutils.c | 24 +++++++++++------------ util/cutils.c | 42 +++++++++++++++++++++++++--------------- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 4a1baf05ca6..1272638582a 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -310,7 +310,7 @@ static void test_qemu_strtoi_null(void) err = qemu_strtoi(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 999); + g_assert_cmpint(res, ==, 0); g_assert_null(endptr); } @@ -610,7 +610,7 @@ static void test_qemu_strtoi_full_null(void) err = qemu_strtoi(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 999); + g_assert_cmpint(res, ==, 0); g_assert_null(endptr); } @@ -713,7 +713,7 @@ static void test_qemu_strtoui_null(void) err = qemu_strtoui(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpuint(res, ==, 999); + g_assert_cmpuint(res, ==, 0); g_assert_null(endptr); } @@ -1011,7 +1011,7 @@ static void test_qemu_strtoui_full_null(void) err = qemu_strtoui(NULL, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpuint(res, ==, 999); + g_assert_cmpuint(res, ==, 0); } static void test_qemu_strtoui_full_empty(void) @@ -1111,7 +1111,7 @@ static void test_qemu_strtol_null(void) err = qemu_strtol(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 999); + g_assert_cmpint(res, ==, 0); g_assert_null(endptr); } @@ -1415,7 +1415,7 @@ static void test_qemu_strtol_full_null(void) err = qemu_strtol(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 999); + g_assert_cmpint(res, ==, 0); g_assert_null(endptr); } @@ -1518,7 +1518,7 @@ static void test_qemu_strtoul_null(void) err = qemu_strtoul(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpuint(res, ==, 999); + g_assert_cmpuint(res, ==, 0); g_assert_null(endptr); } @@ -1811,7 +1811,7 @@ static void test_qemu_strtoul_full_null(void) err = qemu_strtoul(NULL, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpuint(res, ==, 999); + g_assert_cmpuint(res, ==, 0); } static void test_qemu_strtoul_full_empty(void) @@ -1911,7 +1911,7 @@ static void test_qemu_strtoi64_null(void) err = qemu_strtoi64(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 999); + g_assert_cmpint(res, ==, 0); g_assert_null(endptr); } @@ -2201,7 +2201,7 @@ static void test_qemu_strtoi64_full_null(void) err = qemu_strtoi64(NULL, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpint(res, ==, 999); + g_assert_cmpint(res, ==, 0); } static void test_qemu_strtoi64_full_empty(void) @@ -2304,7 +2304,7 @@ static void test_qemu_strtou64_null(void) err = qemu_strtou64(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpuint(res, ==, 999); + g_assert_cmpuint(res, ==, 0); g_assert_null(endptr); } @@ -2593,7 +2593,7 @@ static void test_qemu_strtou64_full_null(void) err = qemu_strtou64(NULL, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpuint(res, ==, 999); + g_assert_cmpuint(res, ==, 0); } static void test_qemu_strtou64_full_empty(void) diff --git a/util/cutils.c b/util/cutils.c index 24955d3ca94..b5a6641fa0f 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -384,12 +384,13 @@ static int check_strtox_error(const char *nptr, char *ep, * * @nptr may be null, and no conversion is performed then. * - * If no conversion is performed, store @nptr in *@endptr and return - * -EINVAL. + * If no conversion is performed, store @nptr in *@endptr, 0 in + * @result, and return -EINVAL. * * If @endptr is null, and the string isn't fully converted, return - * -EINVAL. This is the case when the pointer that would be stored in - * a non-null @endptr points to a character other than '\0'. + * -EINVAL with @result set to the parsed value. This is the case + * when the pointer that would be stored in a non-null @endptr points + * to a character other than '\0'. * * If the conversion overflows @result, store INT_MAX in @result, * and return -ERANGE. @@ -407,6 +408,7 @@ int qemu_strtoi(const char *nptr, const char **endptr, int base, assert((unsigned) base <= 36 && base != 1); if (!nptr) { + *result = 0; if (endptr) { *endptr = nptr; } @@ -436,12 +438,13 @@ int qemu_strtoi(const char *nptr, const char **endptr, int base, * * @nptr may be null, and no conversion is performed then. * - * If no conversion is performed, store @nptr in *@endptr and return - * -EINVAL. + * If no conversion is performed, store @nptr in *@endptr, 0 in + * @result, and return -EINVAL. * * If @endptr is null, and the string isn't fully converted, return - * -EINVAL. This is the case when the pointer that would be stored in - * a non-null @endptr points to a character other than '\0'. + * -EINVAL with @result set to the parsed value. This is the case + * when the pointer that would be stored in a non-null @endptr points + * to a character other than '\0'. * * If the conversion overflows @result, store UINT_MAX in @result, * and return -ERANGE. @@ -460,6 +463,7 @@ int qemu_strtoui(const char *nptr, const char **endptr, int base, assert((unsigned) base <= 36 && base != 1); if (!nptr) { + *result = 0; if (endptr) { *endptr = nptr; } @@ -501,12 +505,13 @@ int qemu_strtoui(const char *nptr, const char **endptr, int base, * * @nptr may be null, and no conversion is performed then. * - * If no conversion is performed, store @nptr in *@endptr and return - * -EINVAL. + * If no conversion is performed, store @nptr in *@endptr, 0 in + * @result, and return -EINVAL. * * If @endptr is null, and the string isn't fully converted, return - * -EINVAL. This is the case when the pointer that would be stored in - * a non-null @endptr points to a character other than '\0'. + * -EINVAL with @result set to the parsed value. This is the case + * when the pointer that would be stored in a non-null @endptr points + * to a character other than '\0'. * * If the conversion overflows @result, store LONG_MAX in @result, * and return -ERANGE. @@ -523,6 +528,7 @@ int qemu_strtol(const char *nptr, const char **endptr, int base, assert((unsigned) base <= 36 && base != 1); if (!nptr) { + *result = 0; if (endptr) { *endptr = nptr; } @@ -543,12 +549,13 @@ int qemu_strtol(const char *nptr, const char **endptr, int base, * * @nptr may be null, and no conversion is performed then. * - * If no conversion is performed, store @nptr in *@endptr and return - * -EINVAL. + * If no conversion is performed, store @nptr in *@endptr, 0 in + * @result, and return -EINVAL. * * If @endptr is null, and the string isn't fully converted, return - * -EINVAL. This is the case when the pointer that would be stored in - * a non-null @endptr points to a character other than '\0'. + * -EINVAL with @result set to the parsed value. This is the case + * when the pointer that would be stored in a non-null @endptr points + * to a character other than '\0'. * * If the conversion overflows @result, store ULONG_MAX in @result, * and return -ERANGE. @@ -566,6 +573,7 @@ int qemu_strtoul(const char *nptr, const char **endptr, int base, assert((unsigned) base <= 36 && base != 1); if (!nptr) { + *result = 0; if (endptr) { *endptr = nptr; } @@ -594,6 +602,7 @@ int qemu_strtoi64(const char *nptr, const char **endptr, int base, assert((unsigned) base <= 36 && base != 1); if (!nptr) { + *result = 0; if (endptr) { *endptr = nptr; } @@ -621,6 +630,7 @@ int qemu_strtou64(const char *nptr, const char **endptr, int base, assert((unsigned) base <= 36 && base != 1); if (!nptr) { + *result = 0; if (endptr) { *endptr = nptr; } From patchwork Fri May 12 02:10:31 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238651 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 8A986C7EE22 for ; Fri, 12 May 2023 02:13:37 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFX-0004ql-F6; Thu, 11 May 2023 22:11:15 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFW-0004oh-I9 for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:14 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFF-0000Qh-Iv for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:13 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857452; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=TZCwzc/82AeqgxSVwgQBV/R0GPQa6yEbzAKl8JvPOjg=; b=UJGg6Y0bKsRWs+kCEIT4XuHmEGr2bgxT9R2vUVfqhO2k3gaf+MtO1kQoPY/wN7QwkWPNFd s5b8PW15Rmc+cJEj61oOy3xuw9UYj+vo/zcpXSiAfc+8DlIzc3pP9ARWl52R04gu2kQ0Ae 13HS4Jjv0yBiXhb1i3C6zwHXSY4WKoQ= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-311-0_y6Ll6dNFeUlGkKAunz3A-1; Thu, 11 May 2023 22:10:49 -0400 X-MC-Unique: 0_y6Ll6dNFeUlGkKAunz3A-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id B0A1A3C10246; Fri, 12 May 2023 02:10:48 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4D7EC2026D16; Fri, 12 May 2023 02:10:48 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 17/19] cutils: Use parse_uint in qemu_strtosz for negative rejection Date: Thu, 11 May 2023 21:10:31 -0500 Message-Id: <20230512021033.1378730-18-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.129.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Rather than open-coding two different ways to check for an unwanted negative sign, reuse the same code in both functions. That way, if we decide down the road to accept "-0" instead of rejecting it, we have fewer places to change. Also, it means we now get ERANGE instead of EINVAL for negative values in qemu_strtosz, which is reasonable for what it represents. Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek --- tests/unit/test-cutils.c | 7 +++---- util/cutils.c | 8 ++------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 1272638582a..b8ad4d7fbac 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -3396,10 +3396,9 @@ static void test_qemu_strtosz_trailing(void) static void test_qemu_strtosz_erange(void) { /* FIXME negative values fit better as ERANGE */ - do_strtosz(" -0", -EINVAL /* FIXME -ERANGE */, 0, 0 /* FIXME 3 */); - do_strtosz("-1", -EINVAL /* FIXME -ERANGE */, 0, 0 /* FIXME 2 */); - do_strtosz_full("-2M", qemu_strtosz, -EINVAL /* FIXME -ERANGE */, 0, - 0 /* FIXME 2 */, -EINVAL, 0); + do_strtosz(" -0", -ERANGE, 0, 3); + do_strtosz("-1", -ERANGE, 0, 2); + do_strtosz_full("-2M", qemu_strtosz, -ERANGE, 0, 2, -EINVAL, 0); do_strtosz(" -.0", -EINVAL /* FIXME -ERANGE */, 0, 0 /* FIXME 4 */); do_strtosz_full("-.1k", qemu_strtosz, -EINVAL /* FIXME -ERANGE */, 0, 0 /* FIXME 3 */, -EINVAL, 0); diff --git a/util/cutils.c b/util/cutils.c index b5a6641fa0f..550abbe5c06 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -201,6 +201,7 @@ static int64_t suffix_mul(char suffix, int64_t unit) * - hex with scaling suffix, such as 0x20M * - octal, such as 08 * - fractional hex, such as 0x1.8 + * - negative values, including -0 * - floating point exponents, such as 1e3 * * The end pointer will be returned in *end, if not NULL. If there is @@ -226,15 +227,10 @@ static int do_strtosz(const char *nptr, const char **end, int64_t mul; /* Parse integral portion as decimal. */ - retval = qemu_strtou64(nptr, &endptr, 10, &val); + retval = parse_uint(nptr, &endptr, 10, &val); if (retval) { goto out; } - if (memchr(nptr, '-', endptr - nptr) != NULL) { - endptr = nptr; - retval = -EINVAL; - goto out; - } if (val == 0 && (*endptr == 'x' || *endptr == 'X')) { /* Input looks like hex; reparse, and insist on no fraction or suffix. */ retval = qemu_strtou64(nptr, &endptr, 16, &val); From patchwork Fri May 12 02:10:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238645 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 34A3EC77B7C for ; Fri, 12 May 2023 02:13:00 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFW-0004om-NK; Thu, 11 May 2023 22:11:14 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFU-0004nt-AA for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:12 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFD-0000Qk-5l for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:12 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857453; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=aLFwfuytnGOJ7sYbsdUeziOHz8BkjoY6NmR4AYAaF54=; b=VHEbVR+ilE9zAYQFtkGtEdQp/uh1y1ZTIFmG5Nmk0zzTowZOmjpdpa+xgS54vvQvgWpRn9 6s0UAs2hMNnF8f6NqIgdoZ+FbbZzJun+Nje38141uIa6z9oFXOXVAEQxHYNKxhanpexao5 ykInOEKu6tvh+xzQPtMTjeGPk4JYN/s= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-122-rIS-dXu6MESTM4-hyv7lcA-1; Thu, 11 May 2023 22:10:49 -0400 X-MC-Unique: rIS-dXu6MESTM4-hyv7lcA-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 4D245871CA1; Fri, 12 May 2023 02:10:49 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id DDF372026DFD; Fri, 12 May 2023 02:10:48 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 18/19] cutils: Improve qemu_strtod* error paths Date: Thu, 11 May 2023 21:10:32 -0500 Message-Id: <20230512021033.1378730-19-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Previous patches changed all integral qemu_strto*() error paths to guarantee that *value is never left uninitialized. Do likewise for qemu_strtod. Also, tighten qemu_strtod_finite() to never return a non-finite value (prior to this patch, we were rejecting "inf" with -EINVAL and unspecified result 0.0, but failing "9e999" with -ERANGE and HUGE_VAL - which is infinite on IEEE machines - despite our function claiming to recognize only finite values). Auditing callers, we have no external callers of qemu_strtod, and among the callers of qemu_strtod_finite: - qapi/qobject-input-visitor.c:qobject_input_type_number_keyval() and qapi/string-input-visitor.c:parse_type_number() which reject all errors (does not matter what we store) - utils/cutils.c:do_strtosz() incorrectly assumes that *endptr points to '.' on all failures (that is, it is not distinguishing between EINVAL and ERANGE; and therefore still does the WRONG THING for "9.9e999". The change here does not entirely fix that (a later patch will tackle this more systematically), but at least the value of endptr is now less likely to be out of bounds on overflow - our testsuite, which we can update to match what we document Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek --- v2: no change to cutils.c; commit message tweaks and testsuite rebase were minor enough to keep R-b --- tests/unit/test-cutils.c | 63 +++++++++++++++++++++++----------------- util/cutils.c | 32 +++++++++++--------- 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index b8ad4d7fbac..8f2dd335f13 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -2747,7 +2747,8 @@ static void test_qemu_strtod_einval(void) res = 999; err = qemu_strtod(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpfloat(res, ==, 999.0); + g_assert_cmpfloat(res, ==, 0.0); + g_assert_false(signbit(res)); g_assert_null(endptr); /* not recognizable */ @@ -2979,7 +2980,8 @@ static void test_qemu_strtod_finite_einval(void) res = 999; err = qemu_strtod_finite(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpfloat(res, ==, 999.0); + g_assert_cmpfloat(res, ==, 0.0); + g_assert_false(signbit(res)); g_assert_true(endptr == str); /* NULL */ @@ -2988,7 +2990,8 @@ static void test_qemu_strtod_finite_einval(void) res = 999; err = qemu_strtod_finite(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpfloat(res, ==, 999.0); + g_assert_cmpfloat(res, ==, 0.0); + g_assert_false(signbit(res)); g_assert_null(endptr); /* not recognizable */ @@ -2997,7 +3000,8 @@ static void test_qemu_strtod_finite_einval(void) res = 999; err = qemu_strtod_finite(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpfloat(res, ==, 999.0); + g_assert_cmpfloat(res, ==, 0.0); + g_assert_false(signbit(res)); g_assert_true(endptr == str); } @@ -3008,24 +3012,26 @@ static void test_qemu_strtod_finite_erange(void) int err; double res; - /* overflow */ + /* overflow turns into EINVAL */ str = "9e999"; endptr = "somewhere"; res = 999; err = qemu_strtod_finite(str, &endptr, &res); - g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmpfloat(res, ==, HUGE_VAL); - g_assert_true(endptr == str + 5); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 0.0); + g_assert_false(signbit(res)); + g_assert_true(endptr == str); str = "-9e+999"; endptr = "somewhere"; res = 999; err = qemu_strtod_finite(str, &endptr, &res); - g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmpfloat(res, ==, -HUGE_VAL); - g_assert_true(endptr == str + 7); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpfloat(res, ==, 0.0); + g_assert_false(signbit(res)); + g_assert_true(endptr == str); - /* underflow */ + /* underflow is still possible */ str = "-9e-999"; endptr = "somewhere"; res = 999; @@ -3050,7 +3056,8 @@ static void test_qemu_strtod_finite_nonfinite(void) res = 999; err = qemu_strtod_finite(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpfloat(res, ==, 999.0); + g_assert_cmpfloat(res, ==, 0.0); + g_assert_false(signbit(res)); g_assert_true(endptr == str); str = "-infinity"; @@ -3058,7 +3065,8 @@ static void test_qemu_strtod_finite_nonfinite(void) res = 999; err = qemu_strtod_finite(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpfloat(res, ==, 999.0); + g_assert_cmpfloat(res, ==, 0.0); + g_assert_false(signbit(res)); g_assert_true(endptr == str); /* not a number */ @@ -3067,7 +3075,8 @@ static void test_qemu_strtod_finite_nonfinite(void) res = 999; err = qemu_strtod_finite(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpfloat(res, ==, 999.0); + g_assert_cmpfloat(res, ==, 0.0); + g_assert_false(signbit(res)); g_assert_true(endptr == str); } @@ -3091,7 +3100,8 @@ static void test_qemu_strtod_finite_trailing(void) res = 999; err = qemu_strtod_finite(str, NULL, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpfloat(res, ==, 999.0); + g_assert_cmpfloat(res, ==, 1.0); + g_assert_false(signbit(res)); /* trailing e is not an exponent */ str = ".5e"; @@ -3106,7 +3116,7 @@ static void test_qemu_strtod_finite_trailing(void) res = 999; err = qemu_strtod_finite(str, NULL, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpfloat(res, ==, 999.0); + g_assert_cmpfloat(res, ==, 0.5); /* trailing ( not part of long NaN */ str = "nan("; @@ -3114,14 +3124,16 @@ static void test_qemu_strtod_finite_trailing(void) res = 999; err = qemu_strtod_finite(str, &endptr, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpfloat(res, ==, 999.0); + g_assert_cmpfloat(res, ==, 0.0); + g_assert_false(signbit(res)); g_assert_true(endptr == str); endptr = "somewhere"; res = 999; err = qemu_strtod_finite(str, NULL, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpfloat(res, ==, 999.0); + g_assert_cmpfloat(res, ==, 0.0); + g_assert_false(signbit(res)); } static void test_qemu_strtod_finite_erange_junk(void) @@ -3146,7 +3158,8 @@ static void test_qemu_strtod_finite_erange_junk(void) res = 999; err = qemu_strtod_finite(str, NULL, &res); g_assert_cmpint(err, ==, -EINVAL); - g_assert_cmpfloat(res, ==, 999.0); + g_assert_cmpfloat(res, ==, 0.0); + g_assert_false(signbit(res)); } typedef int (*qemu_strtosz_fn)(const char *, const char **, uint64_t *); @@ -3384,13 +3397,9 @@ static void test_qemu_strtosz_trailing(void) 0 /* FIXME EiB * 1.5 */, 0 /* FIXME 4 */, -EINVAL, 0); - /* - * FIXME overflow in fraction is so buggy it can read beyond bounds - * if we don't stuff extra \0 in our literal - */ - do_strtosz_full("1.5E999\0\0" /* FIXME 1.5E999" */, qemu_strtosz, - 0, 1 /* FIXME EiB * 1.5 */, 8 /* FIXME 4 */, - 0 /* FIXME -EINVAL */, 1 /* FIXME 0 */); + /* FIXME overflow in fraction is still buggy */ + do_strtosz_full("1.5E999", qemu_strtosz, 0, 1 /* FIXME EiB * 1.5 */, + 2 /* FIXME 4 */, -EINVAL, 0); } static void test_qemu_strtosz_erange(void) diff --git a/util/cutils.c b/util/cutils.c index 550abbe5c06..25c95b0933e 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -653,12 +653,13 @@ int qemu_strtou64(const char *nptr, const char **endptr, int base, * * @nptr may be null, and no conversion is performed then. * - * If no conversion is performed, store @nptr in *@endptr and return - * -EINVAL. + * If no conversion is performed, store @nptr in *@endptr, +0.0 in + * @result, and return -EINVAL. * * If @endptr is null, and the string isn't fully converted, return - * -EINVAL. This is the case when the pointer that would be stored in - * a non-null @endptr points to a character other than '\0'. + * -EINVAL with @result set to the parsed value. This is the case + * when the pointer that would be stored in a non-null @endptr points + * to a character other than '\0'. * * If the conversion overflows, store +/-HUGE_VAL in @result, depending * on the sign, and return -ERANGE. @@ -673,6 +674,7 @@ int qemu_strtod(const char *nptr, const char **endptr, double *result) char *ep; if (!nptr) { + *result = 0.0; if (endptr) { *endptr = nptr; } @@ -687,24 +689,28 @@ int qemu_strtod(const char *nptr, const char **endptr, double *result) /** * Convert string @nptr to a finite double. * - * Works like qemu_strtod(), except that "NaN" and "inf" are rejected - * with -EINVAL and no conversion is performed. + * Works like qemu_strtod(), except that "NaN", "inf", and strings + * that cause ERANGE overflow errors are rejected with -EINVAL as if + * no conversion is performed, storing 0.0 into @result regardless of + * any sign. -ERANGE failures for underflow still preserve the parsed + * sign. */ int qemu_strtod_finite(const char *nptr, const char **endptr, double *result) { - double tmp; + const char *tmp; int ret; - ret = qemu_strtod(nptr, endptr, &tmp); - if (!ret && !isfinite(tmp)) { + ret = qemu_strtod(nptr, &tmp, result); + if (!isfinite(*result)) { if (endptr) { *endptr = nptr; } + *result = 0.0; + ret = -EINVAL; + } else if (endptr) { + *endptr = tmp; + } else if (*tmp) { ret = -EINVAL; - } - - if (ret != -EINVAL) { - *result = tmp; } return ret; } From patchwork Fri May 12 02:10:33 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 13238650 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 61B53C77B7C for ; Fri, 12 May 2023 02:13:23 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pxIFZ-0004rJ-T7; Thu, 11 May 2023 22:11:17 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFW-0004p4-Ph for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:14 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pxIFF-0000Qd-4K for qemu-devel@nongnu.org; Thu, 11 May 2023 22:11:14 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683857451; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=AKFOfNNi9BdkRp7/+X9Cab6BuRiu5XuzIp3gc5roTWI=; b=ISURy9eSOPmEZuRfi00lfCWgQBb9c+/FS4EenlVQBRGKV/Mvb6IbXSJuMjUtFNI3I070oA SF5TaTvBYYAtWAFGLiOB02zByQp9xGd1yW91VqQ7MCyqTDvK5gjF05JFLEXbU3qWnDtce4 ONjGJdIrPjn4mywHmXRsp8auGYq8sBg= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-668-46IOOHTJNfCqpzLAXZrz7A-1; Thu, 11 May 2023 22:10:50 -0400 X-MC-Unique: 46IOOHTJNfCqpzLAXZrz7A-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id E2E6885A588; Fri, 12 May 2023 02:10:49 +0000 (UTC) Received: from green.redhat.com (unknown [10.2.16.49]) by smtp.corp.redhat.com (Postfix) with ESMTP id 812EC2027043; Fri, 12 May 2023 02:10:49 +0000 (UTC) From: Eric Blake To: qemu-devel@nongnu.org Cc: hreitz@redhat.com, armbru@redhat.com, richard.henderson@linaro.org Subject: [PATCH v2 19/19] cutils: Improve qemu_strtosz handling of fractions Date: Thu, 11 May 2023 21:10:33 -0500 Message-Id: <20230512021033.1378730-20-eblake@redhat.com> In-Reply-To: <20230512021033.1378730-1-eblake@redhat.com> References: <20230512021033.1378730-1-eblake@redhat.com> MIME-Version: 1.0 Content-type: text/plain X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 Received-SPF: pass client-ip=170.10.133.124; envelope-from=eblake@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org We have several limitations and bugs worth fixing; they are inter-related enough that it is not worth splitting this patch into smaller pieces: * ".5k" should work to specify 512, just as "0.5k" does * "1.9999k" and "1." + "9"*50 + "k" should both produce the same result of 2048 after rounding * "1." + "0"*350 + "1B" should not be treated the same as "1.0B"; underflow in the fraction should not be lost * "7.99e99" and "7.99e999" look similar, but our code was doing a read-out-of-bounds on the latter because it was not expecting ERANGE due to overflow. While we document that scientific notation is not supported, and the previous patch actually fixed qemu_strtod_finite() to no longer return ERANGE overflows, it is easier to pre-filter than to try and determine after the fact if strtod() consumed more than we wanted. Note that this is a low-level semantic change (when endptr is not NULL, we can now successfully parse with a scale of 'E' and then report trailing junk, instead of failing outright with EINVAL); but an earlier commit already argued that this is not a high-level semantic change since the only caller passing in a non-NULL endptr also checks that the tail is whitespace-only. Fixes: https://gitlab.com/qemu-project/qemu/-/issues/1629 Fixes: cf923b78 ("utils: Improve qemu_strtosz() to have 64 bits of precision", 6.0.0) Fixes: 7625a1ed ("utils: Use fixed-point arithmetic in qemu_strtosz", 6.0.0) Signed-off-by: Eric Blake Reviewed-by: Hanna Czenczek --- v2: more changes, handle negatives differently, catch fractions that round to 0 but don't underflow [Hanna] --- tests/unit/test-cutils.c | 50 +++++++++------------- util/cutils.c | 89 ++++++++++++++++++++++++++++++---------- 2 files changed, 86 insertions(+), 53 deletions(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 8f2dd335f13..67c3de00c82 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -3285,19 +3285,18 @@ static void test_qemu_strtosz_float(void) /* An empty fraction tail is tolerated */ do_strtosz("1.k", 0, 1024, 3); - /* FIXME An empty fraction head should be tolerated */ - do_strtosz(" .5k", -EINVAL /* FIXME 0 */, 0 /* FIXME 512 */, - 0 /* FIXME 4 */); + /* An empty fraction head is tolerated */ + do_strtosz(" .5k", 0, 512, 4); /* For convenience, we permit values that are not byte-exact */ do_strtosz("12.345M", 0, (uint64_t) (12.345 * MiB + 0.5), 7); - /* FIXME Fraction tail should round correctly */ + /* Fraction tail can round up */ do_strtosz("1.9999k", 0, 2048, 7); do_strtosz("1.9999999999999999999999999999999999999999999999999999k", 0, - 1024 /* FIXME 2048 */, 55); + 2048, 55); - /* FIXME ERANGE underflow in the fraction tail should not matter for 'k' */ + /* ERANGE underflow in the fraction tail does not matter for 'k' */ do_strtosz("1." "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" @@ -3306,7 +3305,7 @@ static void test_qemu_strtosz_float(void) "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" - "1k", 0, 1 /* FIXME 1024 */, 354); + "1k", 0, 1024, 354); } static void test_qemu_strtosz_invalid(void) @@ -3330,10 +3329,9 @@ static void test_qemu_strtosz_invalid(void) do_strtosz("1.1B", -EINVAL, 0, 0); do_strtosz("1.1", -EINVAL, 0, 0); - /* FIXME underflow in the fraction tail should matter for 'B' */ + /* 'B' cannot have any nonzero fraction, even with rounding or underflow */ do_strtosz("1.00001B", -EINVAL, 0, 0); - do_strtosz("1.00000000000000000001B", 0 /* FIXME -EINVAL */, - 1 /* FIXME 0 */, 23 /* FIXME 0 */); + do_strtosz("1.00000000000000000001B", -EINVAL, 0, 0); do_strtosz("1." "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" @@ -3342,8 +3340,7 @@ static void test_qemu_strtosz_invalid(void) "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" - "1B", 0 /* FIXME -EINVAL */, 1 /* FIXME 0 */, - 354 /* FIXME 0 */); + "1B", -EINVAL, 0, 0); /* No hex fractions */ do_strtosz("0x1.8k", -EINVAL, 0, 0); @@ -3389,28 +3386,20 @@ static void test_qemu_strtosz_trailing(void) do_strtosz_full("123-45", qemu_strtosz, 0, 123, 3, -EINVAL, 0); do_strtosz_full(" 123 - 45", qemu_strtosz, 0, 123, 4, -EINVAL, 0); - /* FIXME should stop parse after 'e'. No floating point exponents */ - do_strtosz_full("1.5e1k", qemu_strtosz, -EINVAL /* FIXME 0 */, - 0 /* FIXME EiB * 1.5 */, 0 /* FIXME 4 */, - -EINVAL, 0); - do_strtosz_full("1.5E+0k", qemu_strtosz, -EINVAL /* FIXME 0 */, - 0 /* FIXME EiB * 1.5 */, 0 /* FIXME 4 */, - -EINVAL, 0); - - /* FIXME overflow in fraction is still buggy */ - do_strtosz_full("1.5E999", qemu_strtosz, 0, 1 /* FIXME EiB * 1.5 */, - 2 /* FIXME 4 */, -EINVAL, 0); + /* Parse stops at 'e', which is not a floating point exponent */ + do_strtosz_full("1.5e1k", qemu_strtosz, 0, EiB * 1.5, 4, -EINVAL, 0); + do_strtosz_full("1.5E+0k", qemu_strtosz, 0, EiB * 1.5, 4, -EINVAL, 0); + do_strtosz_full("1.5E999", qemu_strtosz, 0, EiB * 1.5, 4, -EINVAL, 0); } static void test_qemu_strtosz_erange(void) { - /* FIXME negative values fit better as ERANGE */ + /* no negative values */ do_strtosz(" -0", -ERANGE, 0, 3); do_strtosz("-1", -ERANGE, 0, 2); do_strtosz_full("-2M", qemu_strtosz, -ERANGE, 0, 2, -EINVAL, 0); - do_strtosz(" -.0", -EINVAL /* FIXME -ERANGE */, 0, 0 /* FIXME 4 */); - do_strtosz_full("-.1k", qemu_strtosz, -EINVAL /* FIXME -ERANGE */, 0, - 0 /* FIXME 3 */, -EINVAL, 0); + do_strtosz(" -.0", -ERANGE, 0, 4); + do_strtosz_full("-.1k", qemu_strtosz, -ERANGE, 0, 3, -EINVAL, 0); do_strtosz_full(" -." "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" @@ -3419,17 +3408,16 @@ static void test_qemu_strtosz_erange(void) "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" - "1M", qemu_strtosz, -EINVAL /* FIXME -ERANGE */, 0, - 0 /* FIXME 354 */, -EINVAL, 0); + "1M", qemu_strtosz, -ERANGE, 0, 354, -EINVAL, 0); /* 2^64; see strtosz_simple for 2^64-1 */ do_strtosz("18446744073709551616", -ERANGE, 0, 20); do_strtosz("20E", -ERANGE, 0, 3); - /* FIXME Fraction tail can cause ERANGE overflow */ + /* Fraction tail can cause ERANGE overflow */ do_strtosz("15.9999999999999999999999999999999999999999999999999999E", - 0 /* FIXME -ERANGE */, 15ULL * EiB /* FIXME 0 */, 56); + -ERANGE, 0, 56); /* EINVAL has priority over ERANGE */ do_strtosz_full("100000Pjunk", qemu_strtosz, -ERANGE, 0, 7, -EINVAL, 0); diff --git a/util/cutils.c b/util/cutils.c index 25c95b0933e..20b732176fa 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -194,15 +194,18 @@ static int64_t suffix_mul(char suffix, int64_t unit) * - 12345 - decimal, scale determined by @default_suffix and @unit * - 12345{bBkKmMgGtTpPeE} - decimal, scale determined by suffix and @unit * - 12345.678{kKmMgGtTpPeE} - decimal, scale determined by suffix, and - * fractional portion is truncated to byte + * fractional portion is truncated to byte, either side of . may be empty * - 0x7fEE - hexadecimal, unit determined by @default_suffix * * The following are intentionally not supported - * - hex with scaling suffix, such as 0x20M - * - octal, such as 08 - * - fractional hex, such as 0x1.8 - * - negative values, including -0 - * - floating point exponents, such as 1e3 + * - hex with scaling suffix, such as 0x20M (0x1b is 27, not 1) + * - octal, such as 08 (parsed as decimal instead) + * - binary, such as 0b1000 (parsed as 0b with trailing garbage "1000") + * - fractional hex, such as 0x1.8 (parsed as 0 with trailing garbage "x1.8") + * - negative values, including -0 (fail with -ERANGE) + * - floating point exponents, such as 1e3 (parsed as 1e with trailing + * garbage "3") or 0x1p3 (parsed as 1 with trailing garbage "p3") + * - non-finite values, such as inf or NaN (fail with -EINVAL) * * The end pointer will be returned in *end, if not NULL. If there is * no fraction, the input can be decimal or hexadecimal; if there is a @@ -221,17 +224,17 @@ static int do_strtosz(const char *nptr, const char **end, uint64_t *result) { int retval; - const char *endptr, *f; + const char *endptr; unsigned char c; - uint64_t val, valf = 0; + uint64_t val = 0, valf = 0; int64_t mul; /* Parse integral portion as decimal. */ retval = parse_uint(nptr, &endptr, 10, &val); - if (retval) { + if (retval == -ERANGE || !nptr) { goto out; } - if (val == 0 && (*endptr == 'x' || *endptr == 'X')) { + if (retval == 0 && val == 0 && (*endptr == 'x' || *endptr == 'X')) { /* Input looks like hex; reparse, and insist on no fraction or suffix. */ retval = qemu_strtou64(nptr, &endptr, 16, &val); if (retval) { @@ -242,27 +245,69 @@ static int do_strtosz(const char *nptr, const char **end, retval = -EINVAL; goto out; } - } else if (*endptr == '.') { + } else if (*endptr == '.' || (endptr == nptr && strchr(nptr, '.'))) { /* * Input looks like a fraction. Make sure even 1.k works - * without fractional digits. If we see an exponent, treat - * the entire input as invalid instead. + * without fractional digits. strtod tries to treat 'e' as an + * exponent, but we want to treat it as a scaling suffix; + * doing this requires modifying a copy of the fraction. */ - double fraction; + double fraction = 0.0; - f = endptr; - retval = qemu_strtod_finite(f, &endptr, &fraction); - if (retval) { + if (retval == 0 && *endptr == '.' && !isdigit(endptr[1])) { + /* If we got here, we parsed at least one digit already. */ endptr++; - } else if (memchr(f, 'e', endptr - f) || memchr(f, 'E', endptr - f)) { - endptr = nptr; - retval = -EINVAL; - goto out; } else { - /* Extract into a 64-bit fixed-point fraction. */ + char *e; + const char *tail; + g_autofree char *copy = g_strdup(endptr); + + e = strchr(copy, 'e'); + if (e) { + *e = '\0'; + } + e = strchr(copy, 'E'); + if (e) { + *e = '\0'; + } + /* + * If this is a floating point, we are guaranteed that '.' + * appears before any possible digits in copy. If it is + * not a floating point, strtod will fail. Either way, + * there is now no exponent in copy, so if it parses, we + * know 0.0 <= abs(result) <= 1.0 (after rounding), and + * ERANGE is only possible on underflow which is okay. + */ + retval = qemu_strtod_finite(copy, &tail, &fraction); + endptr += tail - copy; + if (signbit(fraction)) { + retval = -ERANGE; + goto out; + } + } + + /* Extract into a 64-bit fixed-point fraction. */ + if (fraction == 1.0) { + if (val == UINT64_MAX) { + retval = -ERANGE; + goto out; + } + val++; + } else if (retval == -ERANGE) { + /* See comments above about underflow */ + valf = 1; + retval = 0; + } else { + /* We want non-zero valf for any non-zero fraction */ valf = (uint64_t)(fraction * 0x1p64); + if (valf == 0 && fraction > 0.0) { + valf = 1; + } } } + if (retval) { + goto out; + } c = *endptr; mul = suffix_mul(c, unit); if (mul > 0) {