From nobody Tue May 26 07:02:53 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=1777963815; cv=none; d=zohomail.com; s=zohoarc; b=Qlhaw13xIT4vgRxFJEA+T0yxdkpw/0mTDMo5Jx3zDLWS50itRC19uj1I2e4uDdP8cvzjky2qX9JMT+knST7VgJ+hLo0SMYiSJg6YCaniNPAMNY3IvY0Qhd8lEm1L/ljjq+3sK5C+Anjkgl6oQGiJIKKQwDZqyu3d8n2kCE+aNo0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1777963815; 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=seRe1ZqQqT3HIB24WiVLXa3WLn+CdJlH2m0bpSi8QME=; b=XB+ztm6FTzQKM8DAD0HjIR3bupRBt40ASgmjGADciD6fRE6XsZZBW+mfLBvdWGGrgnuA3DSItKHL9YMCSNmx6IUsgUkT1blydoPgZgqu09FM/xu9bk7Sf1v9rKCn+rw7mWf2Y497rAdTdutqGAHv7b39BWC6s0QrVx3KmCkiAwc= 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 1777963815504642.7087627569755; Mon, 4 May 2026 23:50:15 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wK9b3-0000AU-88; Tue, 05 May 2026 02:49:33 -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 1wK9b1-0000AC-O9 for qemu-devel@nongnu.org; Tue, 05 May 2026 02:49:31 -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 1wK9az-0005ms-Bt for qemu-devel@nongnu.org; Tue, 05 May 2026 02:49:30 -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-668-z9pwDgVeMYCCWYsZTQAW8Q-1; Tue, 05 May 2026 02:49:26 -0400 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-48d144d3428so5708195e9.3 for ; Mon, 04 May 2026 23:49:26 -0700 (PDT) Received: from [192.168.10.48] ([176.206.106.181]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-48a82307f7csm385227895e9.12.2026.05.04.23.49.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2026 23:49:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1777963767; 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=seRe1ZqQqT3HIB24WiVLXa3WLn+CdJlH2m0bpSi8QME=; b=aPY2gDxdErvG/UpD4pQ5uYrQLm5UFBmVXJRKQO7a+Zy1RR7YixO1I9+SKXmVyPiZebI+vq AUGK9OPcMVGJ8Q27W5bz3JXRuGI4tAtyQoOKomdYHdo1U0emjvaU5c9atqKGXoWmjR/0+Z soJoWRS/70e/HkDmetM06oX8G/OqH9c= X-MC-Unique: z9pwDgVeMYCCWYsZTQAW8Q-1 X-Mimecast-MFC-AGG-ID: z9pwDgVeMYCCWYsZTQAW8Q_1777963765 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1777963764; x=1778568564; 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=seRe1ZqQqT3HIB24WiVLXa3WLn+CdJlH2m0bpSi8QME=; b=CqINq38R6o4E8KG/92eljbcz7aVbyA+SKv9ShQ2FaLXbBiwwl/4U8zEDRs9d/92sTv q7mdW2SgjYfnZy5WNvSRF0/HctqvhmbUEAFSeqIt6440JvNUmCDvsUFsgidERFtIU6Pl fqNnOX6p6/EbevTKC4xBYKOwSYjE9inOP0nNRmYHpC23YnN2lcMfXxSq1OPDBhGvjRWi Y8elwzDEaulnuZ4/qcButuSs/DMh6VaVbaxS+UqRe8WVl87hgE0TJpiGVbo3B9psv7Y/ z2zdYIhHyrR/AUMgNFo3I5zVGbmcgz5Ebdbryi/So2WAM7GOzeMVLZOAxiQzSVOZfdBF AYsA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777963764; x=1778568564; 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=seRe1ZqQqT3HIB24WiVLXa3WLn+CdJlH2m0bpSi8QME=; b=RqtjkBAMBjOW4Xr5vnWqazZlPZzGxbnklRRQtc5FVqcfvS/6GCTJukcraLzYGMolGg ODc7CIbmBtP9OXXVTlZiafrSC7X82Be5xVCHLBlXNKI5aVrHCaZrrM7Ss7HXROJ7lLPU yJ8ZLU5rgXPPZZXuh7hRjoFjn4tq/jb7zY6Aadg174u3Ur831lLqVE0q3jzUgNz0RP9R rN6evIl87cdPspw0uLtKLylKNlnWTzFpmERlZbce22WwXd7WENCEDNfNYxWEFAn8eSdR OQqCGcyUxGtU0jGwf/+n8ZW7NOCoxvLJDXyd7eQZLt8NoFH4NCVX8xtHmcwfAnHdROcY 8MRA== X-Gm-Message-State: AOJu0YyglgfTHH0H/CUY3JPHttJXeReu+gDULSRsK6Lgg+5Dd34tGRu3 wdxnxKOi+3qDxNZBH4P2o3LlqXBC4vlS68RRRWBsx7kaQKcuNVdm9qlqot7JFZG4PFLMdiszVKO jKBssTWVO95JLWIOxyk6x8uC1UKrPmZl737BQRzt8HAVv6chiUh/X3YVwBFGjICTayU5fdjELZZ +L0uQQAfjdbb1KX3JlFTekIOqnTcu9UBKy9AcmjgUs X-Gm-Gg: AeBDietrADjOhrUzpphqgXMuoklxs4AMH+t7lchBqe8yfkFm5WYK/3NbsRwPIaMbc8R KIkda1MHshqJehGhxgM6zpjFQNRksfVIMOZSPOc3s3843O7vviLCQoYCtvo4c627deyKDSWtJro AXeN/Q7/5q+Xm3J5hW1b4hX/eFRv4uJRlxH/89x5/AAQkZ0VLLdjsiQqwruRLHS1OOxYHMQlEAf aEqhKypSmEemQxLZB1kvX1AZeUWbssV4nUlbztV0DLNPSm8aOy0lXUMhzVrNw3X4lsJxOLPdOLz 7bcmPPLMrx4ZyG1pJOe/GpqV4PGeRDjdbl8scRz4YscUi7OWjbYbi2jqv/U5csLmlVhw4u1fGDH A6REAyg4Vr9VuZeJe0Ep7X6zh3dc6CgV6rD9OFp1/bNTuA29M9sBRbxX6yA555g/esBJdUFKGu2 PIjilp8XwwntHb+o5GGHtQ8EyhsuwGjoONTLjDFcM= X-Received: by 2002:a05:600c:a302:b0:48a:568f:ae8a with SMTP id 5b1f17b1804b1-48a98638a65mr147188395e9.8.1777963764690; Mon, 04 May 2026 23:49:24 -0700 (PDT) X-Received: by 2002:a05:600c:a302:b0:48a:568f:ae8a with SMTP id 5b1f17b1804b1-48a98638a65mr147188235e9.8.1777963764293; Mon, 04 May 2026 23:49:24 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: armbru@redhat.com Subject: [PATCH v2 1/7] json-parser: constify JSONToken Date: Tue, 5 May 2026 08:49:13 +0200 Message-ID: <20260505064919.177855-2-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505064919.177855-1-pbonzini@redhat.com> References: <20260505064919.177855-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.444, 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: 1777963817335158500 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 07:02:53 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=1777963851; cv=none; d=zohomail.com; s=zohoarc; b=lj2+9WgChpcVUdN1uu2YKf/g+O1GJCARVdCMgfWFjM6C4WDD0TwO129uuHvpKF+yOLGLXwwbqpMCW4i1EHlPfiE/MKYw7AwIS0vbECX2kOXiLUedvIrtKHZopJ0etZ8k6w+F2IPcEnvhzMWNsQ+pFdh64kN7CyhOASiAo6SP5W8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1777963851; h=Content-Type: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=6JUlv7Osd38BoiHT7ox8emJyuMRLpI5wB8G+6/9to0Y=; b=nW7NGp0nAPEivlw8+TOwQ2olGN+hx2ZXVoqLJjtfVG+kwlNk/baW8OlGWjoZ/Beh0gIjZL0FY5a+2CWO6BnZcItYvvFUETe63hrq2jRTXpq9m5LxkREBLiJJvv1Nl5Z/bypgrSNxWSA+t0+oAeK6YCIRrGYHHzSVajT+cllzYj0= 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 1777963851863414.9157593874978; Mon, 4 May 2026 23:50:51 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wK9b8-0000Bt-7o; Tue, 05 May 2026 02:49:38 -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 1wK9b6-0000B9-Bw for qemu-devel@nongnu.org; Tue, 05 May 2026 02:49:36 -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 1wK9b1-0005nM-HB for qemu-devel@nongnu.org; Tue, 05 May 2026 02:49:34 -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-657-Dec7RANCN3WxOc1QLh3hVw-1; Tue, 05 May 2026 02:49:28 -0400 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-4891f97aef0so30896555e9.2 for ; Mon, 04 May 2026 23:49:28 -0700 (PDT) Received: from [192.168.10.48] ([176.206.106.181]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45055960902sm2167318f8f.28.2026.05.04.23.49.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2026 23:49:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1777963770; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6JUlv7Osd38BoiHT7ox8emJyuMRLpI5wB8G+6/9to0Y=; b=fOeTSMGkAWk3b+3v4uINTByzkJ10GTx9EJyj6jjJ6V6FT4tWErASW3h8eR6b/GuNZW/Kx+ G5lhGXEw0LNpoIbgEH+Fe7ayozHzyNXnzBG0/duNbYkk/eRhJhddjcaSthvcFrp+D0CARG fgGh0ZZMiKP6Tjq3e9UcKGk/69JQ2PQ= X-MC-Unique: Dec7RANCN3WxOc1QLh3hVw-1 X-Mimecast-MFC-AGG-ID: Dec7RANCN3WxOc1QLh3hVw_1777963768 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1777963767; x=1778568567; 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=6JUlv7Osd38BoiHT7ox8emJyuMRLpI5wB8G+6/9to0Y=; b=Qul+LzyHUnlRgoB1Eir9++4x+Gb/d9P7V3rffSwBQN/yoigAp24LOuFTXOtsz+ddII G3uS2ukVq2aeYdGNi2CU/+JT4VGMlTmeTY0rs2YZ8L62CQHe3VbImi/F116oW3DXfpP6 Z1QDXb4CHBUNgFQJaVrSCbCQXwc+bU29jsfomWgpup8obLYhR/kh/lX8mdmRoeTOUINQ tnstvlvP4I4NNmLDsoPqXK5a+zqqEteaqgbW6a8znuNjrCsrmWPnZBdmNQ8d5q8tBf2c LNtViP03S9lkIluNTX2oxr8mbWgJm4rATHCZ/GIHomwCpgzD3gQb+kY60R4/0OW7F56K 0lQg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777963767; x=1778568567; 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=6JUlv7Osd38BoiHT7ox8emJyuMRLpI5wB8G+6/9to0Y=; b=ANVIS8wNPdB62Z5LEmmf1bPI5jkjMCTF1i9/Z3oPBP3tJwtdznLW+Rfc2BX36iFeZK Un6/48pIuvPei9tRI/ii5PVYzTGzmFKk/fxN1k7ytdDmPwqGsOh+PEpbHbc3zsv9mEP3 SQ3PF0f+KjRp80VXK7UiZ5KNU91R4FbhwirGfVazoZVn8U/KiaAeJ5/HnOtWaDVODyaj oEVyDm+hy3fz/sryc9zP8LTMXyuApuZt+eLqQ+eks5ZkkRuhVKFhheCJlLvW/Q1WxGr/ 059JXYiNOGdtI5wKk8MxTCiS2EZZfrp+VQ/LXfaFFZy1TXgGFAXnmm5Nykq59dZqMOtL sHRQ== X-Gm-Message-State: AOJu0YyJj0/ZRcj0q7M9AXB6WyoRMcBhwV7QrCAjBWemTOSwfQ3b0gmB EWMzAg1Kp9Bt3HlMeqKWs02NAVlUtYxnizKfr2oTeEoQLyryNbhEZtnkuXfk4R/ThBqNKqZ2JHy N3WwBBF66BnaJRNEE4pBibT7sQ1S6I6aAXrnnJrQtcgTfmGf1UHtYLIgLtGTpPUQW8ckykfpali 4FsesTfyOGSiFcjKPDr3DRhMevWRromZ3a41Io8TUq X-Gm-Gg: AeBDieuwicXwFHn5ItCG+yeXITDz+ERVE9Djdn6Zti9ND9jHErFw62ZgNQT+BWTmZ8/ TQavrttwDlx8XdWP9GHIH3u76EjkrujA+LnnoCUKxs9Ds2lacPdE1jewbW7oT0N0jMFakQmfIFe MuQYpb+TpIxH76KCBlByCFW+068e4kz7x1MHTP6FZcWYHZRXTujcEv+Lp7fyUwFJy132MiWbazP /oZUuwY926LLR7VG+Vtn6E0gxr2lOFlXONsmWO65GPrCZxORD+MF4RoCb3zdexs7IV+BXQIAGig kVsBLHA1FYMQBopOl1UkSxG2UExHgU0S4F2dFHhQoug29pQnGIPY8kcT+xFOk6kEpevNEQljsjy otc+4VWsRw7TXoaXtGfynEE3/zbYjDSJg93V7vktjzPm1in/GifAZuw9IQ5Z7ciUnCO4SZLf4xk wP5PgltAtkAJuqUOrhjS7mEUHbXkFyZOB00n87dro= X-Received: by 2002:a05:600c:a111:b0:48a:6268:18a9 with SMTP id 5b1f17b1804b1-48a9865e835mr145174635e9.13.1777963766716; Mon, 04 May 2026 23:49:26 -0700 (PDT) X-Received: by 2002:a05:600c:a111:b0:48a:6268:18a9 with SMTP id 5b1f17b1804b1-48a9865e835mr145174155e9.13.1777963766044; Mon, 04 May 2026 23:49:26 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: armbru@redhat.com Subject: [PATCH v2 2/7] json-parser: replace with a push parser Date: Tue, 5 May 2026 08:49:14 +0200 Message-ID: <20260505064919.177855-3-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505064919.177855-1-pbonzini@redhat.com> References: <20260505064919.177855-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.444, 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: 1777963852888158500 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 | 548 +++++++++++++++++++--------------- qobject/json-streamer.c | 21 +- 4 files changed, 342 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..df103b4666c 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 -> 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,164 @@ 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 *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) { + key =3D parse_string(ctxt, token); + if (!key) { + return NULL; + } + + /* Store key in a special entry on the stack */ + push_entry(ctxt, QOBJECT(key), END_OF_KEY); + } else { + parse_error(ctxt, token, "key is not a string in object"); + } + 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 +618,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 07:02:53 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=1777963837; cv=none; d=zohomail.com; s=zohoarc; b=IF4zwiuR2NAXbDspT1Oflw7AEqFt2vaiQHkO19RhDkeTj2WvSweefRxdfFxisx1H6CdpnKPumoWSSHDKElm8CRfYP2Jv4G/0SXvzx1mIq2euRDVu2qt8gaoKn/mb1+Vyt+qLyVAl9nukwFx8OWd8n3osJjjqLLeutuSojGeNcSM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1777963837; 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=/ERjXe+UF5yfB73iQjlHQiSxNM/6kyfITxFBZNn5OvM=; b=HFTlamAGNz5Up4gNDzY2wiD5jm9Jcb8HQ0RjEFCljyLUEdjDML0axguPoiuyoJExcEqGsZ+C39fSQ/P7S7Z30pLA7Rx4+8AG2XYWzflc4ZPHsotfR/Sw3DjJ9hRJmxxxiVCAA9w56xfN1iowptX5ksSDgXsuiQ4bLtsdflWxDPo= 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 1777963837482186.83542960376906; Mon, 4 May 2026 23:50:37 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wK9b7-0000Bb-Fb; Tue, 05 May 2026 02:49:37 -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 1wK9b6-0000B8-C6 for qemu-devel@nongnu.org; Tue, 05 May 2026 02:49:36 -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 1wK9b3-0005rs-9l for qemu-devel@nongnu.org; Tue, 05 May 2026 02:49:35 -0400 Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-635-w9dtPyHdMJmPnI1ZZKxrIg-1; Tue, 05 May 2026 02:49:31 -0400 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-44696b11265so5217347f8f.0 for ; Mon, 04 May 2026 23:49:30 -0700 (PDT) Received: from [192.168.10.48] ([176.206.106.181]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45054b02f76sm2059488f8f.23.2026.05.04.23.49.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2026 23:49:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1777963772; 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=/ERjXe+UF5yfB73iQjlHQiSxNM/6kyfITxFBZNn5OvM=; b=A19d+HTvyZ7LhEc5nsAY7hWtBya+Aw9j/eGtxKzSU1f/8Q9ROdvpxgi5xVf6KKd0aDRkh6 gVGvIekbGhlXcQ4MCmlWKNEx30gANXQfBhHgmqcmexIeT0IwdfMKRfTpf8xm4B7pST6Ko/ 2v0DNs6ODrMjVtVCjVPr00R1NFTAo/Y= X-MC-Unique: w9dtPyHdMJmPnI1ZZKxrIg-1 X-Mimecast-MFC-AGG-ID: w9dtPyHdMJmPnI1ZZKxrIg_1777963770 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1777963769; x=1778568569; 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=/ERjXe+UF5yfB73iQjlHQiSxNM/6kyfITxFBZNn5OvM=; b=gnA9L6PEueeXEqb7nIrcsqk2XjtBnX6rR8s4ZuTJm8/P6oYATuEuBdVx8dqkGX4tQo Ju4DNx6YxpBKXmJNZMZ5KUlIDU5Yyn2MIq5RhszcyWbGzGCTB4orCapcC/lr4fnjMjIB PT4FTOcUokaO99Wx6s7b9z7dSWW0WE3Am7jXakTxDOJpyt6GdAKmqI1SY+SRIi0g+vwG WlfQwbKccpgzNmyOEpxsNF9HlBaLS93cq4Wc7M/D3HPDITNPdQvMV5yUYiuNDj1UNKgV O36I+Nk8r4ZybkZI/r29Azd1Kt4xGj/ntpmNKR6Jl8P5q4srzydZFbAgC7Y814DAB+eh OgmA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777963769; x=1778568569; 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=/ERjXe+UF5yfB73iQjlHQiSxNM/6kyfITxFBZNn5OvM=; b=Bji04DX6+hH7U44Cx2xshP1XDQ4tqGdnEVBeLptYnE8AInJNHVrGGChLYIm9TJ5Y1y gkpd1ymSLD6rehKGJ2Wlr06eXd/+ssa4R3cBb5fRXgJwp8a83UCVwZOfB7o5YpgG4WiQ 0FwYlO5hNNmHmGbHda7ZynHT9P4jKir9svgLCmwp2r6J+/E5MeOLA308Hw/yL1UpaaOn /s/ky8QPhmuPgZdWkchJcrdEhbSYVucjMvvt+jL4miPBIC4XS6MUh0ZczfzHjng0tJb4 5rz+xq7FpN8Y87xGfmHYZPx2uDmowdB67NtieTyLubI6zYN2MqTsHM5lcTLB+0ffcpdA IUEw== X-Gm-Message-State: AOJu0Yykw1Brm4+SiGgAihhebow+AGfadwhlnyXQ8D/DDA3q6Lm1c8zo 82e2PdR/1XzccWgkRuJwiL8SC0Z46dKvqj2ZS5M8V+zpA8CW/c38C28xvd9O/5oHoTs14/HRGKa M03BaqXd8viXE+VyoTuzUVM1lc+P6qap6513NmISTApr2Squ2816TM1NQQxRKwo2k3+t/qGRx4F Ds+vxbWhGLHBti1js+QF9faitK+aulwDXuqRCgh1yA X-Gm-Gg: AeBDies4BIqX9DcZeImKbn0RKgd4jwHVyqRUM4h35IYzTQ250pDSOQP17lRgRxT8Wcq DgiYbP79Bq37B0VFFRnrDNCuuCJCl7XFMVH0eYhy/Tvlry0+82c9R/ud9WHvPbOh8qOMXf1uwGy rJdIEAdUiSLBx8KsZ3XqS8uE52IZDzt+mJN3QUvTQNfOK0U9Qwkvbrpo4zp4Urpyskilzy8QtXa 9fqD/+5RINs35MkNCaSkQ3L8dHhyK/E6E5nH+/tiOnjVu9cv7blcjG72a1ndNPYflm5fbzJThF9 UJNpB7NG6rPlmi1y8H+scyhnePXs2QexOdKWy13V0tUmlUsBxTIi0+c090RRShjAzNvDw1FqJuG SUTvQ4e0BMQa7BDZ5LCs77qgSLvmp/iZpBZi32dR064qyRZ0bibK8Wr8RN0cvhRxM2Xs1sD4RSB 0vnmz9q8ogSO6x+pBMMuYBdh0X8ZapjFZ43i7Hj7M= X-Received: by 2002:a05:6000:18a5:b0:449:c5e2:a8b7 with SMTP id ffacd0b85a97d-450060571bemr3031263f8f.30.1777963768996; Mon, 04 May 2026 23:49:28 -0700 (PDT) X-Received: by 2002:a05:6000:18a5:b0:449:c5e2:a8b7 with SMTP id ffacd0b85a97d-450060571bemr3031230f8f.30.1777963768482; Mon, 04 May 2026 23:49:28 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: armbru@redhat.com Subject: [PATCH v2 3/7] json-streamer: reuse parser Date: Tue, 5 May 2026 08:49:15 +0200 Message-ID: <20260505064919.177855-4-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505064919.177855-1-pbonzini@redhat.com> References: <20260505064919.177855-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.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.444, 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: 1777963838832158500 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 07:02:53 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=1777963815; cv=none; d=zohomail.com; s=zohoarc; b=FMSDfdh2rXCiYRJPxzrB2FzM07f+z+S35X7QZ2RCXQ//EpKr5qp9O5cZ0ousL1A2BwRNeq4EhhEgOE7KAvqNMyeBwsZd/weNf/I8TPijEY9woNNQEo225DA99T4V5qw47I2kI8RYJ8dul9aK6recyvW2mmBBbHH9ODd9CrO03tY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1777963815; 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=AfrrwrN03JoDX1UHDEy1542TbBdn4gexX/B54SPADws=; b=dm96RiMD6d2xTVhRVpPNkavCavVnqMb+NAF8xCON29cuVIoOTzqNUdU2GGnJ7OuS8+Ybl6o2oLWpuOjUROZvrEd1Z9gVaTfu+FkZtTR7gUCiDrGOcEDyogIwuWuP5LCFOX9BXyGXW5/79VtixQyzHuHdwBsv/GVL75sqN0cOIhs= 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 1777963815905417.3957746163121; Mon, 4 May 2026 23:50:15 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wK9bS-0000E4-RJ; Tue, 05 May 2026 02:49:59 -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 1wK9bA-0000CK-CG for qemu-devel@nongnu.org; Tue, 05 May 2026 02:49:41 -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 1wK9b6-0005xr-5V for qemu-devel@nongnu.org; Tue, 05 May 2026 02:49:37 -0400 Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-694-m8YQn6NxPZyHbvU2_NdsdQ-1; Tue, 05 May 2026 02:49:33 -0400 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-44a3aee3813so1955376f8f.3 for ; Mon, 04 May 2026 23:49:33 -0700 (PDT) Received: from [192.168.10.48] ([176.206.106.181]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45055f2487dsm2158730f8f.35.2026.05.04.23.49.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2026 23:49:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1777963775; 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=AfrrwrN03JoDX1UHDEy1542TbBdn4gexX/B54SPADws=; b=CvkpkHzZ0odCBbz0SuNaErhv1xCOFB+8o4e1QsDbcybVkbB4mYWWoRApXzP8Vki2OehQ2R GqdGn0mnRNGRvfm3sW+JAzFhTHFtqYfp3uR5uPtzhLilBfeo+nc/o7lDKgCxwalob3LlAs QphRiaoYS4ErQ43pMMgfr4p0COREwxo= X-MC-Unique: m8YQn6NxPZyHbvU2_NdsdQ-1 X-Mimecast-MFC-AGG-ID: m8YQn6NxPZyHbvU2_NdsdQ_1777963772 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1777963771; x=1778568571; 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=AfrrwrN03JoDX1UHDEy1542TbBdn4gexX/B54SPADws=; b=pm+WHvJhl/D3/bY22jH+FDjdr63wvAsf4DmYWVI2N96IhB2J1uatWJIe/JQjm7Yc9s OOc9O19D1CoQes20/44ARQf/hxaQ6CSqeIfxENB7iNJmqMKly6moHeMCHnk678ibTVFm zDnBnGrg7f94IKgD7TLaiFM/NHVxiOLcnNd1Dqb8Oeu3qHgLK74NMZGNMg3qM9lT0qsF ZpkVWhz43ZKUAJrxOyQGbDLxwcXrZ6sq5Av48uQT60uTjwJpgmYGLR8h5c/bdhnY/UnJ 975bl4q8QTLhjio5GzkW/rmQJrQ1DqiA/gcNlYGeG/m7a5jgoSy2f/F/FIc91BZgkugn xTzg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777963771; x=1778568571; 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=AfrrwrN03JoDX1UHDEy1542TbBdn4gexX/B54SPADws=; b=quQSBUUNGguwXxNn26nf9WvNcWVzfNakNniMTtau11ykOy+7eLhMqQiTf+j4VxZ4Tl 94R7R2JfTo64Kv5BnDzWLTo1zIQmWZcewkgmdfQ8P7eS+70jTKnW9uhP9SpE8lds4fws tCPkFMSzbncz7e3OQGPo9iNIltn6vgheKuxA0IwagJFst8zKQEX2w7aP2ko4qLNHYu/e ETat2+jSVExu56g8shPDfTCjzfe0sLM9rHMS9EtK/G19gHobV1LT7ylVsVrgBtyWofHv b+CxpqHLDaqVo6h7KFlfWP6X8sogCYed6coO43+SCLFSj0G3IMdqVNngPJuwklvjMa54 eHwQ== X-Gm-Message-State: AOJu0Yw4MGcAc3P1qxbeZwHzrucaBsiD5SegUIJNy87/0Q5SCn/ALEHT yBsTOhLv7kHQnhD3fHPISTBvZcv/XI9mZP3+2CYz2LeXu5T4xIwuWkRqqvXMr7Z4Fh3C6qR8q55 P86PhC/Y5ZDkR44zrXqQvwJR9g5a2XfyuHfOmwWBNNO8eCVtMT+Bqx0rPLsL/t39SyrSqunfGV9 SDjJFpBRHpNccGpF/Ota6u/IZTWcEPZJx5QwPrTtmT X-Gm-Gg: AeBDieuj4nGEH+GNgI/CXDgwRkKR2kaOctmB1NYzBRvFzgNnTnIYrthXHiluT+G9IjJ 7DVe4KaisguWX4+QY5OmJczM38liU681TQ+DFBldE04/fch1gShHV9md5KzDjABAqaKwvkcRfcH b9evo/kClTG/avvILgPL+eUDT02tqGPchpM9AqtZRT4ynL/0JAhfOWDCwf2ood/pFN0rHcdN2Yn 1h2mXqCljVHT5PRqTaqjGejQVlJ9n8q/JLFQqVeRk+0nnBT6n+BuH39+SH//Ks2EmgD2Mwg91fQ oDzHCUSbRqaGJulZJzlT45FpnZUGfdrxrj+tHxbYdSOY2qDOO8Ljjlxdzs4F4bgOdhEhEjnf3f/ awNxKY86Tl3e3S/NVY2joa2+vF3gjjWw/FSubzq44Yhnp71tVYZybasrGbyplorftBIPkzso+L6 bzWiPD7SFLIGU8N4RdRnTJ1clttl6iZv7srBojCqE= X-Received: by 2002:a05:6000:18a5:b0:449:a07a:967f with SMTP id ffacd0b85a97d-45005a97b08mr3084239f8f.28.1777963771661; Mon, 04 May 2026 23:49:31 -0700 (PDT) X-Received: by 2002:a05:6000:18a5:b0:449:a07a:967f with SMTP id ffacd0b85a97d-45005a97b08mr3084200f8f.28.1777963771186; Mon, 04 May 2026 23:49:31 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: armbru@redhat.com Subject: [PATCH v2 4/7] json-streamer: make brace/bracket count unsigned Date: Tue, 5 May 2026 08:49:16 +0200 Message-ID: <20260505064919.177855-5-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505064919.177855-1-pbonzini@redhat.com> References: <20260505064919.177855-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.444, 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: 1777963817070158500 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..d400e3814fa 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 07:02:53 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=1777963815; cv=none; d=zohomail.com; s=zohoarc; b=NVkX7AS6UMjO0AFiv8RLVEVvuzwm43wMCP9cCpMV5QIvvQ/V2SMgEBTcCJgwLAJzTTG7u2vJgimAfhKSDbA59t+i78e3LIWYVzaH4ePp1DQzbNfl8I2AoVDhpnDXdLAdXQpIVG++9uboZXRMDqPOBEo8h+LwQMAsMFSgjxZMyiI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1777963815; 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=GAFLgNMvcSnlXSKkNfRXd6OuUhnFRvE1krLfdKSFa9Q=; b=cagTM7onzKCs1UkEVKc8UMMMq2iSwQbuJ7kTQ5S/n7Z2EbjB4FSgSEsGRb6a+Asl5LJETucwFn14dtdy2nvs21h5s4DsMeeQ2dxRLpIB1adeYWqFhkEH1LjJIk2/B/UmKZF6LqP/tReYP026sv375IvlsUgxW0pblRbabil29ow= 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 1777963815733397.00890330589255; Mon, 4 May 2026 23:50:15 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wK9bT-0000EY-De; Tue, 05 May 2026 02:50:00 -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 1wK9bC-0000Cn-Ta for qemu-devel@nongnu.org; Tue, 05 May 2026 02:49:43 -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 1wK9b9-0005yK-DZ for qemu-devel@nongnu.org; Tue, 05 May 2026 02:49:41 -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-531-8XDxV6O6MtKv2c_Llc7BHg-1; Tue, 05 May 2026 02:49:35 -0400 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-43d7a5b9678so3919340f8f.2 for ; Mon, 04 May 2026 23:49:35 -0700 (PDT) Received: from [192.168.10.48] ([176.206.106.181]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45055e2d3d0sm2027855f8f.34.2026.05.04.23.49.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2026 23:49:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1777963777; 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=GAFLgNMvcSnlXSKkNfRXd6OuUhnFRvE1krLfdKSFa9Q=; b=FlRBmWW6vaG49Cmp9A2PGzSBHx6G177QrtNvhWsVf6dSSdukj/LHiW+oweqSWDaysPzKG7 Lp6VfIeUbOfZv18R9gBgdsyr6ANYZHEtxhuaMCs9df8uyg/Bu+bEiJXTM2lygHg86px4vf YJg3lGTmkEUfufojcyGzrq7HEWPLglA= X-MC-Unique: 8XDxV6O6MtKv2c_Llc7BHg-1 X-Mimecast-MFC-AGG-ID: 8XDxV6O6MtKv2c_Llc7BHg_1777963775 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1777963774; x=1778568574; 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=GAFLgNMvcSnlXSKkNfRXd6OuUhnFRvE1krLfdKSFa9Q=; b=TZtdCkt1jWtgNiI2CMvPP8rSm2uwGu4pUcmL5txVkjDaRGKpsvqTstlWsfIlJXROvM E4pNmf1JPEcM2fzW8u/XvplG+kg1P087UuRvYT5rt1IBzXvPJ24XteJEQGNwlllve8U1 Rf8u6DzTYJVJyKzqDAHBH8nqr7nNyzzAa9J7wk4VTPIIRqC+3GougH1hYS5H5WmkulAi tSDKGRtjEwqfQdKlQ/En9BXcCPRAg17vgEjKC/gdLTxF9lBxojPhDmSajca1OIvR4A/H 8XzNePJmM+vypAcyRdC5wVUpdBVWwQDdRQWrgL5Z9iRuZ0yonGqVCkgG9vQ50j6ulA2B xAEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777963774; x=1778568574; 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=GAFLgNMvcSnlXSKkNfRXd6OuUhnFRvE1krLfdKSFa9Q=; b=J1xobi2I5FkHuJKecME2jsDj2tauzg0AZjD2FgR6T4Ftjh5BVPCoxKcrLtDOi29Idc 0J6cOLomVFhB9tyvjKDvMPC/q1p+t3d1PN/Z/ahenzwCWmbQ7rW3Zs+Ypoueb4qXgRFb UDZIXDiMTgfO1GaLQmUm0ZmfnEASWeCijZL/9TtTeMdqm1cXnJxD7fokMNVgLMb6ylhV 2uIVf4aNSOMNepf544JZ2UAPZCyWKqyiqiFEOJgf3dFuNUAaP8XnX9qDWWscl8k0zhSy pa8+7E1PvSoGkOxJWK+JXKZxqqYUJUFtmFIYV4VrGifS33CITNJcAeDWNEm+nLVYDt8Y sQew== X-Gm-Message-State: AOJu0YwfklQcuicjyBWS6HDk1Er853ReBYUY7tOvJ/hzePMo3MU64eBq WfnAu1xr56fiNVNJaSBKW3RE5omv/GSqv5xfM/yCUGnNKIgDym+wE3aelEu26RzaBrQqfGunSBu CJ8+7kSc+z7bUZbxwWnBok+8B8SgX5GxzJ0psZbbVItgvMrWOM55/IiPvr8YVMBUoZ2nnm+ge8m TPXBPCx5WJr+1DqQLtrG8/g7EDLsBfvCG/5lwVtz+5 X-Gm-Gg: AeBDieuRoIPjKqT6niT9wf+4lN2WdW8Pn1R9EXs624cPuJhHcMB76GBt/MuNCOwjB09 155dFpUMdCLbWeYxYLKz69GZfGYAPoE6kM9iq1GY/PgzHcwNsNQgUq137emUblIiVn3eu9Cf8iY LxEYVa8J9UYw0C3qQeBDvpf3qMwaLhAHqz3afNpDmw37HazeClIQdSswyRiwxk/Pp2cqybxLoVV 4QjSPQzxHvkAYlXBLu0wnI4fUBbWe8ssOKacAgqW7HI2KserYubcHBZMOQGFyStdaFzbwBAa8cG UCibGB7qo8ja9jKgTIhPLwEIfa5SvN2AZ2Xu2yQygnVIwOqlFi6/U/958AxRlSZ0h7izdN6w8VZ tUhRwZJspJtMkq6ewZcrpAaBPxhzR9LOSbjZ5KMM6FsIupJbqSysXtDGJANX3t+hOxPYN1wiQz3 Mlw9crimROXFkWF5LJdG2+Le8M20A+ntw7BI/b4SI= X-Received: by 2002:adf:e902:0:b0:44f:d9f8:bb9f with SMTP id ffacd0b85a97d-44fd9f8bbf3mr3255503f8f.43.1777963774252; Mon, 04 May 2026 23:49:34 -0700 (PDT) X-Received: by 2002:adf:e902:0:b0:44f:d9f8:bb9f with SMTP id ffacd0b85a97d-44fd9f8bbf3mr3255477f8f.43.1777963773773; Mon, 04 May 2026 23:49:33 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: armbru@redhat.com Subject: [PATCH v2 5/7] json-streamer: remove token queue Date: Tue, 5 May 2026 08:49:17 +0200 Message-ID: <20260505064919.177855-6-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505064919.177855-1-pbonzini@redhat.com> References: <20260505064919.177855-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.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.444, 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: 1777963817586154100 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 df103b4666c..93ad48361af 100644 --- a/qobject/json-parser.c +++ b/qobject/json-parser.c @@ -656,6 +656,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 d400e3814fa..bc223053828 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 07:02:53 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=1777963822; cv=none; d=zohomail.com; s=zohoarc; b=M64DZ+AR9dIElCRMYL5jqW3WuIEVqx//Ic+L4EgnyjiyQvwBGCOLVjBj28RQMpkwLrXn/ieFTCqbju1mgKPcAXpiA6KWnpQuzCj4/zRxeS8ta6ibEZx+dhjzpEqceN5X8u45SOcgqovD02ABqaaMlPZksO1j5riMaxrodwPcVWg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1777963822; 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=K9Zty9QPvafc3EO/rY42r/T0cheD7R5WL7hpe0gpaW4=; b=D9eQB4AsSSkl0z73I+SABspgZZPrbLQALF8XhFJT2HqTBiLn5cGuS+LHOmDfdTKvMMtICAonWkV0e360nNrrOSCxsmSHHCKebrbJt2jZYTLzx2o5ph7fEIc6/RIe/lVK2bfopv3A1ENc1ywd4qA33xVLEEYiYi5rcpAH7gaxItQ= 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 1777963822154681.0542638153509; Mon, 4 May 2026 23:50:22 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wK9bU-0000Eh-2j; Tue, 05 May 2026 02:50:02 -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 1wK9bF-0000Dl-HJ for qemu-devel@nongnu.org; Tue, 05 May 2026 02:49:51 -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 1wK9bB-0005zp-Ip for qemu-devel@nongnu.org; Tue, 05 May 2026 02:49:44 -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-192-P8P8HpqSPu-vCU0q0-8glA-1; Tue, 05 May 2026 02:49:39 -0400 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-488ba2f4094so34764355e9.1 for ; Mon, 04 May 2026 23:49:38 -0700 (PDT) Received: from [192.168.10.48] ([176.206.106.181]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-48d14786d8csm12392455e9.0.2026.05.04.23.49.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2026 23:49:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1777963780; 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=K9Zty9QPvafc3EO/rY42r/T0cheD7R5WL7hpe0gpaW4=; b=fAtt60eJ6DTX1bdtBPcw4wI9OuAWDdAPMRG9+WzgKyvH8sF0yR/VztRoa6eKUrGbJiaCcR Us+zU0QLuEZiZFRUsymIWTHtwh3DktANRKAk7Xv9/AgtjbFPCvGSwSUKzAgJDBosKG9UU7 Wzbd8xqMyyfV5PMVIuuMbOkkJOK7F/U= X-MC-Unique: P8P8HpqSPu-vCU0q0-8glA-1 X-Mimecast-MFC-AGG-ID: P8P8HpqSPu-vCU0q0-8glA_1777963778 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1777963777; x=1778568577; 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=K9Zty9QPvafc3EO/rY42r/T0cheD7R5WL7hpe0gpaW4=; b=HpUQPsOAU+mgsc3fZ2Dnzw08kDgaeDxJ3Sw52l175P6ermv0d0Br4k+z8lM+/aHCcX 8r0l4amYNx6Hh6V2FChl76525Jyi+8e9DSESX6tg5trz+0DtRqLoWirnJ6869xPzhFcM sgD/oijwA590aVUpWa5Qukli26kXTfMnj+/OCQDNzzkZb1sAiqQlKBD3ga+M1c/QT6vT FAyrxpn2L3jAr0/NEDMda61TXvKkCFghpB8+ZzpBhoKeLb3pKymnUGc6aR4c7YYhY0aL TBMn5wKXEu9d9LILk4ZdGD5dY3jF2VwCDgKt18R1e8xaT7MvxGJ2ed6BhuUOtOynBBs+ lHZA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777963777; x=1778568577; 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=K9Zty9QPvafc3EO/rY42r/T0cheD7R5WL7hpe0gpaW4=; b=T4CDYTLRbARqZC2r6A2tjRzocUVlSFmn/16EOyL8sSu3dW51yWow08iw82yqhYVRpp PQPu7bn+TNgcsEH1pAC1DavrK7LZFKgFFHTz0QZh6dtX5GlaE3+LaP5B7Hj34S61RC+c tCfq3peiV0apqhdnln3oEZALKATsOSLlxG+2RbVFZrO94QsZlTYdgiTXcXrzt9vXoO1a MkrO+gF+fejCct2vq3rowH54VGM3ehS0glfvXYF6Ek/7lBuGZR0D/xwfMLPovoHIgh0Z weXJnUJTXw0u2barV9QwByDgAkzShTIVit0wNDKafOPTBpdgPyGrIVAkDW+798WMNdXy tPbA== X-Gm-Message-State: AOJu0YyoiQXnk+2OFd3zRB0Cb2o+I1MpGRttZpZsufSLUt7nMUNzxdto 2lOOg88AQvvz88iSmuPFA1ooYChnR3wCKUEEu3Ve6RMmNwMvlNtZZOcBHlD3nLWSzyM4/b1opkf pYUvQp/D9u1ExsMhhzivuZN+90BdUEnN9duevlxuz4ARDJSKHdkB8ImJ+UXxxtvc0iJ9c1OvSDl OAqjGYeCCfb9LAj8cKDnPFmFSBCCsGaA6vVdXzIfYv X-Gm-Gg: AeBDievLyYWA9s8mfMYPZX/PmTHdmPiG4HC1WknSY1jHNr3y05yRBPpVGaQdXFw9mHB lF9QEJ/CL1WepRXDXpok/Qv23y+QLyxaOPWcIqzyA3J+nKmJYaO2/5Tn7FEMs0IuiQjauFcbr75 CNBqqVThE3lXNNZMQNfG/gJqqsr9sb8RJy+HT3/clSSiYqaovnsaJBv2HQLVxypSpE8ivop89hE 0XSr3vl0FZPfdUsdMHelE7GB+DFQrc1zqZZzgeB6ehcHiWG2J9DxoegGnf/EtEwmnqLhGmceVKp +pL+KAqa+mrOt/E28HcVYRU4t9vP0sh/AXg3o/LTpL33qmBlF222OjlV+uIMT8pS1FMzsyj1wjE Zysp4LAP0K8RpijEz/64jG5Rod0PNTx54tr9RZ5u6yv3DcgfILpzETMqaH9HDzEObkdrxaBtVI/ saSsQbC0CUv2VXngeUfMybqzdhT62nNmsh0OiQLRs= X-Received: by 2002:a05:600c:a46:b0:485:3ff1:d5ed with SMTP id 5b1f17b1804b1-48d186dc7c6mr25544755e9.1.1777963777048; Mon, 04 May 2026 23:49:37 -0700 (PDT) X-Received: by 2002:a05:600c:a46:b0:485:3ff1:d5ed with SMTP id 5b1f17b1804b1-48d186dc7c6mr25544335e9.1.1777963776585; Mon, 04 May 2026 23:49:36 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: armbru@redhat.com Subject: [PATCH v2 6/7] json-streamer: do not heap-allocate JSONToken Date: Tue, 5 May 2026 08:49:18 +0200 Message-ID: <20260505064919.177855-7-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505064919.177855-1-pbonzini@redhat.com> References: <20260505064919.177855-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.444, 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: 1777963823420154100 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 93ad48361af..7bf1a81af86 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 @@ -606,17 +599,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 bc223053828..c4395f865f3 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 07:02:53 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=1777963840; cv=none; d=zohomail.com; s=zohoarc; b=iwW2exJyjnsL9ctRsOrJeznScBUBEp/gzORjBckkSHafnaY9OZqIdtJ06O1uXM2L7pTUyEFINkN++aASKpvHO/D4r7Yhl+2+ELOjzVHyaxisqNgb2jHnejTQRrwMvUPAIuGooXnf/kYNeN1QRW9wpN++WXiV1ryhQy9jdC/GK+Y= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1777963840; 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=RVT0tnJmjgmnhqKsD8dcnUu8DxkM2B1RNvvxkw4xAcU=; b=OqA9lwtSH+m/cL17Z8B/C3Pjq8/MZpat9IfF6ahjQvsKf7Xy0zS7qZqazk7NiQLEGABKmsODb6HrWISY2rbGDMiG5DXBh9xeeq8e7mRpKbr/6KgmY2z5ccwj0QRycq0caYb/ADeym61+jBG/DN78BRR1SFm+3KJS5K/4qrn949o= 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 1777963840315980.9862664303605; Mon, 4 May 2026 23:50:40 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wK9bT-0000EX-4F; Tue, 05 May 2026 02:49:59 -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 1wK9bH-0000Dm-Re for qemu-devel@nongnu.org; Tue, 05 May 2026 02:49:51 -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 1wK9bD-00063d-7s for qemu-devel@nongnu.org; Tue, 05 May 2026 02:49:45 -0400 Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-547-05y1N-hUMoaEdxF6h_msZg-1; Tue, 05 May 2026 02:49:41 -0400 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-43efc93e4f6so3718634f8f.3 for ; Mon, 04 May 2026 23:49:41 -0700 (PDT) Received: from [192.168.10.48] ([176.206.106.181]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-48d14d1b4f6sm11598395e9.12.2026.05.04.23.49.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2026 23:49:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1777963782; 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=RVT0tnJmjgmnhqKsD8dcnUu8DxkM2B1RNvvxkw4xAcU=; b=DgGKbZAnM/hR1YpZuAbwE3W9BOSgO5q6FHi6kEWD0cSIRRPZ+Hyk5fyqyrC6ax4/eZC0SJ n8ESWUEjreY3vuysBrEfT116NI9eO+D+Vr/FGsu2e1ctGg9FS8qKqAEV5YTLm7IgdQ1NfM WSX9+X7bTrQPZne0znVBBeqmHwtcyJ8= X-MC-Unique: 05y1N-hUMoaEdxF6h_msZg-1 X-Mimecast-MFC-AGG-ID: 05y1N-hUMoaEdxF6h_msZg_1777963780 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1777963779; x=1778568579; 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=RVT0tnJmjgmnhqKsD8dcnUu8DxkM2B1RNvvxkw4xAcU=; b=PjfATBcAzVo1GVmeEhWOMn/N69267OVaexrxU/2gHo6GM2nhNi4Wxf3jLIES4UMHht 24xLe6JnWtU8i2xTRPdoiop41ITUJqi/74NKPe4gdS+vIx2orEXovWVsc/0apjG96r1X xZUy01Wz+3x0gnBw/ra0alZuCnlfEIH6v0vfi6J/tb//WFolwL2xQ4H+9DXNtrnngD2b cghoaxztDu5UlWr5/hu+Dq1kHGIL4GcIg+aHPnPG718m6rRqbdadWzIj5pNdpjnFcSe1 5vGfjutWH7ewvaneQWd9tAtL5fNiuBxix3VOeWPGvEpkooQPHvzFo9bNhsUOttnkl+oa ZCGA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777963779; x=1778568579; 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=RVT0tnJmjgmnhqKsD8dcnUu8DxkM2B1RNvvxkw4xAcU=; b=MX0gNw/IROZceQwpZxbwt1cx5ABWhy8DbrYPyk/zfz8zrYq1VpgJSZr1K34nmA1RxK F46kH+JRK9jLwM8FICwOSXQMTWq9E5QWSP7ASuCAA1mbCVdK3FFWItQkIUJedQXXWPQF GvQ0R2+X0nMwXIWgYI2S8/FL08SGrdPPk5I+mpxBptUyEpQz0z/dAdf5fnrJz1p48Dd2 /4Xv+wOVwUX9PGbGnlPKtUbDhu8IeAYr0JfihyssGA4F9Uh7aMl1Z+iqWtDIbNkfIeF+ wsbLy2zHq1YYy6J+Oj5o1DWjblwnQDKU1dydQACrsqKnXnmAF/L98nwEWkH2Vr6tz9q6 l8dg== X-Gm-Message-State: AOJu0YyhvYYNcuVwPulRPZCVWP602iZFKfESqnU+acsNg+/9mJaX4ks/ RGCFxJJLE1qdL+2pRKkCqe1sr0FOq21RTwe4HNsle3HgNZ4qm9hAW5OCqVKnmvhAeiLzKviCA6+ igJ1VBWFy97zeUbH3JvxVYkC/ZsRq0yOrxbQBUhs/mF8YxW3Inn6hnS4jnzSDM8zAGnzyQJhcqF 4vK2xCjsYBP1YHZZy0BEU49uVJRejknQSJxpusY7BO X-Gm-Gg: AeBDieuqzWrJQwUUAQl9KemHLGjdk3P6ak0wSRfm2yLDNw+9liJEzfoAv/ilhl7uY2W qnpQhErd1q2dLiTKGS6uyuNb4jsSxdXcuCUICVQ5S3mjxhzEbgToJD1TCAiGZQrOTqTX+BE0SpH +D0NX0fKyajlLLXLb5oDGMRSVQo2XCKykDUOiQXpRKjIIrw5cqDwEMdW6SJ/FU7+7GAI83xxxWY lvARhuifmd0KhAN5xhLLd2ryxs+jiC6kNz7mnb4A2D9gc5j3X2wVeWwtNP1ALKDdzQSU2lO9Uyp b4M8jBkVy6PMOtzRUMTjmveFsyE1uDXU15aswgAUOb84KVWdJmdVBT9a8QYnB8nY5HjlUdSLMuS 7wXuoqIe4a6rT3NtYz6szP25WZr7u0w4PWme2owUWqHBu5uzK6SZ2jtHcllEdaBrp38bAEaKcDk hHHC2KJj3NbmPD1Bvj4QWTZ3GHRB0imUn3J/IDyAw= X-Received: by 2002:a05:600c:4e04:b0:48a:906a:9050 with SMTP id 5b1f17b1804b1-48a98638cebmr218946325e9.10.1777963779296; Mon, 04 May 2026 23:49:39 -0700 (PDT) X-Received: by 2002:a05:600c:4e04:b0:48a:906a:9050 with SMTP id 5b1f17b1804b1-48a98638cebmr218945795e9.10.1777963778688; Mon, 04 May 2026 23:49:38 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: armbru@redhat.com Subject: [PATCH v2 7/7] json-parser: add location to JSON parsing errors Date: Tue, 5 May 2026 08:49:19 +0200 Message-ID: <20260505064919.177855-8-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505064919.177855-1-pbonzini@redhat.com> References: <20260505064919.177855-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.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.444, 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: 1777963840766158500 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 7bf1a81af86..1ae90434c97 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