From nobody Tue May 26 08:31:32 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779721601; cv=none; d=zohomail.com; s=zohoarc; b=oHYgHBQJlmzxwgfsjc2Uz3Bs4ipk1ufxMZu1xwJ1UW9f75iIc4QxuG5t+j4+exRcz+/Gi0eCu2MfcEVYBmSQJSOfLkDqGtY5MRAG6xaLFuCUpuSpOMVaRbAOXO4yTL1k+m74OYxmApSDP6J2sDVN9kl9ul21WbB61rwXoeV1UY4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779721601; h=Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To:Cc; bh=seRe1ZqQqT3HIB24WiVLXa3WLn+CdJlH2m0bpSi8QME=; b=imwDzq/68Nlj7KeqrP3NoYvbbiITLGh/50Hjn+6KHAQiOkKTUubOugQKb0sxacgP0LE81x9BYO5KqCoTu+8/w6kkStZPNZDCocIi0fkwVylDR57rzEHvnprFWGvABPkCNTOqPBhBg2ZZ3WaofMIocrbqAiP4ypoNk96sxG7pO74= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779721601376708.0873288128313; Mon, 25 May 2026 08:06:41 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRWri-0000ja-FF; Mon, 25 May 2026 11:05:14 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRWrh-0000iv-Ip for qemu-devel@nongnu.org; Mon, 25 May 2026 11:05:13 -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 1wRWrf-00014N-Ne for qemu-devel@nongnu.org; Mon, 25 May 2026 11:05:13 -0400 Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-510-9qttMOuRPeOa5CEwjEfyuQ-1; Mon, 25 May 2026 11:05:08 -0400 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-49050c44bcdso29140745e9.3 for ; Mon, 25 May 2026 08:05:08 -0700 (PDT) Received: from [192.168.10.48] ([176.206.106.181]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-490454ea134sm284210305e9.8.2026.05.25.08.05.05 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 25 May 2026 08:05:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779721510; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=seRe1ZqQqT3HIB24WiVLXa3WLn+CdJlH2m0bpSi8QME=; b=EVyJewoj9G3aQA1Rw+rRUiQDiDu1SA0UaR5nkvrsdL76WRwbq4LSPMuX7FMw8RUaP3wxDD nys88KJ11QYxYeD1DOdg2k9EoTOHRppDpE5/3y3mcTzSbyCJ2zQgTfaZhisyo+c5Z1XptM eKXRVs7P23fEfsRppcf6rOLb1B8jpQg= X-MC-Unique: 9qttMOuRPeOa5CEwjEfyuQ-1 X-Mimecast-MFC-AGG-ID: 9qttMOuRPeOa5CEwjEfyuQ_1779721507 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779721507; x=1780326307; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=seRe1ZqQqT3HIB24WiVLXa3WLn+CdJlH2m0bpSi8QME=; b=A7a9SosVTQ3C2KQS3ECkB7p3i8euAlZ1MILDilppnp2VUTAD4Rxs5EqGCVEh+uqBKH 7ofNZim3AkU4dekSGhWhro6yE26H7BqYSQ0hwd/jMqaAuZ7U93vD6UhRdxU3T0TC4uvr SuEvA4H9nEDBWPv6kdvZPK3gpoHxUE4hPW4u1Ny+SJtOT351NKCcFNYbbnMFaJVsqR7l u7O5ib+AHN8xB118nKMjKjYBSq9lBpGzMOQPclhpGKenWYqewa7F37TMpM5q55Bz1qQb 7XtDuJIm4hcY7xCQFUGQ+uqDCCfE5xR5ruGhxvC8gH8ZFR4B/uTWS1WpeKSUWSx3GW0h k6ug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779721507; x=1780326307; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=seRe1ZqQqT3HIB24WiVLXa3WLn+CdJlH2m0bpSi8QME=; b=aqTR70AOPWF82LboXP9JxTCJmR5WVSoGetkDC7GB7S2dXehIi9hHkApuaRkd6UWvpp TGvkWrHk7EvhXW9/JsP/NPGi/VQAxl2DEYqQfpXi68tczYW6Pi2Pz4chfFY7Ke8gBrzg 9YNvy+MlcF/q9T3YrmcTrlksLZcZj8FBbj5UorUgS7QHCrGkgzFGceoL7aeKmYBD2UFc MW0/4OM5dAOqdcsP+GWiGKl50e3iVGKxCU2VuvjHFq7/HVvEH8Cpb3tDO8SVNFPzL/bB WlUaEy834zb8Ud1id24ywYXmGVrzP/WX+0IPs4dStGxhhZTLuqhLWp4D6Q7E/6RYS9Rl lAEw== X-Gm-Message-State: AOJu0Yw4JBqdHSMFlsCrDRqeSY8D8Go+J/n+kIfsB7PwVSuJAAVhhbE7 SBn/A3/1jRe1v50Z7+boWmchpMUt95VgadfHJ8Hgc24uTbqD4X03AgYtp0VWG8VeONHcfO72mK6 vh/xYz9WI75PYu3k5I2GwAz5a/jl3OMDdm/Ab/+fopuZNKhZk1NTeoaZd1QrPd2lEY3hRjVzWSP h5UM8p2ggLgH6jnO/3pTECzMyb4dkQN+U2yoXt5YI0 X-Gm-Gg: Acq92OGrFTMnlskobnoJYlWgyMkgGFVYZpt9dpENqsdNdRo1Fd8tBGTsjIezViZquwF v/T1pFuICB1HSeA747ZAarb0RbSrTf4v70r7RxKKuxLXSdp/WKPG57lODsSbvmPIQ8YGWYk70X1 sLRKXoNtBJ0YEKOWIaXtSqax3reCsrHA4Cvm/+pIATZ5dFj68x6pVa5pr/VTy5PO8XmXuVUBVTt ikvbCHjOZHQcdZfq70vqC99ZwhLRDcVTjHbphDv1+R26b83rhR5BxTLGJZIjBWT+kRvSMrASAgE SHuLWayKrtSGNwBf95vdTRstm49FW8Gdfq+LoNOymB9lKfnibONWo2asxwIukmO0XqwSrpU99D+ nBLkFhEkGEzOHp6vQDINFNauHRp+MWteP4xdiW44MW+OCdjUFagOuq3tSGp6kn2Z+y2bfNhBDbM w+AgtyA6vNZ7LB/g4vBykQJ37kHb6c X-Received: by 2002:a05:600d:6450:10b0:48a:7a10:4f17 with SMTP id 5b1f17b1804b1-4904249d125mr172190575e9.6.1779721507366; Mon, 25 May 2026 08:05:07 -0700 (PDT) X-Received: by 2002:a05:600d:6450:10b0:48a:7a10:4f17 with SMTP id 5b1f17b1804b1-4904249d125mr172189955e9.6.1779721506852; Mon, 25 May 2026 08:05:06 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Subject: [PATCH v3 1/7] json-parser: constify JSONToken Date: Mon, 25 May 2026 17:04:57 +0200 Message-ID: <20260525150503.393743-2-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260525150503.393743-1-pbonzini@redhat.com> References: <20260525150503.393743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, 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_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 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: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779721603231154100 Content-Type: text/plain; charset="utf-8" Signed-off-by: Paolo Bonzini --- qobject/json-parser.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/qobject/json-parser.c b/qobject/json-parser.c index 7483e582fea..f6622b82b0a 100644 --- a/qobject/json-parser.c +++ b/qobject/json-parser.c @@ -55,7 +55,8 @@ static QObject *parse_value(JSONParserContext *ctxt); * Error handler */ static void G_GNUC_PRINTF(3, 4) parse_error(JSONParserContext *ctxt, - JSONToken *token, const char *m= sg, ...) + const JSONToken *token, + const char *msg, ...) { va_list ap; char message[1024]; @@ -126,7 +127,7 @@ static int cvt4hex(const char *s) * - Invalid Unicode characters are rejected. * - Control characters \x00..\x1F are rejected by the lexer. */ -static QString *parse_string(JSONParserContext *ctxt, JSONToken *token) +static QString *parse_string(JSONParserContext *ctxt, const JSONToken *tok= en) { const char *ptr =3D token->str; GString *str; @@ -239,14 +240,14 @@ out: * parser_context_pop_token is deleted as soon as parser_context_pop_token * is called again. */ -static JSONToken *parser_context_pop_token(JSONParserContext *ctxt) +static const JSONToken *parser_context_pop_token(JSONParserContext *ctxt) { g_free(ctxt->current); ctxt->current =3D g_queue_pop_head(ctxt->buf); return ctxt->current; } =20 -static JSONToken *parser_context_peek_token(JSONParserContext *ctxt) +static const JSONToken *parser_context_peek_token(JSONParserContext *ctxt) { return g_queue_peek_head(ctxt->buf); } @@ -259,7 +260,7 @@ static int parse_pair(JSONParserContext *ctxt, QDict *d= ict) QObject *key_obj =3D NULL; QString *key; QObject *value; - JSONToken *peek, *token; + const JSONToken *peek, *token; =20 peek =3D parser_context_peek_token(ctxt); if (peek =3D=3D NULL) { @@ -309,7 +310,7 @@ out: static QObject *parse_object(JSONParserContext *ctxt) { QDict *dict =3D NULL; - JSONToken *token, *peek; + const JSONToken *token, *peek; =20 token =3D parser_context_pop_token(ctxt); assert(token && token->type =3D=3D JSON_LCURLY); @@ -363,7 +364,7 @@ out: static QObject *parse_array(JSONParserContext *ctxt) { QList *list =3D NULL; - JSONToken *token, *peek; + const JSONToken *token, *peek; =20 token =3D parser_context_pop_token(ctxt); assert(token && token->type =3D=3D JSON_LSQUARE); @@ -426,7 +427,7 @@ out: =20 static QObject *parse_keyword(JSONParserContext *ctxt) { - JSONToken *token; + const JSONToken *token; =20 token =3D parser_context_pop_token(ctxt); assert(token && token->type =3D=3D JSON_KEYWORD); @@ -444,7 +445,7 @@ static QObject *parse_keyword(JSONParserContext *ctxt) =20 static QObject *parse_interpolation(JSONParserContext *ctxt) { - JSONToken *token; + const JSONToken *token; =20 token =3D parser_context_pop_token(ctxt); assert(token && token->type =3D=3D JSON_INTERP); @@ -480,7 +481,7 @@ static QObject *parse_interpolation(JSONParserContext *= ctxt) =20 static QObject *parse_literal(JSONParserContext *ctxt) { - JSONToken *token; + const JSONToken *token; =20 token =3D parser_context_pop_token(ctxt); assert(token); @@ -532,7 +533,7 @@ static QObject *parse_literal(JSONParserContext *ctxt) =20 static QObject *parse_value(JSONParserContext *ctxt) { - JSONToken *token; + const JSONToken *token; =20 token =3D parser_context_peek_token(ctxt); if (token =3D=3D NULL) { --=20 2.54.0 From nobody Tue May 26 08:31:32 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779721596; cv=none; d=zohomail.com; s=zohoarc; b=oH8Sp/G9UeHibInNVjW8VMDp+0XU4QJyJyBrzYUWvMm73G1Q2v9ATJUDHpH8QicFQBsiTQQeXLkRaoL7lycKOVDtPVATCvsN6d4JHJLLSpwDSqUoz2vROGuuwGX6AVzar0+U8dFBbNeBdHlkDVKyqn1yPJFElcfkMsLO1TkKOWs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779721596; h=Content-Type:Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To:Cc; bh=17nfyil9fVonFwkYVSR+98uO8qfpjkpfJ0rZSLmfLys=; b=hwPFTuvJlYSDvfJ+RxWAvkcgV5ZbJWjcyCJnXy8ULsgc/b2BsHuzrZVhmfEi8S5uc5WxZfUmJmoZ9IyzckLj/ylxfehDNQYcruwrAHvN/m0IRIVfHKcmAa0cW0fdKjmu6OMeZPIL8AmPwRiU/GxtZSOpcJQ9dDTLiBUCcTyPYFE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779721596772833.9729991505694; Mon, 25 May 2026 08:06:36 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRWrn-0000mr-0H; Mon, 25 May 2026 11:05:19 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRWrl-0000mF-Tw for qemu-devel@nongnu.org; Mon, 25 May 2026 11:05:17 -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 1wRWrj-00014s-3k for qemu-devel@nongnu.org; Mon, 25 May 2026 11:05:17 -0400 Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-335-SSwFPLm3Pn6PEW0oS0ArLA-1; Mon, 25 May 2026 11:05:11 -0400 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-48fd233d1e2so10406885e9.1 for ; Mon, 25 May 2026 08:05:11 -0700 (PDT) Received: from [192.168.10.48] ([176.206.106.181]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-490428e03d4sm112417895e9.9.2026.05.25.08.05.07 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 25 May 2026 08:05:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779721514; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=17nfyil9fVonFwkYVSR+98uO8qfpjkpfJ0rZSLmfLys=; b=f75fjqRj2PqH9pG1RDtIfqGV8T+NWVpE3Z/EgRABTWWD/We2qVEPrNUGWCF7dD3zuQ7gnA Kso5VvRuIVAM7fspOcUYbeYhby5+ECVS/lv+HC/ByzX4k6sqlpRASlvUiBPMU63z9ce0Dn dRSm0zkJjsvsf7Uv+uL2YJanbgExdtY= X-MC-Unique: SSwFPLm3Pn6PEW0oS0ArLA-1 X-Mimecast-MFC-AGG-ID: SSwFPLm3Pn6PEW0oS0ArLA_1779721510 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779721510; x=1780326310; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=17nfyil9fVonFwkYVSR+98uO8qfpjkpfJ0rZSLmfLys=; b=PyH0YTopCoa3PzGE96e+ZRpmjtdl/G5eHcifJTrOZmu+oCRU/BM4k36UshQzFtL7rA nsxdmfUd5wQm10OIKwWaI6ysPqdWT1trvs/C6F7sYCUkfDbjd/z3ZMf25Dfxf/TyUnga 1v3/lIxw+4YtfOEEs/SWXMwBC1JjluyTwIwMiYEjEJsSJOvBPoraiHT6yUKS6gFd7RvF ee32xtGYMpAClLVgMiEG21AxbtykBIvckvnMtdWiXSjoq7nVf6cPuP6kBRXdcc4j4V0V Tq7tfv9A9Q+0m2LWC4jHhmcGbWPjDcrz9Gg4iOdDEWWrblgrfHHZKKp1MYGySdJBY8ju GG0Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779721510; x=1780326310; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=17nfyil9fVonFwkYVSR+98uO8qfpjkpfJ0rZSLmfLys=; b=cQ409dmEEKg43Rr44ZindCbDZ06gE8r5B5jzZQPzhxmy9EHLyY07bqpdKpNYI5lrFl jFXUm/K1d2bOXF3qJDnX8951WsB2c8NuKp3Tz1EYGW4PInNx557sR3+Zm407Vw4Jr1Nr YB74HppWmHT2Lys4Q+nUaZGfxZO3wrVvXuoSB1x6Dsndor6mMbUXNWdVPLAJ5rMyuggm OtWgTegJH3q2r/JtTqUIKTT60iB/GZ1hS8Ze+h3m/MsU4Lcg/42tsXTLO54qJPHUpJ++ XZ8J9FaEaCAsfpwXVXcDZmaeyuJHWSRe5FeiuORrzJTidwJRar8gAG4M6gbmuUJzJce+ KOHg== X-Gm-Message-State: AOJu0Yx7KgVkob9wkq4y8PsgVYzToHSAc/v+KrVuZ6BRqbcWkVEoLn6q Rmc77bAe8sLStLx6oaUjNd0ZdOPezTmZ2hXti8Q1jjdqwwAqMK2+Xg124lQ7c5iszHSQuoE/hld j0RMAQRCGqXDd78QQhSZEGtOfQLqGUVrajuKy+cCdG5O1hagYRQndNsFt26Ya6oYFh2c2oKP3Pr aAO5t6oKtE+aj2x0I7eoJkZQ1XvA+AWH7WDhKEBI7r X-Gm-Gg: Acq92OEyR86GcgS4tpSojCaEpv1BanbjSqZbvw0PKrM7WYkZrWqj6PJJxoh46J+2w8F XWMdrvdMfArn3Rxrt3duIY9SgpIGstZVmGv8rsrcsfhoMj3Xs6NYyQ8zBj6sy9nSeCHaHCdLdPR AigrGWZScz/KSIONOMMkxmXPbeL2O3/gsz0yWS5PlR/iEv1Q6miSxeiDj4vb6ESmxbVSCeLMA6u 48LpNKj+gZA3OXvAvBQk9VHpdZ7MF18RaL3LKOSUYl2tKp3CQpcYCObpmHPMx9boZny7GvkUhvw rAV9GmqVqiBVo5laWEV4gYGJl7qDMWX9WkAHWGpnswaO7Fxu2v4cpic3hvhWKKYjDi8J+rR2fK9 BwUBB1WKCq2c7w0w8wHCjJp4QJn71ai+rA4qNzBp/yiyGWf885hyACFZUvQLUQHIFtGIzyA92aw NdGdWQbqc8ZI7jLmwYpC8ugA2TZn1U X-Received: by 2002:a05:600c:3e16:b0:490:688b:f10d with SMTP id 5b1f17b1804b1-490688bf142mr46193895e9.7.1779721509845; Mon, 25 May 2026 08:05:09 -0700 (PDT) X-Received: by 2002:a05:600c:3e16:b0:490:688b:f10d with SMTP id 5b1f17b1804b1-490688bf142mr46192725e9.7.1779721508969; Mon, 25 May 2026 08:05:08 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Subject: [PATCH v3 2/7] json-parser: replace with a push parser Date: Mon, 25 May 2026 17:04:58 +0200 Message-ID: <20260525150503.393743-3-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260525150503.393743-1-pbonzini@redhat.com> References: <20260525150503.393743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, 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_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 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: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779721599488154100 In order to avoid stashing all the tokens corresponding to a JSON value, embed the parsing stack and state machine in JSONParser. This is more efficient and allows for more prompt error recovery; it also does not make the code substantially larger than the current recursive descent parser, though the state machine is probably a bit harder to follow. The stack consists of QLists and QDicts corresponding to open brackets and braces, plus optionally a QString with the current key on top of each QDict. After each value is parsed, it is added to the top array or dictionary or, if the stack is empty, json_parser_feed returns the complete QObject. For now, json-streamer.c keeps tracking the tokens up until braces and brackets are balanced, and then shoves the whole queue of tokens into the push parser. The only logic change is that JSON_END_OF_INPUT always triggers the emptying of the queue; the parser takes notice and checks that there is nothing on the stack. Not using brace_count and bracket_count for this is the first step towards improved separation of concerns between json-parser.c and json-streamer.c. Signed-off-by: Paolo Bonzini --- include/qobject/json-parser.h | 6 + qobject/json-parser-int.h | 5 +- qobject/json-parser.c | 551 ++++++++++++++++++++-------------- qobject/json-streamer.c | 21 +- 4 files changed, 345 insertions(+), 238 deletions(-) diff --git a/include/qobject/json-parser.h b/include/qobject/json-parser.h index 7345a9bd5cb..05346fa816b 100644 --- a/include/qobject/json-parser.h +++ b/include/qobject/json-parser.h @@ -20,6 +20,12 @@ typedef struct JSONLexer { int x, y; } JSONLexer; =20 +typedef struct JSONParserContext { + Error *err; + GQueue *stack; + va_list *ap; +} JSONParserContext; + typedef struct JSONMessageParser { void (*emit)(void *opaque, QObject *json, Error *err); void *opaque; diff --git a/qobject/json-parser-int.h b/qobject/json-parser-int.h index 8c01f236276..1f435cb8eb2 100644 --- a/qobject/json-parser-int.h +++ b/qobject/json-parser-int.h @@ -49,6 +49,9 @@ void json_message_process_token(JSONLexer *lexer, GString= *input, =20 /* json-parser.c */ JSONToken *json_token(JSONTokenType type, int x, int y, GString *tokstr); -QObject *json_parser_parse(GQueue *tokens, va_list *ap, Error **errp); +void json_parser_init(JSONParserContext *ctxt, va_list *ap); +void json_parser_reset(JSONParserContext *ctxt); +QObject *json_parser_feed(JSONParserContext *ctxt, const JSONToken *token,= Error **errp); +void json_parser_destroy(JSONParserContext *ctxt); =20 #endif diff --git a/qobject/json-parser.c b/qobject/json-parser.c index f6622b82b0a..3b5edc5bae4 100644 --- a/qobject/json-parser.c +++ b/qobject/json-parser.c @@ -31,12 +31,105 @@ struct JSONToken { char str[]; }; =20 -typedef struct JSONParserContext { - Error *err; - JSONToken *current; - GQueue *buf; - va_list *ap; -} JSONParserContext; +/* + * The JSON parser is a push parser, returning to the caller after every + * token. Therefore it has an explicit representation of its parser + * stack; each stack entry consists of a parser state and a QObject: + * - a QList, for an array that is being added to + * - a QDict, for a dictionary that is being added to + * - a QString, for the key of the next pair that will be added to a QDict + * + * The stack represents an arbitrary nesting of arrays and dictionaries + * (whose next key has been parsed); it can also have a dictionary whose + * next key has not been parsed, but that can only happen at the top level. + * Because of this, the stack contents are always of the form + * "(QList | QDict QString)* QDict?". + * + * An empty stack represents the beginning of the parsing process, with + * start state BEFORE_VALUE. + */ + +typedef enum JSONParserState { + AFTER_LCURLY, + AFTER_LSQUARE, + BEFORE_KEY, + BEFORE_VALUE, + END_OF_KEY, + END_OF_VALUE, +} JSONParserState; + +typedef struct JSONParserStackEntry { + /* + * State when the container is completed or, for the top of the stack, + * entry state for the next token. + */ + JSONParserState state; + + /* + * A QString with the last parsed key, or a QList/QDict for the current + * container. + */ + QObject *partial; +} JSONParserStackEntry; + +/* + * This is the JSON grammar that's parsed, with the state transition and + * action at each point of the grammar. While this is not a formal + * description, "-> action" represents the pseudocode of the action + * and "-> STATE" sets the top stack entry's state to STATE. + * + * // The initial state is BEFORE_VALUE. + * input :=3D value -> END_OF_VALUE -> return parsed value + * END_OF_INPUT -> check stack is empty + * + * // entered on BEFORE_VALUE; after any of these rules are processed, the + * // parser has completed a QObject and is in the END_OF_VALUE state. + * // + * // When the parser reaches the END_OF_VALUE state, it examines the + * // top of the stack to see if it's coming from "input" (stack empty), + * // "array_items" (TOS is a QList) or "dict_pairs" (TOS is a QString; the + * // item below will be a QDict). It then proceeds with the corresponding + * // actions, which will be one of: + * // - return parsed value + * // - add value to QList + * // - pop QString with the key, add key/value to the QDict + * value :=3D literal -> END_OF_VALUE + * | '[' -> push empty QList -> AFTER_LSQUARE + * after_lsquare -> END_OF_VALUE + * | '{' -> push empty QDict -> AFTER_LCURLY + * after_lcurly -> END_OF_VALUE + * + * // non-recursive values, entered on BEFORE_VALUE + * literal :=3D INTEGER -> END_OF_VALUE + * | FLOAT -> END_OF_VALUE + * | KEYWORD -> END_OF_VALUE + * | STRING -> END_OF_VALUE + * | INTERP -> END_OF_VALUE + * + * // entered on AFTER_LSQUARE + * after_lsquare :=3D ']' -> pop completed QList -> END_OF_VALUE + * | =CF=B5 -> BEFORE_VALUE + * array_items -> END_OF_VALUE + * + * // entered on BEFORE_VALUE, with TOS being a QList + * array_items :=3D value -> add value to QList -> END_OF_VALUE + * (']' -> pop completed QList -> END_OF_VALUE + * | ',' -> BEFORE_VALUE + * array_items) -> END_OF_VALUE + * + * // entered on AFTER_LCURLY + * after_lcurly :=3D '}' -> pop completed QDict -> END_OF_VALUE + * | =CF=B5 -> BEFORE_KEY + * dict_pairs -> END_OF_VALUE + * + * // entered on BEFORE_KEY, with TOS being a QDict + * dict_pairs :=3D (STRING | INTERP) -> push QString -> END_OF_KEY + * ':' -> BEFORE_VALUE + * value -> pop QString + add pair to QDict -> END_OF_VA= LUE + * ('}' -> pop completed QDict -> END_OF_VALUE + * | ',' -> BEFORE_KEY + * dict_pairs) -> END_OF_VALUE + */ =20 #define BUG_ON(cond) assert(!(cond)) =20 @@ -49,7 +142,26 @@ typedef struct JSONParserContext { * 4) deal with premature EOI */ =20 -static QObject *parse_value(JSONParserContext *ctxt); +static inline JSONParserStackEntry *current_entry(JSONParserContext *ctxt) +{ + return g_queue_peek_tail(ctxt->stack); +} + +static void push_entry(JSONParserContext *ctxt, QObject *partial, + JSONParserState state) +{ + JSONParserStackEntry *entry =3D g_new(JSONParserStackEntry, 1); + entry->partial =3D partial; + entry->state =3D state; + g_queue_push_tail(ctxt->stack, entry); +} + +static JSONParserStackEntry *pop_entry(JSONParserContext *ctxt) +{ + JSONParserStackEntry *entry =3D g_queue_pop_tail(ctxt->stack); + g_free(entry); + return current_entry(ctxt); +} =20 /** * Error handler @@ -236,200 +348,10 @@ out: return NULL; } =20 -/* Note: the token object returned by parser_context_peek_token or - * parser_context_pop_token is deleted as soon as parser_context_pop_token - * is called again. - */ -static const JSONToken *parser_context_pop_token(JSONParserContext *ctxt) +/* Terminals */ + +static QObject *parse_keyword(JSONParserContext *ctxt, const JSONToken *to= ken) { - g_free(ctxt->current); - ctxt->current =3D g_queue_pop_head(ctxt->buf); - return ctxt->current; -} - -static const JSONToken *parser_context_peek_token(JSONParserContext *ctxt) -{ - return g_queue_peek_head(ctxt->buf); -} - -/** - * Parsing rules - */ -static int parse_pair(JSONParserContext *ctxt, QDict *dict) -{ - QObject *key_obj =3D NULL; - QString *key; - QObject *value; - const JSONToken *peek, *token; - - peek =3D parser_context_peek_token(ctxt); - if (peek =3D=3D NULL) { - parse_error(ctxt, NULL, "premature EOI"); - goto out; - } - - key_obj =3D parse_value(ctxt); - key =3D qobject_to(QString, key_obj); - if (!key) { - parse_error(ctxt, peek, "key is not a string in object"); - goto out; - } - - token =3D parser_context_pop_token(ctxt); - if (token =3D=3D NULL) { - parse_error(ctxt, NULL, "premature EOI"); - goto out; - } - - if (token->type !=3D JSON_COLON) { - parse_error(ctxt, token, "missing : in object pair"); - goto out; - } - - value =3D parse_value(ctxt); - if (value =3D=3D NULL) { - parse_error(ctxt, token, "Missing value in dict"); - goto out; - } - - if (qdict_haskey(dict, qstring_get_str(key))) { - parse_error(ctxt, token, "duplicate key"); - goto out; - } - - qdict_put_obj(dict, qstring_get_str(key), value); - - qobject_unref(key_obj); - return 0; - -out: - qobject_unref(key_obj); - return -1; -} - -static QObject *parse_object(JSONParserContext *ctxt) -{ - QDict *dict =3D NULL; - const JSONToken *token, *peek; - - token =3D parser_context_pop_token(ctxt); - assert(token && token->type =3D=3D JSON_LCURLY); - - dict =3D qdict_new(); - - peek =3D parser_context_peek_token(ctxt); - if (peek =3D=3D NULL) { - parse_error(ctxt, NULL, "premature EOI"); - goto out; - } - - if (peek->type !=3D JSON_RCURLY) { - if (parse_pair(ctxt, dict) =3D=3D -1) { - goto out; - } - - token =3D parser_context_pop_token(ctxt); - if (token =3D=3D NULL) { - parse_error(ctxt, NULL, "premature EOI"); - goto out; - } - - while (token->type !=3D JSON_RCURLY) { - if (token->type !=3D JSON_COMMA) { - parse_error(ctxt, token, "expected separator in dict"); - goto out; - } - - if (parse_pair(ctxt, dict) =3D=3D -1) { - goto out; - } - - token =3D parser_context_pop_token(ctxt); - if (token =3D=3D NULL) { - parse_error(ctxt, NULL, "premature EOI"); - goto out; - } - } - } else { - (void)parser_context_pop_token(ctxt); - } - - return QOBJECT(dict); - -out: - qobject_unref(dict); - return NULL; -} - -static QObject *parse_array(JSONParserContext *ctxt) -{ - QList *list =3D NULL; - const JSONToken *token, *peek; - - token =3D parser_context_pop_token(ctxt); - assert(token && token->type =3D=3D JSON_LSQUARE); - - list =3D qlist_new(); - - peek =3D parser_context_peek_token(ctxt); - if (peek =3D=3D NULL) { - parse_error(ctxt, NULL, "premature EOI"); - goto out; - } - - if (peek->type !=3D JSON_RSQUARE) { - QObject *obj; - - obj =3D parse_value(ctxt); - if (obj =3D=3D NULL) { - parse_error(ctxt, token, "expecting value"); - goto out; - } - - qlist_append_obj(list, obj); - - token =3D parser_context_pop_token(ctxt); - if (token =3D=3D NULL) { - parse_error(ctxt, NULL, "premature EOI"); - goto out; - } - - while (token->type !=3D JSON_RSQUARE) { - if (token->type !=3D JSON_COMMA) { - parse_error(ctxt, token, "expected separator in list"); - goto out; - } - - obj =3D parse_value(ctxt); - if (obj =3D=3D NULL) { - parse_error(ctxt, token, "expecting value"); - goto out; - } - - qlist_append_obj(list, obj); - - token =3D parser_context_pop_token(ctxt); - if (token =3D=3D NULL) { - parse_error(ctxt, NULL, "premature EOI"); - goto out; - } - } - } else { - (void)parser_context_pop_token(ctxt); - } - - return QOBJECT(list); - -out: - qobject_unref(list); - return NULL; -} - -static QObject *parse_keyword(JSONParserContext *ctxt) -{ - const JSONToken *token; - - token =3D parser_context_pop_token(ctxt); assert(token && token->type =3D=3D JSON_KEYWORD); =20 if (!strcmp(token->str, "true")) { @@ -443,11 +365,9 @@ static QObject *parse_keyword(JSONParserContext *ctxt) return NULL; } =20 -static QObject *parse_interpolation(JSONParserContext *ctxt) +static QObject *parse_interpolation(JSONParserContext *ctxt, + const JSONToken *token) { - const JSONToken *token; - - token =3D parser_context_pop_token(ctxt); assert(token && token->type =3D=3D JSON_INTERP); =20 if (!strcmp(token->str, "%p")) { @@ -479,11 +399,8 @@ static QObject *parse_interpolation(JSONParserContext = *ctxt) return NULL; } =20 -static QObject *parse_literal(JSONParserContext *ctxt) +static QObject *parse_literal(JSONParserContext *ctxt, const JSONToken *to= ken) { - const JSONToken *token; - - token =3D parser_context_pop_token(ctxt); assert(token); =20 switch (token->type) { @@ -531,35 +448,167 @@ static QObject *parse_literal(JSONParserContext *ctx= t) } } =20 -static QObject *parse_value(JSONParserContext *ctxt) +/* Parsing state machine */ + +static QObject *parse_begin_value(JSONParserContext *ctxt, + const JSONToken *token) { - const JSONToken *token; - - token =3D parser_context_peek_token(ctxt); - if (token =3D=3D NULL) { - parse_error(ctxt, NULL, "premature EOI"); - return NULL; - } - switch (token->type) { case JSON_LCURLY: - return parse_object(ctxt); + push_entry(ctxt, QOBJECT(qdict_new()), AFTER_LCURLY); + return NULL; case JSON_LSQUARE: - return parse_array(ctxt); + push_entry(ctxt, QOBJECT(qlist_new()), AFTER_LSQUARE); + return NULL; case JSON_INTERP: - return parse_interpolation(ctxt); + return parse_interpolation(ctxt, token); case JSON_INTEGER: case JSON_FLOAT: case JSON_STRING: - return parse_literal(ctxt); + return parse_literal(ctxt, token); case JSON_KEYWORD: - return parse_keyword(ctxt); + return parse_keyword(ctxt, token); default: parse_error(ctxt, token, "expecting value"); return NULL; } } =20 +static QObject *parse_token(JSONParserContext *ctxt, const JSONToken *toke= n) +{ + JSONParserStackEntry *entry; + JSONParserState state; + QString *key; + QObject *key_obj =3D NULL, *value =3D NULL; + + entry =3D current_entry(ctxt); + state =3D entry ? entry->state : BEFORE_VALUE; + switch (state) { + case AFTER_LCURLY: + /* Grab '}' for empty object or fall through to BEFORE_KEY */ + assert(qobject_type(entry->partial) =3D=3D QTYPE_QDICT); + if (token->type =3D=3D JSON_RCURLY) { + value =3D entry->partial; + entry =3D pop_entry(ctxt); + break; + } + entry->state =3D BEFORE_KEY; + /* fall through */ + + case BEFORE_KEY: + /* Expecting object key */ + assert(qobject_type(entry->partial) =3D=3D QTYPE_QDICT); + if (token->type =3D=3D JSON_STRING || token->type =3D=3D JSON_INTE= RP) { + key_obj =3D parse_begin_value(ctxt, token); + if (!key_obj) { + /* parse error happened */ + return NULL; + } + } + if (!key_obj || qobject_type(key_obj) !=3D QTYPE_QSTRING) { + parse_error(ctxt, token, "key is not a string in object"); + return NULL; + } + + /* Store key in a special entry on the stack */ + push_entry(ctxt, key_obj, END_OF_KEY); + return NULL; + + case END_OF_KEY: + /* Expecting ':' after key */ + assert(qobject_type(entry->partial) =3D=3D QTYPE_QSTRING); + if (token->type =3D=3D JSON_COLON) { + entry->state =3D BEFORE_VALUE; + } else { + parse_error(ctxt, token, "expecting ':'"); + } + return NULL; + + case AFTER_LSQUARE: + /* Grab ']' for empty array or fall through to BEFORE_VALUE */ + assert(qobject_type(entry->partial) =3D=3D QTYPE_QLIST); + if (token->type =3D=3D JSON_RSQUARE) { + value =3D entry->partial; + entry =3D pop_entry(ctxt); + break; + } + entry->state =3D BEFORE_VALUE; + /* fall through */ + + case BEFORE_VALUE: + /* Expecting value */ + assert(!entry || qobject_type(entry->partial) !=3D QTYPE_QDICT); + value =3D parse_begin_value(ctxt, token); + if (!value) { + /* Error or '['/'{' */ + return NULL; + } + /* Return value or insert it into a container */ + break; + + case END_OF_VALUE: + /* Grab ',' or ']' for array; ',' or '}' for object */ + if (qobject_to(QList, entry->partial)) { + /* Array */ + if (token->type !=3D JSON_RSQUARE) { + if (token->type =3D=3D JSON_COMMA) { + entry->state =3D BEFORE_VALUE; + } else { + parse_error(ctxt, token, "expected ',' or ']'"); + } + return NULL; + } + } else if (qobject_to(QDict, entry->partial)) { + /* Object */ + if (token->type !=3D JSON_RCURLY) { + if (token->type =3D=3D JSON_COMMA) { + entry->state =3D BEFORE_KEY; + } else { + parse_error(ctxt, token, "expected ',' or '}'"); + } + return NULL; + } + } else { + g_assert_not_reached(); + } + + /* Got ']' or '}'; return full value or insert into parent contain= er */ + value =3D entry->partial; + entry =3D pop_entry(ctxt); + break; + } + + assert(value); + if (entry =3D=3D NULL) { + /* The toplevel value is complete. */ + return value; + } + + key =3D qobject_to(QString, entry->partial); + if (key) { + const char *key_str; + QDict *dict; + + entry =3D pop_entry(ctxt); + dict =3D qobject_to(QDict, entry->partial); + assert(dict); + key_str =3D qstring_get_str(key); + if (qdict_haskey(dict, key_str)) { + parse_error(ctxt, token, "duplicate key"); + qobject_unref(value); + return NULL; + } + qdict_put_obj(dict, key_str, value); + qobject_unref(key); + } else { + /* Add to array */ + qlist_append_obj(qobject_to(QList, entry->partial), value); + } + + entry->state =3D END_OF_VALUE; + return NULL; +} + JSONToken *json_token(JSONTokenType type, int x, int y, GString *tokstr) { JSONToken *token =3D g_malloc(sizeof(JSONToken) + tokstr->len + 1); @@ -572,20 +621,56 @@ JSONToken *json_token(JSONTokenType type, int x, int = y, GString *tokstr) return token; } =20 -QObject *json_parser_parse(GQueue *tokens, va_list *ap, Error **errp) +void json_parser_reset(JSONParserContext *ctxt) { - JSONParserContext ctxt =3D { .buf =3D tokens, .ap =3D ap }; - QObject *result; + JSONParserStackEntry *entry; =20 - result =3D parse_value(&ctxt); - assert(ctxt.err || g_queue_is_empty(ctxt.buf)); - - error_propagate(errp, ctxt.err); - - while (!g_queue_is_empty(ctxt.buf)) { - parser_context_pop_token(&ctxt); + ctxt->err =3D NULL; + while ((entry =3D g_queue_pop_tail(ctxt->stack)) !=3D NULL) { + qobject_unref(entry->partial); + g_free(entry); } - g_free(ctxt.current); +} =20 +void json_parser_init(JSONParserContext *ctxt, va_list *ap) +{ + ctxt->stack =3D g_queue_new(); + ctxt->ap =3D ap; + json_parser_reset(ctxt); +} + +void json_parser_destroy(JSONParserContext *ctxt) +{ + json_parser_reset(ctxt); + g_queue_free(ctxt->stack); + ctxt->stack =3D NULL; +} + +/* + * Advance the parser based on the token that is passed. + * Return the finished toplevel value if the token completes it. + * If an error is returned, the function must not be called without + * first resetting the parser. + */ +QObject *json_parser_feed(JSONParserContext *ctxt, const JSONToken *token, + Error **errp) +{ + QObject *result =3D NULL; + + assert(!ctxt->err); + switch (token->type) { + case JSON_END_OF_INPUT: + /* Check for premature end of input */ + if (!g_queue_is_empty(ctxt->stack)) { + parse_error(ctxt, token, "premature end of input"); + } + break; + + default: + result =3D parse_token(ctxt, token); + break; + } + + error_propagate(errp, ctxt->err); return result; } diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c index b93d97b995f..6c93e6fd78d 100644 --- a/qobject/json-streamer.c +++ b/qobject/json-streamer.c @@ -32,6 +32,7 @@ void json_message_process_token(JSONLexer *lexer, GString= *input, JSONTokenType type, int x, int y) { JSONMessageParser *parser =3D container_of(lexer, JSONMessageParser, l= exer); + JSONParserContext ctxt; QObject *json =3D NULL; Error *err =3D NULL; JSONToken *token; @@ -56,8 +57,7 @@ void json_message_process_token(JSONLexer *lexer, GString= *input, if (g_queue_is_empty(&parser->tokens)) { return; } - json =3D json_parser_parse(&parser->tokens, parser->ap, &err); - goto out_emit; + break; default: break; } @@ -85,11 +85,24 @@ void json_message_process_token(JSONLexer *lexer, GStri= ng *input, g_queue_push_tail(&parser->tokens, token); =20 if ((parser->brace_count > 0 || parser->bracket_count > 0) - && parser->brace_count >=3D 0 && parser->bracket_count >=3D 0) { + && parser->brace_count >=3D 0 && parser->bracket_count >=3D 0 + && type !=3D JSON_END_OF_INPUT) { return; } =20 - json =3D json_parser_parse(&parser->tokens, parser->ap, &err); + json_parser_init(&ctxt, parser->ap); + + /* Process all tokens in the queue */ + while (!g_queue_is_empty(&parser->tokens)) { + token =3D g_queue_pop_head(&parser->tokens); + json =3D json_parser_feed(&ctxt, token, &err); + g_free(token); + if (json || err) { + break; + } + } + + json_parser_destroy(&ctxt); =20 out_emit: parser->brace_count =3D 0; --=20 2.54.0 From nobody Tue May 26 08:31:32 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779721591; cv=none; d=zohomail.com; s=zohoarc; b=hn0RCYPHh+imKmGl3HEFeX8784qnLSgwV0X6yveLP40pFZqirza9HVl7ZfUR4V1xpoRgC6f6txg+EG+KrG74JQApS50oifkskty/YKTsy0dvK/m95+BUHS0Wo35xPV1VDfBOrHf3uwTJPNXJQMQQz/ox3m+Sb8M+NtsBQb2mogA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779721591; h=Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To:Cc; bh=/ERjXe+UF5yfB73iQjlHQiSxNM/6kyfITxFBZNn5OvM=; b=I8S162cXkJmvR/q5WJPpihTr5+gCU2UdZ9nCICYWZnj789pv5rCLaZuydb+7luBxa/xlI86DrGwTIMgjQcJdTMo8JJAtA2VHwV/rMbghr0+gkbgrtttxJXoteM3/d89t0GQB6Cz0aX8YaDb6+LGmLlJIZnhm45RgMh/szTsZEkg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779721591499134.26862053094055; Mon, 25 May 2026 08:06:31 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRWrt-0000va-NN; Mon, 25 May 2026 11:05:25 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRWrs-0000vB-Fl for qemu-devel@nongnu.org; Mon, 25 May 2026 11:05:24 -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 1wRWrq-00016v-NJ for qemu-devel@nongnu.org; Mon, 25 May 2026 11:05:23 -0400 Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-568-3xlDCUAQNX-wEEBMQrGmcA-1; Mon, 25 May 2026 11:05:14 -0400 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-49048e21ea7so13058665e9.1 for ; Mon, 25 May 2026 08:05:14 -0700 (PDT) Received: from [192.168.10.48] ([176.206.106.181]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45eb6cd351csm29081298f8f.14.2026.05.25.08.05.09 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 25 May 2026 08:05:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779721519; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/ERjXe+UF5yfB73iQjlHQiSxNM/6kyfITxFBZNn5OvM=; b=IJrx771c7sXKxDGbXbMOZr0StYGYiuLJrvcEi8kXj/N6Vuv2REUZJcrvvLuXgqEYXwCfDb 5l0DVeptYOdcpVgQcaQ0QvJ6eC4gkp6hQO0jgSrYK6nEqYRei5yJ25gvHkfUSwNYX9nWIB RNzuKBokgLsFJqyC4T7OrwOPgMHgLCw= X-MC-Unique: 3xlDCUAQNX-wEEBMQrGmcA-1 X-Mimecast-MFC-AGG-ID: 3xlDCUAQNX-wEEBMQrGmcA_1779721511 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779721511; x=1780326311; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=/ERjXe+UF5yfB73iQjlHQiSxNM/6kyfITxFBZNn5OvM=; b=bfpcaZXaA1vZiNyIo60et8DWtWRoWKFaGafXc/f/VsJhd/lgHaTYuuxTzJtqfeLpR9 5jrnCi/nLg9WwZlYSuu4JFT7xabAyda4vA2ZIs+ebN5gCB4XFJKckcjViGJ86UzEt8k+ eNTM3wx2J1dx9i+5oT82Hq1cta4Ezm7yAVx/7GP3wPzcQ8/b77YcjAElaC5BWmPCdXLJ mElOHQPWfnZQS/VvZX0WZXuULjwB3yPX+/Q8WbBqc913F9p6mG5izcSbMk7mjojAF1ax QtWCF0VEPwoG6FK9i+AcHsjvMcdBXBCjnhsVpM97Y0+cFgi6xbCFFGrnJdWW0DDEh4LB fiUA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779721511; x=1780326311; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=/ERjXe+UF5yfB73iQjlHQiSxNM/6kyfITxFBZNn5OvM=; b=jNyHdUYi2edYWPAXFXcYo4EtxNGF3G6N5MnKHUCYot+23sOLtyb5N8WcyNCm+dnrUP JlL6I6WrMGU8q6KVKQEPdmkT0xC2oHJv1fdHQjrczfIaOd8Waf66yINHwtJBOE5NFXXB eO2BO5b+YWS/WJ3HBqkn5TdnP+pifVSAv9xOZbCyZGvze7UxUHYDAhHbNgOoLsDONtdc K3cViu261TeFSSKId7rh+gdP3uOTECNcbAPO5RTRk5rtDEiQDgbJz643TvuUV2IaiTEZ EJdbQPFvU4Q5nsyJiH/71XiBLq535nrw0Lf+ieMkUaAG6f59bW0KedIR2TCmLzIfVPfn a5cQ== X-Gm-Message-State: AOJu0Yy6YMeK60SFqf88einCN5vdM4a2wohyuZ/Xy+5ea0f1Leba8sr+ fGkHDCPFoxYYvt5oZZsvDVXEDGIxdjmYzzwYrWihuhx006ySwV+47GQdFIIAHcJOvHxsA3fiQbo EFB7sBVqc6IK5Pd9UOiPvU+SgmmwKqPs5tGFzD8MqfkDlwnmmzNY595K5VtmjFHsV79AKuwgA2v oLVoRHqAyNcAnjO7T752wx9DPt3QjTrMlb9xXtjd87 X-Gm-Gg: Acq92OGh5sbDIhPuGxeYoJitG1tUffSa6Gxo5O6j53yNIK2Eq5N5Nxebz1bZG+ikoqg 887EuWZvFti9OK1TObFNkpXZCijlw8Fq764xAEQX1vRlZIp9S4i7YAjzh1m+aoonqgkQxwckM4m 9Bn5JKzJHa/slZ5C/a2MTXk8ZIv6PIGnuRapE3hF0Dh/j7AaPPhqg52aWZhXtQy07ekFk+r+eaS TFukS5dbzHOzNtucIqkk1zCBOyddU+cVY1JstVoku4zWnSUq3xVDllbVm2Uj+HFR2j6tFZrctD4 4qgEwkWKHq0eW4S9CbVSXReBBb0Jg+xPp7Z678Ul3lYoNKhryRDIC11IZhvUipuUMjyEX7VxyxE hLFnejaufRP5SmrbYEVfXJgicT2e1Jb83ac67rlZRmjTbO0B+yssncQzM7t0SK8wtJyVJrkHpW8 MDzlxtGNvV0cgifLavJJbSSPe3T3K/ X-Received: by 2002:a05:600d:6443:20b0:490:548f:6ca0 with SMTP id 5b1f17b1804b1-490548f6dc2mr95219295e9.8.1779721511419; Mon, 25 May 2026 08:05:11 -0700 (PDT) X-Received: by 2002:a05:600d:6443:20b0:490:548f:6ca0 with SMTP id 5b1f17b1804b1-490548f6dc2mr95218615e9.8.1779721510943; Mon, 25 May 2026 08:05:10 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Subject: [PATCH v3 3/7] json-streamer: reuse parser Date: Mon, 25 May 2026 17:04:59 +0200 Message-ID: <20260525150503.393743-4-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260525150503.393743-1-pbonzini@redhat.com> References: <20260525150503.393743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, 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_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 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: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779721593156154100 Content-Type: text/plain; charset="utf-8" The push parser can be reset, so reuse it when the json-streamer detects a completed toplevel object. Signed-off-by: Paolo Bonzini --- include/qobject/json-parser.h | 2 +- qobject/json-streamer.c | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/include/qobject/json-parser.h b/include/qobject/json-parser.h index 05346fa816b..4c3d89f751f 100644 --- a/include/qobject/json-parser.h +++ b/include/qobject/json-parser.h @@ -29,8 +29,8 @@ typedef struct JSONParserContext { typedef struct JSONMessageParser { void (*emit)(void *opaque, QObject *json, Error *err); void *opaque; - va_list *ap; JSONLexer lexer; + JSONParserContext parser; int brace_count; int bracket_count; GQueue tokens; diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c index 6c93e6fd78d..f3dfdcaea12 100644 --- a/qobject/json-streamer.c +++ b/qobject/json-streamer.c @@ -32,7 +32,6 @@ void json_message_process_token(JSONLexer *lexer, GString= *input, JSONTokenType type, int x, int y) { JSONMessageParser *parser =3D container_of(lexer, JSONMessageParser, l= exer); - JSONParserContext ctxt; QObject *json =3D NULL; Error *err =3D NULL; JSONToken *token; @@ -90,26 +89,23 @@ void json_message_process_token(JSONLexer *lexer, GStri= ng *input, return; } =20 - json_parser_init(&ctxt, parser->ap); - /* Process all tokens in the queue */ while (!g_queue_is_empty(&parser->tokens)) { token =3D g_queue_pop_head(&parser->tokens); - json =3D json_parser_feed(&ctxt, token, &err); + json =3D json_parser_feed(&parser->parser, token, &err); g_free(token); if (json || err) { break; } } =20 - json_parser_destroy(&ctxt); - out_emit: parser->brace_count =3D 0; parser->bracket_count =3D 0; json_message_free_tokens(parser); parser->token_size =3D 0; parser->emit(parser->opaque, json, err); + json_parser_reset(&parser->parser); } =20 void json_message_parser_init(JSONMessageParser *parser, @@ -119,12 +115,12 @@ void json_message_parser_init(JSONMessageParser *pars= er, { parser->emit =3D emit; parser->opaque =3D opaque; - parser->ap =3D ap; parser->brace_count =3D 0; parser->bracket_count =3D 0; g_queue_init(&parser->tokens); parser->token_size =3D 0; =20 + json_parser_init(&parser->parser, ap); json_lexer_init(&parser->lexer, !!ap); } =20 @@ -144,4 +140,5 @@ void json_message_parser_destroy(JSONMessageParser *par= ser) { json_lexer_destroy(&parser->lexer); json_message_free_tokens(parser); + json_parser_destroy(&parser->parser); } --=20 2.54.0 From nobody Tue May 26 08:31:32 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779721600; cv=none; d=zohomail.com; s=zohoarc; b=L0pC/esM+vNvMItzAIRU8aUkTWz0c/SXXcUftMZGPHcno/3C7+S7iDHTddzv6ws4z9vmPYQK35TkiOEdJiOZDkRMEZ8lcASOILKCge6eRAhOxOmmghz8mRrTCVVx/ovAf7k32GKmF9aVrej78wkqsIKNn3dX1tWBESWXjZ13afc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779721600; h=Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To:Cc; bh=gLty9WTrkgb0tLitcavi13F4CVcFzOwMfLsh2O+KoFY=; b=lck84CnAeUn1liKq99fRptN+cY87azz/04xxIESIWEaDNNRAmQ50KTb1Yf5dagW1YRPwTVgAjRD5GP8Yys2vYBIpp2+MTEolXMDcjYOyFOLiCGcLszqZuxmW5Yy0vwzQo4Gn9hCLomEwLC5nGdbk8QzX6EO7UZhnqvPuMP0KqfA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779721600638427.3358091497154; Mon, 25 May 2026 08:06:40 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRWrn-0000o1-D0; Mon, 25 May 2026 11:05:19 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRWrm-0000mW-6j for qemu-devel@nongnu.org; Mon, 25 May 2026 11:05:18 -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 1wRWrk-00015s-Ot for qemu-devel@nongnu.org; Mon, 25 May 2026 11:05:17 -0400 Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-240-qaJQ5OsEMOe8G7MdjNuRUA-1; Mon, 25 May 2026 11:05:14 -0400 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-49058e91639so14172415e9.3 for ; Mon, 25 May 2026 08:05:14 -0700 (PDT) Received: from [192.168.10.48] ([176.206.106.181]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49042af026esm84443205e9.30.2026.05.25.08.05.11 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 25 May 2026 08:05:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779721516; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=gLty9WTrkgb0tLitcavi13F4CVcFzOwMfLsh2O+KoFY=; b=Hto9vGmShYGrW4D0guwhnF8FEA6ycytTsBeoUyOQ8K/HwEpWpNwmyDa5VMc00RV6aRf2o0 8m8IGQS/l/puN7h3csVAOS6rEnDzve0ILPNDOGb9hxw3DD3gos2NhUJXTe8JlheUY/bbTf T+xZUDbOt8PoVEpE5Pi2Aq2o4menMYE= X-MC-Unique: qaJQ5OsEMOe8G7MdjNuRUA-1 X-Mimecast-MFC-AGG-ID: qaJQ5OsEMOe8G7MdjNuRUA_1779721513 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779721513; x=1780326313; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=gLty9WTrkgb0tLitcavi13F4CVcFzOwMfLsh2O+KoFY=; b=r8Y5b7c6fdqzrlol3eYWNa7bRKdlUfcPfPlrgudNiiSfYBoOFb7s9ktfabeQVJUW1M CiscaLBSWDQC9WiNVkI4QTj7jXW3fXyI5Bg5yWOIVTJnmbywqsfTc3UDthXoHLOsDBzO 5NLfJvvnGdrqHAVD3NBcyBRH/R6u8dbarNyWC6OT81i+s2S9OO1bjBh82zHG3k5Okoy6 Gvmt25uqOeQ7va81f9Yv0NgQ/NXL1J/lVvuFrmPzgTM2P7I3P1ESRxgDSh+qeynF2qz6 JWEcWUtJK3YL8M8WnTw0kBlkSOLMz1WhCwgtQYZ/C8zmFdTW/NEskDsV6xYY4oQmbOSU FG8A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779721513; x=1780326313; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=gLty9WTrkgb0tLitcavi13F4CVcFzOwMfLsh2O+KoFY=; b=bXsh3t7AuZnLAw+4xXKTyFGrJoPwj5MEBSYPts8AeEZTaZpKyraPn/Wxgjxbj3f1Vt oFSPnbyyoPn0Kv3wFhffHl3jvxSZBgcXr9TCZWoCuHn2TTgVDxOPuhDuFkWegI3IFePi jrcB9wa4QXMW4GzrQ/F8styqKmiZjLZwJqb7DN/NiaioXuSpnz2IOeIubyToUT+8wVKY NX50jUpLekuV2cGVKiNGtA94wLn0uJpHPh6+qofkAGTSA4RrBRBXNGg1CpUc23QoUNyI P+p5BAXfTkIVay3X0DeJxlId+O+Yazs4i0O/lQgQ6K58LD4H+qi21JVV5yY7VdI4BPZb MwFA== X-Gm-Message-State: AOJu0YyHW+1TTgbVuXaEPQOiM3laqtIL7gWx89ma4+upeuwN0jZl99+V 81gLR89za+xCtZHq/G5DM0U5hGTrTRTKVOTmdXAC7SVwEcay3lyU6xfjgyCRS8qd2eB1x5kZYFp UqBsOiAWUJlB+8+CyEqBu72ZnhyrzrDAhl0sM22G+K/WNFiFY6zTPX3NSkNqOUN0QjmgrsHo5UY WNHda7ZhhJrA70ogM70sFM6vzxTHTqr4i+jhvHSTVX X-Gm-Gg: Acq92OH7BHQGaOeSeG/biFxwBMQZMQ64dHg+kfS7cESARFMf3nsa+rK76AQ8Eh+VOVU 71PiPp4YVYqMrNUIKd+hPl51IcT11qKgK4sOopV9jT0LpqXvq0ulyAOxfx+vWKshbdW57StQB8w fGzAZ9nuL7EBuo/RDxeM+bmOGMT1zKb98OtnD0umYNp9n56RxN/eJ4CmcaJyphD7k4TzXeozefp FGH34Uzrmxv71WY2rFBEttiekcaFIzWBjnpzcKCvUoLD6w69cQUTP8qlwiPqa0SaVdsDo3Fm0Pr z38+GKdr0tH2DI9SOhHFjjunuoFJ0LHQfzlPose1XM0KcwX9tSZFPl5xFj3tCdmZMkZMy6+YzGY D/7jqwQvZ+WW9MuzXKoY4jT1FrqCe9VA38EDgaTK5DgX4u8uzQ3CZsfzNXT6ni2/gerAxhVWqr1 dnG9uFwMGROSZ98mHTEQlj/9KFOK++ X-Received: by 2002:a05:600c:a402:b0:490:3d62:eb0 with SMTP id 5b1f17b1804b1-490426d7019mr202253205e9.24.1779721513354; Mon, 25 May 2026 08:05:13 -0700 (PDT) X-Received: by 2002:a05:600c:a402:b0:490:3d62:eb0 with SMTP id 5b1f17b1804b1-490426d7019mr202252695e9.24.1779721512889; Mon, 25 May 2026 08:05:12 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Subject: [PATCH v3 4/7] json-streamer: make brace/bracket count unsigned Date: Mon, 25 May 2026 17:05:00 +0200 Message-ID: <20260525150503.393743-5-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260525150503.393743-1-pbonzini@redhat.com> References: <20260525150503.393743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, 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_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 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: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779721601137158500 Content-Type: text/plain; charset="utf-8" It makes no sense to let brace_count and bracket_count go negative, also because it immediately ends error recovery and sets them both back to zero. Instead set them to zero *before* choosing whether to process the token queue; this makes it possible to have the fields as unsigned. Note that JSON_END_OF_INPUT now forces the parentheses to appear balanced, so that the queue is emptied and an error is reported; hence, the "type !=3D JSON_END_OF_INPUT" condition can be removed. Signed-off-by: Paolo Bonzini --- include/qobject/json-parser.h | 4 ++-- qobject/json-streamer.c | 19 ++++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/include/qobject/json-parser.h b/include/qobject/json-parser.h index 4c3d89f751f..0cf6932ecdc 100644 --- a/include/qobject/json-parser.h +++ b/include/qobject/json-parser.h @@ -31,8 +31,8 @@ typedef struct JSONMessageParser { void *opaque; JSONLexer lexer; JSONParserContext parser; - int brace_count; - int bracket_count; + unsigned int brace_count; + unsigned int bracket_count; GQueue tokens; uint64_t token_size; } JSONMessageParser; diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c index f3dfdcaea12..b0bf2083ca6 100644 --- a/qobject/json-streamer.c +++ b/qobject/json-streamer.c @@ -41,12 +41,18 @@ void json_message_process_token(JSONLexer *lexer, GStri= ng *input, parser->brace_count++; break; case JSON_RCURLY: + if (parser->brace_count <=3D 0) { + goto end_error_recovery; + } parser->brace_count--; break; case JSON_LSQUARE: parser->bracket_count++; break; case JSON_RSQUARE: + if (parser->bracket_count <=3D 0) { + goto end_error_recovery; + } parser->bracket_count--; break; case JSON_ERROR: @@ -56,6 +62,15 @@ void json_message_process_token(JSONLexer *lexer, GStrin= g *input, if (g_queue_is_empty(&parser->tokens)) { return; } + end_error_recovery: + /* + * Cause error recovery to end immediately. + * If not in error recovery, the parser will raise an error + * (due to JSON_ERROR or unexpected JSON_R{CURLY,SQUARE}) + * but error recovery won't be entered at all. + */ + parser->brace_count =3D 0; + parser->bracket_count =3D 0; break; default: break; @@ -83,9 +98,7 @@ void json_message_process_token(JSONLexer *lexer, GString= *input, =20 g_queue_push_tail(&parser->tokens, token); =20 - if ((parser->brace_count > 0 || parser->bracket_count > 0) - && parser->brace_count >=3D 0 && parser->bracket_count >=3D 0 - && type !=3D JSON_END_OF_INPUT) { + if (parser->brace_count > 0 || parser->bracket_count > 0) { return; } =20 --=20 2.54.0 From nobody Tue May 26 08:31:32 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779721579; cv=none; d=zohomail.com; s=zohoarc; b=Nt7jPNb2Di4mcr1QRLYXYIbmoeCksedfNHogChtBCKxX14zC8P9tVWMxo5p32ywCMuQYVoqrme5LZXwVpdGdo9R85OamZjdunh8MN3DlHlWzL9+Pj+PGgxhahyKt9CGcHEzz9h2acuD1eSLT4D1F9mJdrh245Hwh+qSKzLeXPmw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779721579; h=Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To:Cc; bh=tbwwr95qXJz4xq269Q4zZDMuyeyImlQhnooKYRjbphE=; b=czXzAkIv0gvuvoiFgSyPFU2jc9ncZHZQ4WKkC8TTQKI5r0SDiDC0Pc47MRdBTmwrucAhPmAtqwv7ikaoJFCh6+qPKbB3giXT7Ntf/8X3w91y5jKm6KBLIFowQ7ftzZc1IM+6Nk2VGyW0VDu4AP6wqN8JB3o3aLHfb8qo3ndx1pY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779721579462325.0224749836764; Mon, 25 May 2026 08:06:19 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRWrp-0000tZ-Sh; Mon, 25 May 2026 11:05:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRWrp-0000r9-6x for qemu-devel@nongnu.org; Mon, 25 May 2026 11:05:21 -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 1wRWrn-00016q-5E for qemu-devel@nongnu.org; Mon, 25 May 2026 11:05:20 -0400 Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-638-nK4RZMjQNuGXQnGFLvsz5A-1; Mon, 25 May 2026 11:05:17 -0400 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-4411a2c034fso8830961f8f.3 for ; Mon, 25 May 2026 08:05:16 -0700 (PDT) Received: from [192.168.10.48] ([176.206.106.181]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45eb6d64eb1sm31257502f8f.32.2026.05.25.08.05.13 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 25 May 2026 08:05:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779721518; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=tbwwr95qXJz4xq269Q4zZDMuyeyImlQhnooKYRjbphE=; b=D8vmKl6DLuRHivUUcLNx8iZ8u349CwrWFdk46nZ6z62UTjcaUpfC8Fz29YW5bMpe0IWRZQ S51pMT0ozxZk2pfxTLxPBxj73AX6EUzChnUyokXgth2Klvz/RvmHF/PAHY6MPXdBdlMdof Uj+/4Fuy9Tt4jRj/vxW5Fbys8iqTRqc= X-MC-Unique: nK4RZMjQNuGXQnGFLvsz5A-1 X-Mimecast-MFC-AGG-ID: nK4RZMjQNuGXQnGFLvsz5A_1779721516 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779721516; x=1780326316; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=tbwwr95qXJz4xq269Q4zZDMuyeyImlQhnooKYRjbphE=; b=pYOpCXB46dQtXwLBhjjFVXj8I1AKVR6aswmLA5aqXLCo4MW9B1I4Q7o9B1xzzixJdz Rm0Km7RWl8PJDGsSiWRaRQOiCiJUlgscliOAjcaciJDLfdwtXlBdeA58eDkgIoECv5CM o0+5ZOkpoQeNjHbkdHs+ks0L2eawX+H783R07ji0VdI0q8k6exN8NFy+Z+EBoqJubNTM PbPZmxuqrc8gdju79q0nHlxxKsDRGnYZbsT4MUd3Ts9432EcChMGZt4N5Naih6yYa+fZ E1peVNe3hw25rsFpR9X1xN2NYQP4s20X6fs504YKFcroHTfrDbOlI9WjOMaObEPDUf1j wbLw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779721516; x=1780326316; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=tbwwr95qXJz4xq269Q4zZDMuyeyImlQhnooKYRjbphE=; b=rbsfHOUxtX4k2Uy9GiHMuwS4JB/kVfss6sgl1slJi53Lc9Y0lmeWPBjTw47KHsKvEX cg6Jzxe2eQfwR0SEgNuqo/HTMUyOs7S97/yTOj/pw70UrAM00ljoOg526sNMdPXHorxj xuvbrNizk3yfyE9u3eP7EV1MyvoFe9D6cANKU4XYvffrmJemqKX/WU+doxg28wPTBXoN SKY5sBlmYN3yc5xSNv80SlnKzem3CFRP/7nhHg2TtEmAg+7qEb8YDcbWA9Nxko4Cn679 agLY/yc55O/wIZjui2gU9F/LgZZwhtpcKIP4WcLmlmqJoKsp/UN1jZDEBN9FwINI8cg9 294Q== X-Gm-Message-State: AOJu0YwHop8vBbN4deAHbLPxeK6EPq1zCR/YlnZH9cqDgTKcPKDl7VVX 1k6KHYICJdFvRHMSlix44+sRp6NWuEOHW0KuLpOhvBGlA6cM/YySvVakVeJnrhuNc4DTW+58iu1 dr/P0TLnyJ8GJu3V71+RPR3ZxnMj4t/4fgy7lilvZ9UrobOYMKa4emvgddLLhAYUkj29vEP9M+n aHIXhZGf9QWcEtuY5OL8E0qS5WJ5vsjt+bLvpsvuZz X-Gm-Gg: Acq92OEUclNwrC1ybUSPA/+FX0nDME37/n6wBb3FEl1ehKIakLjKFaDlOgrv42EhzdQ x793SF9XpuJ2a2pDXVRSkHdGh5uj/LPCOJi7Xqe49d2GfsCYn64aP3yfbfeC9ZcYiutzmvtWR4m QflheeYiCvACKykDE0WBPRUDaAClGlO8bR3bucX+IDXHKH38z58UpwVaYMB6mEG3wtR0ku5MliJ dzEkZ2FztC/hOVEgrEhDloX5Jw2tQyd1Bsp5Oe85L3hSUZ982XSZGxi4Loq7bkfd4isA1CQWk82 rgtbfOWsk2TRgMUrZJIA6NLVhbN5dxhiCvs57TZTF+U6A8Q7LZt1OPPHt1MIvflTG/o7SxlDFnT fikRwKKJ0Y9nPJw1XSb14ZKiJ7SBar90cyaoYFnW2EoqosRrmMXaxZGYzq3TowDpukxHV7hFjOO 93btvC5TGqVljOA9M9uBz2kJTfj8Xf4zFMNG5kCb8= X-Received: by 2002:a5d:6f0f:0:b0:45e:6518:21ad with SMTP id ffacd0b85a97d-45eb369cf4amr23170384f8f.3.1779721515489; Mon, 25 May 2026 08:05:15 -0700 (PDT) X-Received: by 2002:a5d:6f0f:0:b0:45e:6518:21ad with SMTP id ffacd0b85a97d-45eb369cf4amr23170307f8f.3.1779721514856; Mon, 25 May 2026 08:05:14 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Subject: [PATCH v3 5/7] json-streamer: remove token queue Date: Mon, 25 May 2026 17:05:01 +0200 Message-ID: <20260525150503.393743-6-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260525150503.393743-1-pbonzini@redhat.com> References: <20260525150503.393743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, 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_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 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: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779721581174154100 Content-Type: text/plain; charset="utf-8" Now fully exploit the push parser, feeding it one token at a time without having to wait until braces and brackets are balanced. While the nesting counts are retained for error recovery purposes, the system can now report the first parsing error without waiting for parentheses to be balanced. This also means that JSON_ERROR can be handled in json-parser.c, not json-streamer.c. After reporting the error, json-streamer.c then enters an error recovery mode where subsequent errors are suppressed. This mimics the previous error reporting behavior, but it provides prompt feedback on parsing errors. As an example, here is an example interaction with qemu-ga. BEFORE (error reported only once braces are balanced): >> {"execute":foo >> } << {"error": {"class": "GenericError", "desc": "JSON parse error, invali= d keyword 'foo'"}} >> {"execute":"somecommand"} << {"error": {"class": "CommandNotFound", "desc": "The command somecomma= nd has not been found"}} AFTER (error reported immediately, but similar error recovery as before): >> {"execute":foo << {"error": {"class": "GenericError", "desc": "JSON parse error, invali= d keyword 'foo'"}} >> } >> {"execute":"somecommand"} << {"error": {"class": "CommandNotFound", "desc": "The command somecomma= nd has not been found"}} Signed-off-by: Paolo Bonzini --- include/qobject/json-parser.h | 3 +- qobject/json-parser.c | 4 ++ qobject/json-streamer.c | 100 ++++++++++++++-------------------- 3 files changed, 46 insertions(+), 61 deletions(-) diff --git a/include/qobject/json-parser.h b/include/qobject/json-parser.h index 0cf6932ecdc..3479e637588 100644 --- a/include/qobject/json-parser.h +++ b/include/qobject/json-parser.h @@ -33,7 +33,8 @@ typedef struct JSONMessageParser { JSONParserContext parser; unsigned int brace_count; unsigned int bracket_count; - GQueue tokens; + unsigned int token_count; + bool error; uint64_t token_size; } JSONMessageParser; =20 diff --git a/qobject/json-parser.c b/qobject/json-parser.c index 3b5edc5bae4..b77baab585f 100644 --- a/qobject/json-parser.c +++ b/qobject/json-parser.c @@ -659,6 +659,10 @@ QObject *json_parser_feed(JSONParserContext *ctxt, con= st JSONToken *token, =20 assert(!ctxt->err); switch (token->type) { + case JSON_ERROR: + parse_error(ctxt, token, "JSON parse error, stray '%s'", token->st= r); + break; + case JSON_END_OF_INPUT: /* Check for premature end of input */ if (!g_queue_is_empty(ctxt->stack)) { diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c index b0bf2083ca6..82d2bbc9426 100644 --- a/qobject/json-streamer.c +++ b/qobject/json-streamer.c @@ -1,5 +1,5 @@ /* - * JSON streaming support + * JSON parser - callback interface and error recovery * * Copyright IBM, Corp. 2009 * @@ -19,23 +19,16 @@ #define MAX_TOKEN_COUNT (2ULL << 20) #define MAX_NESTING (1 << 10) =20 -static void json_message_free_tokens(JSONMessageParser *parser) -{ - JSONToken *token; - - while ((token =3D g_queue_pop_head(&parser->tokens))) { - g_free(token); - } -} - void json_message_process_token(JSONLexer *lexer, GString *input, JSONTokenType type, int x, int y) { JSONMessageParser *parser =3D container_of(lexer, JSONMessageParser, l= exer); - QObject *json =3D NULL; Error *err =3D NULL; - JSONToken *token; =20 + parser->token_size +=3D input->len; + parser->token_count++; + + /* Detect message boundaries for error recovery purposes. */ switch (type) { case JSON_LCURLY: parser->brace_count++; @@ -56,12 +49,6 @@ void json_message_process_token(JSONLexer *lexer, GStrin= g *input, parser->bracket_count--; break; case JSON_ERROR: - error_setg(&err, "JSON parse error, stray '%s'", input->str); - goto out_emit; - case JSON_END_OF_INPUT: - if (g_queue_is_empty(&parser->tokens)) { - return; - } end_error_recovery: /* * Cause error recovery to end immediately. @@ -76,49 +63,43 @@ void json_message_process_token(JSONLexer *lexer, GStri= ng *input, break; } =20 - /* - * Security consideration, we limit total memory allocated per object - * and the maximum recursion depth that a message can force. - */ - if (parser->token_size + input->len + 1 > MAX_TOKEN_SIZE) { - error_setg(&err, "JSON token size limit exceeded"); - goto out_emit; - } - if (g_queue_get_length(&parser->tokens) + 1 > MAX_TOKEN_COUNT) { - error_setg(&err, "JSON token count limit exceeded"); - goto out_emit; - } - if (parser->bracket_count + parser->brace_count > MAX_NESTING) { - error_setg(&err, "JSON nesting depth limit exceeded"); - goto out_emit; - } + if (parser->error) { + /* error recovery, eat tokens until parentheses balance */ + } else { + /* + * Safety consideration, we limit total memory allocated per object + * and the maximum nesting depth that a message can force. + */ + if (parser->token_size > MAX_TOKEN_SIZE) { + error_setg(&err, "JSON token size limit exceeded"); + } else if (parser->token_count > MAX_TOKEN_COUNT) { + error_setg(&err, "JSON token count limit exceeded"); + } else if (parser->bracket_count + parser->brace_count > MAX_NESTI= NG) { + error_setg(&err, "JSON nesting depth limit exceeded"); + } else { + g_autofree JSONToken *token =3D json_token(type, x, y, input); + QObject *json =3D json_parser_feed(&parser->parser, token, &er= r); + if (json) { + parser->emit(parser->opaque, json, NULL); + } + } =20 - token =3D json_token(type, x, y, input); - parser->token_size +=3D input->len; - - g_queue_push_tail(&parser->tokens, token); - - if (parser->brace_count > 0 || parser->bracket_count > 0) { - return; - } - - /* Process all tokens in the queue */ - while (!g_queue_is_empty(&parser->tokens)) { - token =3D g_queue_pop_head(&parser->tokens); - json =3D json_parser_feed(&parser->parser, token, &err); - g_free(token); - if (json || err) { - break; + if (err) { + parser->emit(parser->opaque, NULL, err); + /* start recovery */ + parser->error =3D true; } } =20 -out_emit: - parser->brace_count =3D 0; - parser->bracket_count =3D 0; - json_message_free_tokens(parser); - parser->token_size =3D 0; - parser->emit(parser->opaque, json, err); - json_parser_reset(&parser->parser); + if ((parser->brace_count =3D=3D 0 && parser->bracket_count =3D=3D 0) + || type =3D=3D JSON_END_OF_INPUT) { + parser->error =3D false; + parser->brace_count =3D 0; + parser->bracket_count =3D 0; + parser->token_count =3D 0; + parser->token_size =3D 0; + json_parser_reset(&parser->parser); + } } =20 void json_message_parser_init(JSONMessageParser *parser, @@ -128,9 +109,10 @@ void json_message_parser_init(JSONMessageParser *parse= r, { parser->emit =3D emit; parser->opaque =3D opaque; + parser->error =3D false; parser->brace_count =3D 0; parser->bracket_count =3D 0; - g_queue_init(&parser->tokens); + parser->token_count =3D 0; parser->token_size =3D 0; =20 json_parser_init(&parser->parser, ap); @@ -146,12 +128,10 @@ void json_message_parser_feed(JSONMessageParser *pars= er, void json_message_parser_flush(JSONMessageParser *parser) { json_lexer_flush(&parser->lexer); - assert(g_queue_is_empty(&parser->tokens)); } =20 void json_message_parser_destroy(JSONMessageParser *parser) { json_lexer_destroy(&parser->lexer); - json_message_free_tokens(parser); json_parser_destroy(&parser->parser); } --=20 2.54.0 From nobody Tue May 26 08:31:32 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779721613; cv=none; d=zohomail.com; s=zohoarc; b=l96SWMeUM0wEW1JCxqSdPu69GFB7GIxeBpw1/z82D8ks6Y++huBH/B5FxJpiGqoca2JVZeeadvxoAyC10JsHaMfmqw+yt7jK5SFXcplFoGgfQb61SVe4jKYpiKvVr59CDXeKPAe6TmdP7TgAlNzV620JkLL/jAUim2QV/7kGxzI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779721613; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=K7RDjCFtQaBkL/yRAJRX+bTcPtvbDBTZmwcpcHMzSVs=; b=II2OBeTkO/f3hoMQAYh8+bXoLgIU61CFtV+bix3LFHapWuRDU3ZwVaQJC0e8B6c4O+3bvudUl7VIa8gCScJnQv18wce/hUrYXqf+VSVcfWkoFGS4lNpi8R2llhuT7j5lGS+RA5TcSDAIb7NaHC7QfhzgYgpz16Ov+deJgWsVN3k= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 177972161346921.97488576499427; Mon, 25 May 2026 08:06:53 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRWrs-0000vK-Sd; Mon, 25 May 2026 11:05:24 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRWrq-0000uk-He for qemu-devel@nongnu.org; Mon, 25 May 2026 11:05:22 -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 1wRWro-000170-Vm for qemu-devel@nongnu.org; Mon, 25 May 2026 11:05:22 -0400 Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-460-Pn3h9GjENVGO3O0Nax5Yeg-1; Mon, 25 May 2026 11:05:18 -0400 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-4903dcb32f8so31531305e9.0 for ; Mon, 25 May 2026 08:05:18 -0700 (PDT) Received: from [192.168.10.48] ([176.206.106.181]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45eb6d48e23sm26784409f8f.20.2026.05.25.08.05.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 25 May 2026 08:05:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779721520; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=K7RDjCFtQaBkL/yRAJRX+bTcPtvbDBTZmwcpcHMzSVs=; b=HLGC0ZN8zEwM7+VLAsmdJ1yJXRoQ2ee2RSsR5SUz+XfvIstrQPkMHJUUXRkXTjQIAHHdv7 iRN9wrw2jm0X72Cq/ypBtudjoq3u5upZq9eBy4Aoz6zlyze7fTGu3JaKc9E0pRAXZv+LkD cnCnzNGTIQddi12av4dLA6zCxL3YKxo= X-MC-Unique: Pn3h9GjENVGO3O0Nax5Yeg-1 X-Mimecast-MFC-AGG-ID: Pn3h9GjENVGO3O0Nax5Yeg_1779721518 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779721517; x=1780326317; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=K7RDjCFtQaBkL/yRAJRX+bTcPtvbDBTZmwcpcHMzSVs=; b=QRaV7OcI4+Vnd1KNC6hkf6G7gRLgJRfT8H/vNA/bE73B8cG8JGLepoQUMVs0g09bjM Woh3EqdLRbrh6p5aGki2lSfRQY+9X/N+rQaNrE/Iv65SdlLD3AnYwirapfprx7N/1eIP RR7kpt7bHFb6lqVlnGdhdeEmEr2eGT9xD66TeYWF8SOhs698YTb53qFUGNBNycubt+t7 +AxSC/hYkKFjq/AJovKlEjVQY192sfR167c356UDHSIAwvX5ShBHA7XN01qnj9iLVTFm RboZLyL+jjoVpVsP5ORGnTtRtTnNKsxWHIAckQlUX8I0VYgJ9fgwcemgtNt6OZXrQ3Tx NZ+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779721517; x=1780326317; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=K7RDjCFtQaBkL/yRAJRX+bTcPtvbDBTZmwcpcHMzSVs=; b=RMY9LIwaeVz+TX1FA1KAmVEj3bLzMxML/nKwU5zg2BUazeUoTDWZ6kv/fsp8GqObAT PqxcvIKe8lsS/KvPNxFu1z1EQUbR0by+iZhldwfjsqzr6QjRpeuRRNuX8sCGp6Iw9NZ4 KkseE0cfQRM0Q8vv+vIfzJxwpB8pFM2okwY81R+RuMhCd2M3oinZ6PE+zYqbRmkGgdqt 51RPZP2biwnNqsXETNZbE7amhg6GPx2P5oprS4HEFxRHpW/i7BHJbKtV2Jx6nWqp/WKE hLrJiQQLXI55JgB3LX8blimQm+w/XFnXCKK+0XozjuBAvUPckDVzKpV4C6Brl/ff8Xz0 TPXg== X-Gm-Message-State: AOJu0Yze/LoXMQ91EGz/EtcwqMYG91nMjJZLpvJRf9YgRiKkR+VpMnth qFzB4RofLIGgf3uzUgP8Lu9Vb56AI53nmfp78eOHX5VvKyb9NBlV4/RM/A8YOi03hw6u791abbF auz41yyY/0KOOBc65DVfa5beFErot4jQYIqfQODmAQ1LITry+8Je+P01XhD9yfvzRQkX8R2PlhG k1PBZmUSxKiy63YY4II9giii+rQoHtNtdb/31eOoq4 X-Gm-Gg: Acq92OHjS1eGeVREvPBK9fLZ+zW1pvlPo8gjm6GJZuMCwLNM8oYhcjsPywX2BXf9/f/ SlI7O8BIySLDulp2aXHUvCsYD+ots/NsITNb4+oDr9OZ14in3tIhCZbSX86olaAC/bdzhn31Bep gUrwr3U3Dk1I/7HInMqhQ/ecyW9L8mJUvSkdO3Y2Yt6dHQ15Om9toOCbRcm1IHn7yc60wzeeiA5 /MSg4fwuI01QiWFePIZdf4mChCHjSOXcHbR/PiX0vQRhLP0BGVKkb7s8OBqBHpUtEwaovvZbP/Z lr6l1DNxg5PCoJUPygFvu8qgD2g8qMwyBTmrAJRNPglffOeqwhpMw3XPCqeLLVEiUc3CK8GoIsg 3P9yPa6r7rzZ8CjAySQPR+mzIazBLpHpi2A5pvtdrdyuS0W/4d/JurwoL4QZ0FDe3rPyTfhJKBM yA72pGD2utAIk7o8d1OVIK6QioVhKJqDIx1dH3yeI= X-Received: by 2002:a05:600c:a012:b0:490:5191:6e26 with SMTP id 5b1f17b1804b1-490519170bamr180276935e9.18.1779721517520; Mon, 25 May 2026 08:05:17 -0700 (PDT) X-Received: by 2002:a05:600c:a012:b0:490:5191:6e26 with SMTP id 5b1f17b1804b1-490519170bamr180276125e9.18.1779721517051; Mon, 25 May 2026 08:05:17 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: Markus Armbruster Subject: [PATCH v3 6/7] json-streamer: do not heap-allocate JSONToken Date: Mon, 25 May 2026 17:05:02 +0200 Message-ID: <20260525150503.393743-7-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260525150503.393743-1-pbonzini@redhat.com> References: <20260525150503.393743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, 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_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 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: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779721615661154100 Content-Type: text/plain; charset="utf-8" This is not needed with a push parser. Since it processes tokens immediately, the JSONToken can be created directly on the stack and does not need to copy the lexer's string data. Reviewed-by: Markus Armbruster Signed-off-by: Paolo Bonzini --- qobject/json-parser-int.h | 8 ++++++-- qobject/json-parser.c | 18 ------------------ qobject/json-streamer.c | 9 +++++++-- 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/qobject/json-parser-int.h b/qobject/json-parser-int.h index 1f435cb8eb2..5a6b5c9af90 100644 --- a/qobject/json-parser-int.h +++ b/qobject/json-parser-int.h @@ -35,7 +35,12 @@ typedef enum json_token_type { JSON_MAX =3D JSON_END_OF_INPUT } JSONTokenType; =20 -typedef struct JSONToken JSONToken; +typedef struct JSONToken { + JSONTokenType type; + int x; + int y; + char *str; +} JSONToken; =20 /* json-lexer.c */ void json_lexer_init(JSONLexer *lexer, bool enable_interpolation); @@ -48,7 +53,6 @@ void json_message_process_token(JSONLexer *lexer, GString= *input, JSONTokenType type, int x, int y); =20 /* json-parser.c */ -JSONToken *json_token(JSONTokenType type, int x, int y, GString *tokstr); void json_parser_init(JSONParserContext *ctxt, va_list *ap); void json_parser_reset(JSONParserContext *ctxt); QObject *json_parser_feed(JSONParserContext *ctxt, const JSONToken *token,= Error **errp); diff --git a/qobject/json-parser.c b/qobject/json-parser.c index b77baab585f..faf3a9142bd 100644 --- a/qobject/json-parser.c +++ b/qobject/json-parser.c @@ -24,13 +24,6 @@ #include "qobject/qstring.h" #include "json-parser-int.h" =20 -struct JSONToken { - JSONTokenType type; - int x; - int y; - char str[]; -}; - /* * The JSON parser is a push parser, returning to the caller after every * token. Therefore it has an explicit representation of its parser @@ -609,17 +602,6 @@ static QObject *parse_token(JSONParserContext *ctxt, c= onst JSONToken *token) return NULL; } =20 -JSONToken *json_token(JSONTokenType type, int x, int y, GString *tokstr) -{ - JSONToken *token =3D g_malloc(sizeof(JSONToken) + tokstr->len + 1); - - token->type =3D type; - memcpy(token->str, tokstr->str, tokstr->len); - token->str[tokstr->len] =3D 0; - token->x =3D x; - token->y =3D y; - return token; -} =20 void json_parser_reset(JSONParserContext *ctxt) { diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c index 82d2bbc9426..2c1f20fc62b 100644 --- a/qobject/json-streamer.c +++ b/qobject/json-streamer.c @@ -77,8 +77,13 @@ void json_message_process_token(JSONLexer *lexer, GStrin= g *input, } else if (parser->bracket_count + parser->brace_count > MAX_NESTI= NG) { error_setg(&err, "JSON nesting depth limit exceeded"); } else { - g_autofree JSONToken *token =3D json_token(type, x, y, input); - QObject *json =3D json_parser_feed(&parser->parser, token, &er= r); + JSONToken token =3D (JSONToken) { + .type =3D type, + .x =3D x, + .y =3D y, + .str =3D input->str + }; + QObject *json =3D json_parser_feed(&parser->parser, &token, &e= rr); if (json) { parser->emit(parser->opaque, json, NULL); } --=20 2.54.0 From nobody Tue May 26 08:31:32 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779721616; cv=none; d=zohomail.com; s=zohoarc; b=JtKEb7DZwEWyqGkBDwk3A4XgTk/aglMLW0Y4w7+BnqtNSZ66+H5pBWq+VC8wtsniL3SnZIv7Yj6AIzP2NbCqEK9bVcLZdWANCArAHkeDmhLiyV9Sm/ik2ljbdYZsE/+lpkGNT3c4xjbsi+SVvETqHS2b6MRWdI+RF13o0lyC8qU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779721616; h=Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To:Cc; bh=LSlPLllxbCkrfFMjQn0uDUMwWkJljCiXnCYQyJGHgeQ=; b=jAoyLq24i3u1vQ4l6yyjUVok3nfTzhmVpiOK7elCqi3v6nbLDMRg1dDjFEzm3hflDzUrXDWwKkZZwWRFLbCGn6SY7y5lTSLUp/ylih885x5XjTS+yV8pzJxiBJRNFH3l47hn4nS53fRTubhCYsYb12IavBdrC4029NM4jBS86Yk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17797216167881011.5751915323568; Mon, 25 May 2026 08:06:56 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRWry-0000z6-Fw; Mon, 25 May 2026 11:05:31 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRWrv-0000vq-LY for qemu-devel@nongnu.org; Mon, 25 May 2026 11:05:27 -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 1wRWru-00017X-0a for qemu-devel@nongnu.org; Mon, 25 May 2026 11:05:27 -0400 Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-68-kVUvW07jOMWxJPRk1YiVMQ-1; Mon, 25 May 2026 11:05:22 -0400 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-48fde68e420so78316275e9.0 for ; Mon, 25 May 2026 08:05:20 -0700 (PDT) Received: from [192.168.10.48] ([176.206.106.181]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-490428d3e9esm115289225e9.7.2026.05.25.08.05.17 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 25 May 2026 08:05:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779721525; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=LSlPLllxbCkrfFMjQn0uDUMwWkJljCiXnCYQyJGHgeQ=; b=jDuoHtSzLd6UMxt2DeILxeOLehThV285yMucuhAz/ghYP5LTTzW3dz945BChTgD3636Qoa pL/hkTjaOsjMVYX1pr19YvbxrJK4zZE8Js4jFqS9XEKeKtqFG0L/KtjnLNzUIEDVha3Cnn 0uiyR7T/FcT1Wo+rPzpZ8nBlhf91vrs= X-MC-Unique: kVUvW07jOMWxJPRk1YiVMQ-1 X-Mimecast-MFC-AGG-ID: kVUvW07jOMWxJPRk1YiVMQ_1779721520 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779721520; x=1780326320; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=LSlPLllxbCkrfFMjQn0uDUMwWkJljCiXnCYQyJGHgeQ=; b=TBWzlH7vKjtDwmKKNtIpNii52a/wrMpRVHhNwlATLfrzUceAencPlh+S/vrcExli/C oOEpdbCxB15lsDHsWbP80IyDKAdpohACcBPMzmb0QuuZHJ+ZCezciVd9GrDHwM136Zvm TqcdABnRp7EBv6xgMnL1peDtrsUJhyYZygtj5eIu89IisgBv6GXMZLQ+y/vf8dW2Gm98 JBjS+pVwz2ijYFmeYnJpj+UGQD2OsbzL1IKBJpHmjiHEGl/oqTh6f02wUAotlQXPlXMs H1UAIQdcJbmcSXng9TxyVbdzaKHVDzJUjPRFSEi53dlIHFkGjw9+UF1O4Ai1x+zbxE7L drUQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779721520; x=1780326320; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=LSlPLllxbCkrfFMjQn0uDUMwWkJljCiXnCYQyJGHgeQ=; b=mIXz5jraY6c94SpiXT19wUM1DKYJjA911YryTtnPsQ+0lHh5XuLjo9tThLaT26fZjY t0Ljv6QXGm+EtwzmSCOTLISlvph4MO9KQRIHhscuElsLwpxpAGddWzhcwLtTaG+5XKfn 0+9lcb5ezC1SHxjbXd7+rBWbBTCINxpxQi5b1MY/De5wQl9fiuDg2T9Xekqki8HG49JF WMCJb886hWF+SDnhLALynLm4279WJ0YWplVe+Ode8WW/m4bw8iwNwZQNglxNXqXgFm46 x1NB1gbWKnk1h672+XudAZtlsnM7Qn9GRtXeCCocVEcFE3tJAv5yhm4mOxjA46/lAJq/ sgJw== X-Gm-Message-State: AOJu0Yx+lQmp+J5kXdst7E0ahJe4t+AfN1AOiIvMrFNT3GlTmVzOfdgM QKCakCKj7XZD0q9ulmGibvF6vd8JwOfQugJHfFA+6RhgFPUUsZx35DjKONOTq2kDmviTFZ7tSPq WkmZFDsqYfvJhcBUZRO18r9W98S3l+pMP8JJ/GD7LQncgjTYFSJq8KM7YmIhuLYpvHMUWWRPqpO QoLnbf89unFIJqTraPKUxHG0OMqUPlXVUYipv2Q/gS X-Gm-Gg: Acq92OHFcNSvcoCjNdBM8CCJh/ny/Cp0ThVEXqCGGVMf22+PtB46w4R29grdgNU0x6T EcI7+HuT9PgmpBbk/oZdcIIr5+upGrV0Q7BI7wUF13jw8g0umqoQKDPaFCOG99Fpof7qvYphYPo 9EKM0pmTwsxwK5Y2MS3sZjYg3+kfUNwrd+bEdwBZYPL118cZoiZjn3q07tTpPyv19id9RHiAKgR ooICXsNSscM8pc1tSFBuzcXUukopD2kr6h+dG6hjzmduuyibEIxXvL3or2ZB1Pp0gN0p6BQa90W zM67AiuVI/r8rUIGyKKFPnP08ZyfS60rqiK6yjADlbhUp8dm9XIrg3q7T2dCDW0KaSYZKSBH1yE ypy0mZNkU44AhLpTZB9st0GaRtADOmmDfI2BSk1ZBQ92Ar3fuZE30m3ALMIoge+QAsQTlb8tcOZ v34+AvWkbJMG1My+08rpiYKTFkOgEj X-Received: by 2002:a05:600c:4e14:b0:490:5cb3:e936 with SMTP id 5b1f17b1804b1-4905cb3eb00mr122124915e9.4.1779721519793; Mon, 25 May 2026 08:05:19 -0700 (PDT) X-Received: by 2002:a05:600c:4e14:b0:490:5cb3:e936 with SMTP id 5b1f17b1804b1-4905cb3eb00mr122123635e9.4.1779721519186; Mon, 25 May 2026 08:05:19 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Subject: [PATCH v3 7/7] json-parser: add location to JSON parsing errors Date: Mon, 25 May 2026 17:05:03 +0200 Message-ID: <20260525150503.393743-8-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260525150503.393743-1-pbonzini@redhat.com> References: <20260525150503.393743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, 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_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 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: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779721617563154100 Content-Type: text/plain; charset="utf-8" Now that all calls to parse_error have a token, add the line and column to the message. As far as I can see the two important TODOs (better errors and better EOI handling) are done, and the others (token range information and "parsed size"?) do not really matter or are handled better by json-streamer.c. So remove the list, which had sat unchanged since 2009. This needs some adjustments to provide a good x and y for error messages. First of all, they switch from zero-based to one-based, which is safe because they were both sitting unused. Second, right now the x and y are those of the *last* character in the token. Modify json-lexer.c to freeze tok->x and tok->y at the first character added to the GString. Signed-off-by: Paolo Bonzini --- include/qobject/json-parser.h | 1 + qobject/json-lexer.c | 11 +++++++---- qobject/json-parser.c | 12 ++---------- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/include/qobject/json-parser.h b/include/qobject/json-parser.h index 3479e637588..e078b36b2d5 100644 --- a/include/qobject/json-parser.h +++ b/include/qobject/json-parser.h @@ -17,6 +17,7 @@ typedef struct JSONLexer { int start_state, state; GString *token; + int cur_x, cur_y; int x, y; } JSONLexer; =20 diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c index 51341d96e49..7753ba6c092 100644 --- a/qobject/json-lexer.c +++ b/qobject/json-lexer.c @@ -277,7 +277,8 @@ void json_lexer_init(JSONLexer *lexer, bool enable_inte= rpolation) lexer->start_state =3D lexer->state =3D enable_interpolation ? IN_START_INTERP : IN_START; lexer->token =3D g_string_sized_new(3); - lexer->x =3D lexer->y =3D 0; + lexer->cur_x =3D lexer->cur_y =3D 1; + lexer->x =3D lexer->y =3D 1; } =20 static void json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush) @@ -285,10 +286,10 @@ static void json_lexer_feed_char(JSONLexer *lexer, ch= ar ch, bool flush) int new_state; bool char_consumed =3D false; =20 - lexer->x++; + lexer->cur_x++; if (ch =3D=3D '\n') { - lexer->x =3D 0; - lexer->y++; + lexer->cur_x =3D 1; + lexer->cur_y++; } =20 while (flush ? lexer->state !=3D lexer->start_state : !char_consumed) { @@ -316,6 +317,8 @@ static void json_lexer_feed_char(JSONLexer *lexer, char= ch, bool flush) case IN_START: g_string_truncate(lexer->token, 0); new_state =3D lexer->start_state; + lexer->x =3D lexer->cur_x; + lexer->y =3D lexer->cur_y; break; case JSON_ERROR: json_message_process_token(lexer, lexer->token, JSON_ERROR, diff --git a/qobject/json-parser.c b/qobject/json-parser.c index faf3a9142bd..8c58ae0349a 100644 --- a/qobject/json-parser.c +++ b/qobject/json-parser.c @@ -126,15 +126,6 @@ typedef struct JSONParserStackEntry { =20 #define BUG_ON(cond) assert(!(cond)) =20 -/** - * TODO - * - * 0) make errors meaningful again - * 1) add geometry information to tokens - * 3) should we return a parsed size? - * 4) deal with premature EOI - */ - static inline JSONParserStackEntry *current_entry(JSONParserContext *ctxt) { return g_queue_peek_tail(ctxt->stack); @@ -172,7 +163,8 @@ static void G_GNUC_PRINTF(3, 4) parse_error(JSONParserC= ontext *ctxt, va_start(ap, msg); vsnprintf(message, sizeof(message), msg, ap); va_end(ap); - error_setg(&ctxt->err, "JSON parse error, %s", message); + error_setg(&ctxt->err, "JSON parse error at line %d, column %d, %s", + token->y, token->x, message); } =20 static int cvt4hex(const char *s) --=20 2.54.0