From nobody Sat May 30 17:44:36 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; 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=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1779312416; cv=none; d=zohomail.com; s=zohoarc; b=WKz8f6j71sgoV6bWRF7BqLTB2JbEnB54csCn0/K3k9tHT6pFsJDJGVDldCf32RA6SDOat9v9abtRx7Gadqam2NIZ7VF17xwZtIs0VIkSUazrkn1fvsVu74HWusCczhBMeOmjx/pvNDJ5UX/Pd0MPDmReV1+3NNIEnsbSF5PsDO0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779312416; 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:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=C9VDCBZBoAIEzbXAJnmyhl/vTrWXdh18LhUxlVY1cCU=; b=eaxJNvaAVxtS+nEYsQgqkqsj43ms9XPKCGT44DtMF+v7t8yhVyso3nz4UHR/NlQJPe4DD9kaA1Vr0Ns3BR5hRtAHSxnOF7+mnmIm+/p9lTpXH8FFnQDlX69UsKqk72kzKB0j2BM7UpUts9OOu4ftLCbLeq7sqWYvvCMSwrbUrX0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; 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=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779312416351745.2040053195635; Wed, 20 May 2026 14:26:56 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wPoR0-0006iD-MP; Wed, 20 May 2026 17:26:34 -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 1wPoQz-0006hy-7B for qemu-devel@nongnu.org; Wed, 20 May 2026 17:26:33 -0400 Received: from relay.virtuozzo.com ([130.117.225.111]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wPoQx-0005YG-CN for qemu-devel@nongnu.org; Wed, 20 May 2026 17:26:32 -0400 Received: from ch-demo-asa.virtuozzo.com ([130.117.225.8] helo=iris.astra-academy.ru) by relay.virtuozzo.com with esmtp (Exim 4.96) (envelope-from ) id 1wPoNa-003Cdo-0d; Wed, 20 May 2026 23:26:28 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=virtuozzo.com; s=relay; h=MIME-Version:Message-ID:Date:Subject:From: Content-Type; bh=C9VDCBZBoAIEzbXAJnmyhl/vTrWXdh18LhUxlVY1cCU=; b=KZcyV53G9D+X FxMKO6vNeBJy2XcZieLiR8QrvEsPwpF2lC3WnYITFCpTJnUbiHAeSeERLvKmFmnLC04zWRIqVnwbc Qtb0wNXjxqWZH7nr9hoN1RaWA69bjpCB4mVo0XjkDneqj9Kp/vUNa+LjviuY00bWeZe11aidcppmj fHfhDIO3Tk3fS8BC9pOobCM8oPMzCqrsXL3honoRIvcijB/H/MAlbJxoy8rrPSMBZHOcsO5TCeZA0 s0TPRT9A9XS0oDluUsTMI8y0l9SfNwAkRDRCb1BUy9XDmrE0R/9aWY++AcGGW1/+CReCNHOe2qHDe +v6Ek3oq/b0lHRPLL5yEzw==; To: qemu-devel@nongnu.org Cc: den@openvz.org, Stefan Hajnoczi , Markus Armbruster , Paolo Bonzini Subject: [PATCH 1/2] util/envlist: fix prefix-match in envlist_unsetenv() name lookup Date: Wed, 20 May 2026 23:26:27 +0200 Message-ID: <20260520212628.479772-2-den@openvz.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260520212628.479772-1-den@openvz.org> References: <20260520212628.479772-1-den@openvz.org> 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: softfail client-ip=130.117.225.111; envelope-from=den@openvz.org; helo=relay.virtuozzo.com X-Spam_score_int: -34 X-Spam_score: -3.5 X-Spam_bar: --- X-Spam_report: (-3.5 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_SOFTFAIL=0.665 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: , Reply-to: "Denis V. Lunev" From: "Denis V. Lunev" via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1779312418646154100 Content-Type: text/plain; charset="utf-8" envlist_unsetenv() looked up the entry to remove with strncmp(entry->ev_var, env, strlen(env)). The comparison length is the requested name's length, so any stored entry whose name *starts* with that name compares equal. envlist_setenv() inserts at the head of the list, so the first hit wins: with FOO=3D... stored first and FOOBAR=3D... stored afterward, envlist_unsetenv("FOO") iterates from the head, matches FOOBAR=3D... on the prefix, and drops it instead of FOO=3D... linux-user and bsd-user reach this code via the -U command-line switch, so the bug is reachable from a normal qemu-user invocation. envlist_setenv() used the same strncmp pattern but with envname_len =3D (eq_sign - env + 1), so the '=3D' byte sat inside the compared window and acted as an implicit boundary. setenv was therefore not buggy -- but the safety lived in the byte layout of ev_var rather than in the entry, so a future edit could easily drift the two sites apart again. Store the name length on each entry at insertion time and compare with explicit length equality plus memcmp via a small helper. Use the helper at both lookup sites so the boundary becomes a structural property of the entry: envlist_unsetenv() stops prefix-matching, and envlist_setenv()'s self-search no longer depends on the '=3D' byte serving as a sentinel. Fixes: 04a6dfebb6b5 ("linux-user: Add generic env variable handling") Signed-off-by: Denis V. Lunev Cc: Stefan Hajnoczi Cc: Markus Armbruster Cc: Paolo Bonzini --- util/envlist.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/util/envlist.c b/util/envlist.c index 15fdbb109d..196c92c190 100644 --- a/util/envlist.c +++ b/util/envlist.c @@ -3,7 +3,8 @@ #include "qemu/envlist.h" =20 struct envlist_entry { - const char *ev_var; /* actual env value */ + const char *ev_var; /* actual env value: "NAME=3DVALUE" */ + size_t ev_name_len; /* length of NAME (offset of '=3D') */ QLIST_ENTRY(envlist_entry) ev_link; }; =20 @@ -12,6 +13,13 @@ struct envlist { size_t el_count; /* number of entries */ }; =20 +static inline bool envlist_name_eq(const struct envlist_entry *entry, + const char *name, size_t name_len) +{ + return entry->ev_name_len =3D=3D name_len && + memcmp(entry->ev_var, name, name_len) =3D=3D 0; +} + /* * Allocates new envlist and returns pointer to it. */ @@ -67,7 +75,7 @@ envlist_setenv(envlist_t *envlist, const char *env) /* find out first equals sign in given env */ if ((eq_sign =3D strchr(env, '=3D')) =3D=3D NULL) return (EINVAL); - envname_len =3D eq_sign - env + 1; + envname_len =3D eq_sign - env; =20 /* * If there already exists variable with given name @@ -76,8 +84,9 @@ envlist_setenv(envlist_t *envlist, const char *env) */ for (entry =3D envlist->el_entries.lh_first; entry !=3D NULL; entry =3D entry->ev_link.le_next) { - if (strncmp(entry->ev_var, env, envname_len) =3D=3D 0) + if (envlist_name_eq(entry, env, envname_len)) { break; + } } =20 if (entry !=3D NULL) { @@ -90,6 +99,7 @@ envlist_setenv(envlist_t *envlist, const char *env) =20 entry =3D g_malloc(sizeof(*entry)); entry->ev_var =3D g_strdup(env); + entry->ev_name_len =3D envname_len; QLIST_INSERT_HEAD(&envlist->el_entries, entry, ev_link); =20 return (0); @@ -119,8 +129,9 @@ envlist_unsetenv(envlist_t *envlist, const char *env) envname_len =3D strlen(env); for (entry =3D envlist->el_entries.lh_first; entry !=3D NULL; entry =3D entry->ev_link.le_next) { - if (strncmp(entry->ev_var, env, envname_len) =3D=3D 0) + if (envlist_name_eq(entry, env, envname_len)) { break; + } } if (entry !=3D NULL) { QLIST_REMOVE(entry, ev_link); --=20 2.51.0 From nobody Sat May 30 17:44:36 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; 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=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1779312427; cv=none; d=zohomail.com; s=zohoarc; b=BKW8E2+ssq2LXEaaOGtAzaGaRmI2T8LqYjzSzK2qrmM6ld/CSvLgmfxlIARGtfqXNeBEhGzH1a56LtVJgJAiwYe6ERnIJ5/jTAvH78d6xpXU7tBwKhZv+PmE6sFhd/Yu3cUiXHmsTwah+8pMuDRQWjGE7P3wfBBvvLr/EoYZDis= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779312427; 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:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=pH2FUvyhi+mHii53FUt0c0qNEmmfH14JumiyrbnsBpg=; b=OB5tPcsqlLna4cF9z4NuaxvwG8TsuCFlmYy8y1c77MmlNloRQWJwHvPFtABC45OdfBjK/BhcnlX7AdPNWAczqHerWaHozBFrS0pwBDv+SsuUjv+4/wAeuXbFlBWEtlQkv070LQXEXvBDFzJ9+grkk1WSrwJQqgKJSI744I+5V7I= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; 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=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779312427209399.9049161420901; Wed, 20 May 2026 14:27:07 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wPoR2-0006ix-48; Wed, 20 May 2026 17:26:36 -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 1wPoR0-0006iC-Hc for qemu-devel@nongnu.org; Wed, 20 May 2026 17:26:34 -0400 Received: from relay.virtuozzo.com ([130.117.225.111]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wPoQx-0005YE-AQ for qemu-devel@nongnu.org; Wed, 20 May 2026 17:26:34 -0400 Received: from ch-demo-asa.virtuozzo.com ([130.117.225.8] helo=iris.astra-academy.ru) by relay.virtuozzo.com with esmtp (Exim 4.96) (envelope-from ) id 1wPoNa-003Cdo-1e; Wed, 20 May 2026 23:26:28 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=virtuozzo.com; s=relay; h=MIME-Version:Message-ID:Date:Subject:From: Content-Type; bh=pH2FUvyhi+mHii53FUt0c0qNEmmfH14JumiyrbnsBpg=; b=ELS855UPMeCn UBuRhLm6puBh2wmA79bRrg98JTn61zJGYGadVirHaAm7zC3hU1MHkWUsK1i2dgVmkdBvDghxbYP7Y KBQ5FGMwJ5CvqwRVgvstZ7IqqTuNoLrtDCWHSIa5hwERVDMjYPmMIoRbckRhOi++aVUlNemqhmw6K YcPvpF5oCyZpj1b3CDirWEn/AQffYIVl91lx0jh24i+RNVodiCTxVU4WU9GCb/nc2m6Vba3Gzs/Ki WpmQNvPxU3BgdEOAaqycWIUOsAfJBypxzyqI6dipRE8T+w8U312FgF9ku79OHuMmxEBDF1l8RedL+ sXQ7JEFsvPmBo/zSzoJkMA==; To: qemu-devel@nongnu.org Cc: den@openvz.org, Stefan Hajnoczi , Markus Armbruster , Paolo Bonzini Subject: [PATCH 2/2] tests/unit: add test-envlist covering setenv/unsetenv name matching Date: Wed, 20 May 2026 23:26:28 +0200 Message-ID: <20260520212628.479772-3-den@openvz.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260520212628.479772-1-den@openvz.org> References: <20260520212628.479772-1-den@openvz.org> 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: softfail client-ip=130.117.225.111; envelope-from=den@openvz.org; helo=relay.virtuozzo.com X-Spam_score_int: -34 X-Spam_score: -3.5 X-Spam_bar: --- X-Spam_report: (-3.5 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_SOFTFAIL=0.665 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: , Reply-to: "Denis V. Lunev" From: "Denis V. Lunev" via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1779312428471158500 Content-Type: text/plain; charset="utf-8" util/envlist had no test coverage. Add tests/unit/test-envlist exercising the public envlist API and pinning down the prefix-match hazard fixed in the previous commit: - envlist_unsetenv("FOO") must not remove an entry named "FOOBAR"; - envlist_setenv("FOO=3D...") must not replace an existing "FOOBAR=3D..." entry placed earlier in the list (envlist_setenv() inserts at the head, so the first prefix match wins under the old strncmp rule). Also cover the rest of the contract: head-insertion order observed through envlist_to_environ(), replacement of an existing variable, the count argument of envlist_to_environ(), and the documented EINVAL paths (NULL inputs, setenv without '=3D', unsetenv with '=3D'). Signed-off-by: Denis V. Lunev Cc: Stefan Hajnoczi Cc: Markus Armbruster Cc: Paolo Bonzini --- tests/unit/meson.build | 1 + tests/unit/test-envlist.c | 196 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 tests/unit/test-envlist.c diff --git a/tests/unit/meson.build b/tests/unit/meson.build index de64f9501f..01cc540a45 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -49,6 +49,7 @@ tests =3D { 'test-qapi-util': [], 'test-interval-tree': [], 'test-fifo': [], + 'test-envlist': [], } =20 if have_system or have_tools diff --git a/tests/unit/test-envlist.c b/tests/unit/test-envlist.c new file mode 100644 index 0000000000..53813dd4de --- /dev/null +++ b/tests/unit/test-envlist.c @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * envlist tests + * + * Copyright 2026 Virtuozzo International GmbH + * + * Authors: + * Denis V. Lunev + */ + +#include "qemu/osdep.h" +#include "qemu/envlist.h" + +static void free_environ(char **env) +{ + char **p; + + for (p =3D env; *p !=3D NULL; p++) { + g_free(*p); + } + g_free(env); +} + +static const char *find_env(char **env, const char *name) +{ + size_t name_len =3D strlen(name); + char **p; + + for (p =3D env; *p !=3D NULL; p++) { + if (strncmp(*p, name, name_len) =3D=3D 0 && (*p)[name_len] =3D=3D = '=3D') { + return *p + name_len + 1; + } + } + return NULL; +} + +static void test_envlist_basic(void) +{ + envlist_t *el =3D envlist_create(); + char **env; + size_t count; + + /* empty list */ + env =3D envlist_to_environ(el, &count); + g_assert_cmpuint(count, =3D=3D, 0); + g_assert_null(env[0]); + free_environ(env); + + /* add */ + g_assert_cmpint(envlist_setenv(el, "A=3D1"), =3D=3D, 0); + g_assert_cmpint(envlist_setenv(el, "B=3D2"), =3D=3D, 0); + + env =3D envlist_to_environ(el, &count); + g_assert_cmpuint(count, =3D=3D, 2); + g_assert_cmpstr(find_env(env, "A"), =3D=3D, "1"); + g_assert_cmpstr(find_env(env, "B"), =3D=3D, "2"); + free_environ(env); + + /* replace */ + g_assert_cmpint(envlist_setenv(el, "A=3D42"), =3D=3D, 0); + env =3D envlist_to_environ(el, &count); + g_assert_cmpuint(count, =3D=3D, 2); + g_assert_cmpstr(find_env(env, "A"), =3D=3D, "42"); + g_assert_cmpstr(find_env(env, "B"), =3D=3D, "2"); + free_environ(env); + + /* unset existing */ + g_assert_cmpint(envlist_unsetenv(el, "A"), =3D=3D, 0); + env =3D envlist_to_environ(el, &count); + g_assert_cmpuint(count, =3D=3D, 1); + g_assert_null(find_env(env, "A")); + g_assert_cmpstr(find_env(env, "B"), =3D=3D, "2"); + free_environ(env); + + /* unset non-existing is a no-op success */ + g_assert_cmpint(envlist_unsetenv(el, "NOPE"), =3D=3D, 0); + env =3D envlist_to_environ(el, &count); + g_assert_cmpuint(count, =3D=3D, 1); + free_environ(env); + + envlist_free(el); +} + +/* + * envlist_setenv() inserts at the head; envlist_to_environ() walks + * head-to-tail, so the last setenv comes out first. + */ +static void test_envlist_head_insertion_order(void) +{ + envlist_t *el =3D envlist_create(); + char **env; + size_t count; + + g_assert_cmpint(envlist_setenv(el, "A=3D1"), =3D=3D, 0); + g_assert_cmpint(envlist_setenv(el, "B=3D2"), =3D=3D, 0); + g_assert_cmpint(envlist_setenv(el, "C=3D3"), =3D=3D, 0); + + env =3D envlist_to_environ(el, &count); + g_assert_cmpuint(count, =3D=3D, 3); + g_assert_cmpstr(env[0], =3D=3D, "C=3D3"); + g_assert_cmpstr(env[1], =3D=3D, "B=3D2"); + g_assert_cmpstr(env[2], =3D=3D, "A=3D1"); + g_assert_null(env[3]); + + free_environ(env); + envlist_free(el); +} + +static void test_envlist_einval(void) +{ + envlist_t *el =3D envlist_create(); + + /* NULL list */ + g_assert_cmpint(envlist_setenv(NULL, "A=3D1"), =3D=3D, EINVAL); + g_assert_cmpint(envlist_unsetenv(NULL, "A"), =3D=3D, EINVAL); + + /* NULL string */ + g_assert_cmpint(envlist_setenv(el, NULL), =3D=3D, EINVAL); + g_assert_cmpint(envlist_unsetenv(el, NULL), =3D=3D, EINVAL); + + /* setenv: missing '=3D' */ + g_assert_cmpint(envlist_setenv(el, "NOEQ"), =3D=3D, EINVAL); + + /* unsetenv: name must not contain '=3D' */ + g_assert_cmpint(envlist_unsetenv(el, "A=3DB"), =3D=3D, EINVAL); + + envlist_free(el); +} + +/* + * Regression: envlist_unsetenv("FOO") must not remove an entry named + * "FOOBAR" -- the previous strncmp(entry, name, strlen(name)) lookup + * prefix-matched. To trigger the bug, the longer-named entry has to + * be ahead of the target in the list: envlist_setenv() inserts at + * the head, so we add FOO first and FOOBAR last. + */ +static void test_envlist_unsetenv_no_prefix_match(void) +{ + envlist_t *el =3D envlist_create(); + char **env; + size_t count; + + g_assert_cmpint(envlist_setenv(el, "FOO=3Dy"), =3D=3D, 0); + g_assert_cmpint(envlist_setenv(el, "FOOBAR=3Dx"), =3D=3D, 0); + + g_assert_cmpint(envlist_unsetenv(el, "FOO"), =3D=3D, 0); + + env =3D envlist_to_environ(el, &count); + g_assert_cmpuint(count, =3D=3D, 1); + g_assert_cmpstr(find_env(env, "FOOBAR"), =3D=3D, "x"); + g_assert_null(find_env(env, "FOO")); + + free_environ(env); + envlist_free(el); +} + +/* + * envlist_setenv() must not replace a prior FOOBAR=3D... entry when + * setting FOO=3D... The pre-fix code happened to be safe here only + * because it included the trailing '=3D' byte in its strncmp length; + * this test pins down the post-fix contract that the name boundary + * is a property of the entry, not of the encoded form. + */ +static void test_envlist_setenv_no_prefix_match(void) +{ + envlist_t *el =3D envlist_create(); + char **env; + size_t count; + + g_assert_cmpint(envlist_setenv(el, "FOOBAR=3Dx"), =3D=3D, 0); + g_assert_cmpint(envlist_setenv(el, "FOO=3Dy"), =3D=3D, 0); + + env =3D envlist_to_environ(el, &count); + g_assert_cmpuint(count, =3D=3D, 2); + g_assert_cmpstr(find_env(env, "FOOBAR"), =3D=3D, "x"); + g_assert_cmpstr(find_env(env, "FOO"), =3D=3D, "y"); + + free_environ(env); + envlist_free(el); +} + +int main(int argc, char *argv[]) +{ + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/envlist/basic", test_envlist_basic); + g_test_add_func("/envlist/head_insertion_order", + test_envlist_head_insertion_order); + g_test_add_func("/envlist/einval", test_envlist_einval); + g_test_add_func("/envlist/unsetenv_no_prefix_match", + test_envlist_unsetenv_no_prefix_match); + g_test_add_func("/envlist/setenv_no_prefix_match", + test_envlist_setenv_no_prefix_match); + + return g_test_run(); +} --=20 2.51.0