Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2217873/?format=api
{ "id": 2217873, "url": "http://patchwork.ozlabs.org/api/patches/2217873/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20260330202955.23697-1-sandipkambli79@gmail.com/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260330202955.23697-1-sandipkambli79@gmail.com>", "list_archive_url": null, "date": "2026-03-30T20:29:54", "name": "[v2] analyzer: model strnlen", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "d30111adbb8d4cad9c218b38617a36b07c894660", "submitter": { "id": 92949, "url": "http://patchwork.ozlabs.org/api/people/92949/?format=api", "name": "Saish Sandip Kambali", "email": "sandipkambli79@gmail.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20260330202955.23697-1-sandipkambli79@gmail.com/mbox/", "series": [ { "id": 498088, "url": "http://patchwork.ozlabs.org/api/series/498088/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=498088", "date": "2026-03-30T20:29:54", "name": "[v2] analyzer: model strnlen", "version": 2, "mbox": "http://patchwork.ozlabs.org/series/498088/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2217873/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2217873/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=Y+QA9uOS;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)", "sourceware.org;\n\tdkim=pass (2048-bit key,\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=Y+QA9uOS", "sourceware.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com", "sourceware.org; spf=pass smtp.mailfrom=gmail.com", "server2.sourceware.org;\n arc=none smtp.remote-ip=209.85.214.170" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fl2v84F2Sz1y1q\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 31 Mar 2026 07:30:44 +1100 (AEDT)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 80C1D4BA2E0A\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 30 Mar 2026 20:30:42 +0000 (GMT)", "from mail-pl1-f170.google.com (mail-pl1-f170.google.com\n [209.85.214.170])\n by sourceware.org (Postfix) with ESMTPS id D86644BA2E0A\n for <gcc-patches@gcc.gnu.org>; Mon, 30 Mar 2026 20:30:10 +0000 (GMT)", "by mail-pl1-f170.google.com with SMTP id\n d9443c01a7336-2ab232cc803so23574345ad.3\n for <gcc-patches@gcc.gnu.org>; Mon, 30 Mar 2026 13:30:10 -0700 (PDT)", "from ShreeKrishna.localdomain ([106.213.81.16])\n by smtp.gmail.com with ESMTPSA id\n d9443c01a7336-2b242765b0csm109323195ad.50.2026.03.30.13.30.07\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Mon, 30 Mar 2026 13:30:09 -0700 (PDT)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 80C1D4BA2E0A", "OpenDKIM Filter v2.11.0 sourceware.org D86644BA2E0A" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org D86644BA2E0A", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org D86644BA2E0A", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774902611; cv=none;\n b=oA+HWDWKZ7Js5hbosNc7OnvZMb+uAWdHHahHhbty5SG0QdcWlBQ/aG0rhwsmkYfQKiJ1bBq02OxNUATpcf4WQHNdaBW7aM3IB3IUH5EiOi7gkXIOH5D3KPCy+DclJrnXyCPjXtVzCuugoszB//BzFguTg1Nayepo3mvfQzyTF0U=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1774902611; c=relaxed/simple;\n bh=KiuIjO1qBr0re28Pf2Ta5Vev69Ws3qo/ZMQrVKhImEA=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=x5MbRv1mBC9jC+rZf9vjYwWSXsAzd4DNk7ST3UOClqGv5Sr121r2Bs/8JWe3XKsKEoifjKjtnVdN2xU1RkcfyH+DhBnofM1pP0/ch7ql16QIxJKVY9BkN4w8VLWWTOoG8LkRva2XuIDzqjhgCxIEUMLKbogp6M+gWza4aTuB85k=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1774902610; x=1775507410; darn=gcc.gnu.org;\n h=content-transfer-encoding:mime-version:message-id:date:subject:cc\n :to:from:from:to:cc:subject:date:message-id:reply-to;\n bh=s7Dvxx2IEn4eecTUNOQVMQ3Bd+qMkW+WJmidjdEJ/aI=;\n b=Y+QA9uOSfhQ9QrjU7WSZNDTzCB5MExE2aErIYIAj2PwYMzRw+BI1bSU7g2UeL+0Kex\n ozTG8sTMynBwEhcOgmcvMzi08fuYUr1SsQhJTDIPCSMqHsJjFgoWvxmgAm7AjiWomHy0\n lQYn0PvDrZDf5RZhsbiHsKg4XemU+fNW3LRpfbcjRiyfRkdZWHsjPKMMuyiImNNl+6YC\n KZfmuzBUAOw+xPG8p4E0lwNMoJV1U13Cz49uqQxO/P8r+2nIAVPcBZD9jY0VwO/KG+I5\n 0m+YkVcuGcTnxgrZaqkb4cVRpO2jA4i/+PCeJdCVO0PGVrjcsbJkQlPRjQAFe7FgNzAx\n Ao9Q==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1774902610; x=1775507410;\n h=content-transfer-encoding:mime-version:message-id:date:subject:cc\n :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=s7Dvxx2IEn4eecTUNOQVMQ3Bd+qMkW+WJmidjdEJ/aI=;\n b=hjWc9mNAfwTWMeduxkf6UC85tLgJaM2IbWuxgCPuejp2mz7Xo09YP6aTAMRdcHfHpI\n xrOmxNeuLje16syvu9uzJk0+lKsJkLDBeKXTfSQ8cPHm+q9wiY37XUddsxE65vDcVUZ2\n mDaJC1IIPxc/C809hww7FOb9CS8AUy5qCXITBd3rz998joqjJ5Eh+DT95Cw+BPGIMlyM\n nYW/zdP5dz4AY/6cXTerB1KV3i/pRoGTQ5Y4Xgfe4piOTLdjx/ll1Ng+/dinKu2KTxUt\n lnyyJ8pFEVKQnNZ/sLrc5oZW+GHM01ob84PzOVuN3DgAQoxQ0KAjFqe93KpwW1HfRc6F\n qKMA==", "X-Gm-Message-State": "AOJu0Yx0TC4Rwx7vX1J9f/LQ//bt9kJpJ+eLLFkww7Uo3sDWrnTOkwyz\n Un42OBshEXyRsvIx8+S0kjAYCl9aumlvgmW0CcytBcBEshoeCW4nAdMHIRxfLA==", "X-Gm-Gg": "ATEYQzwflD/uqeM8tHZBYr6YBjZ5ED0MBb9LqGcXDl+cPj71EF2rMLN9JMVOdEWYxax\n 58G7FcnPZkSh+zKwwvOcGmIB6E7dcRB45WQbta2QiYYbHMYj9k+SuGwQ2BGoV2z8LDDYBbkx/eJ\n mbFqAg5yZaqMGzDBvq58t14d66gHSe6LG7SfV/rgtX5519D9vIbR9ovyz6uraPanqxP1u8hoBbn\n 9JU8dq9LrXR3MeRnAE2wxTBZZxk3IWgG9NVCN3VbKNeezijS4S43+bdwEgPI6e/NpWcG/qV0gil\n hQWm+0Jmbp26dZECbdpke7bnS2a+l+wa0GW0MmdBNfA6kY13PAnbSDov4dMt2RdfvIeWG/GN5Wk\n iWc1HkQC4FUgwWvXy7fF2+nU+Sfo7qUfsWpQxP96EA0WeX/1X8sxtI4rKxtTq1nM8fKej9vpLs/\n LS8epRS0UH9bedI8tSVFhynYMVfJN3mCcm0yQmqJu1C3zsucuB28oumutoDiHcdGZM8M3V+q01o\n CxF", "X-Received": "by 2002:a17:902:cf43:b0:2b2:5503:1b8c with SMTP id\n d9443c01a7336-2b25503299cmr49398925ad.11.1774902609450;\n Mon, 30 Mar 2026 13:30:09 -0700 (PDT)", "From": "Saish Sandip Kambali <sandipkambli79@gmail.com>", "To": "gcc-patches@gcc.gnu.org", "Cc": "dmalcolm@redhat.com,\n\tsandipkambli79@gmail.com", "Subject": "[PATCH v2] analyzer: model strnlen", "Date": "Mon, 30 Mar 2026 20:29:54 +0000", "Message-ID": "<20260330202955.23697-1-sandipkambli79@gmail.com>", "X-Mailer": "git-send-email 2.43.0", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "X-BeenThere": "gcc-patches@gcc.gnu.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>", "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>", "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>", "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org" }, "content": "This patch implements known_function handling for strnlen and\n__builtin_strnlen within the analyzer. It uses bifurcation logic\nto handle both truncated and full read conditions correctly.\n\ngcc/analyzer/ChangeLog:\n\t* kf.cc (class kf_strnlen): New known_function subclass.\n\t(register_known_functions_libc): Register strnlen and\n\t__builtin_strnlen.\n\ngcc/testsuite/ChangeLog:\n\t* gcc.dg/analyzer/strnlen-1.c: New test.\n\nSigned-off-by: Saish Sandip Kambali <sandipkambli79@gmail.com>\n---\nv2 changes:\n- Removed redundant else blocks.\n- Added test_passthrough test case in testsuite.\n- Added __builtin_strnlen (buf, 1) test case.\n- Fixed coding style and standardized comments.\n\nTesting:\n- 'make check-gcc RUNTESTFLAGS=\"analyzer.exp=strnlen-1.c\"' shows 18 passes and 0 failures.\n- Verified on x86_64-pc-linux-gnu.\n\n gcc/analyzer/kf.cc | 170 ++++++++++++++++++++++\n gcc/testsuite/gcc.dg/analyzer/strnlen-1.c | 134 +++++++++++++++++\n 2 files changed, 304 insertions(+)\n create mode 100644 gcc/testsuite/gcc.dg/analyzer/strnlen-1.c", "diff": "diff --git a/gcc/analyzer/kf.cc b/gcc/analyzer/kf.cc\nindex b1ccbd6584a..03294d7d55a 100644\n--- a/gcc/analyzer/kf.cc\n+++ b/gcc/analyzer/kf.cc\n@@ -1710,6 +1710,173 @@ public:\n }\n };\n \n+/* Handles strnlen by splitting into two outcomes:\n+ a) Truncated read: The limit 'n' is reached before any null-terminator,\n+ in this case the result is 'n'.\n+ b) Full read: A null-terminator is found before or at the limit n,\n+ in this case the result is the number of bytes read before the\n+ null-terminator. */\n+\n+class kf_strnlen : public builtin_known_function\n+{\n+public:\n+ bool matches_call_types_p (const call_details &cd) const final override\n+ {\n+ return (cd.num_args () == 2\n+\t && cd.arg_is_pointer_p (0)\n+\t && cd.arg_is_integral_p (1));\n+ }\n+\n+ enum built_in_function builtin_code () const final override\n+ {\n+ return BUILT_IN_STRNLEN;\n+ }\n+\n+ void impl_call_post (const call_details &cd) const final override;\n+};\n+\n+void\n+kf_strnlen::impl_call_post (const call_details &cd) const\n+{\n+ class strnlen_call_info : public call_info\n+ {\n+ public:\n+ strnlen_call_info (const call_details &cd,\n+\t\t const svalue *num_bytes_with_terminator_sval,\n+\t\t bool truncated_read)\n+ : call_info (cd),\n+ m_num_bytes_with_terminator_sval (num_bytes_with_terminator_sval),\n+ m_truncated_read (truncated_read)\n+ {\n+ }\n+\n+ void print_desc (pretty_printer &pp) const final override\n+ {\n+ if (m_truncated_read)\n+ pp_printf (&pp, \"when %qE reaches the maximum limit\", get_fndecl ());\n+ else\n+ pp_printf (&pp, \"when %qE finds the null terminator\", get_fndecl ());\t\n+ }\n+\n+ bool update_model (region_model *model,\n+\t\t const exploded_edge *,\n+\t\t region_model_context *ctxt) const final override\n+ {\n+ const call_details cd (get_call_details (model, ctxt));\n+\n+ /* Arguments at index '0' is the string pointer. */\n+ const svalue *src_sval = cd.get_arg_svalue (0);\n+ const region *src_reg\n+ = model->deref_rvalue (src_sval, cd.get_arg_tree (0), ctxt);\n+\n+ /* Argument 1 is the limit n. */\n+ const svalue *limit_n_sval = cd.get_arg_svalue (1);\n+\n+ /*Symbolic values for return value of the call. */\n+ const svalue *result_sval = nullptr;\n+ const svalue *bytes_to_check = nullptr;\n+\n+ /* Truncated read. */\n+ if (m_truncated_read)\n+ {\n+\t result_sval = limit_n_sval;\n+\n+\t if (m_num_bytes_with_terminator_sval)\n+\t {\n+\t if (!model->add_constraint (m_num_bytes_with_terminator_sval,\n+\t\t\t\t\t GT_EXPR, limit_n_sval, ctxt))\n+\t\treturn false;\n+\t }\n+\t}\n+ else\n+ {\n+\t /* Full read. */\n+\t if (m_num_bytes_with_terminator_sval)\n+\t {\n+\n+\t if (!model->add_constraint (m_num_bytes_with_terminator_sval,\n+\t\t\t\t\t LE_EXPR, limit_n_sval, ctxt))\n+\t\treturn false; \n+ \n+\t /* Computing return value only if lhs is present. */\n+\t if (tree lhs_type = cd.get_lhs_type ())\n+\t {\n+\t\t /* Since the strnlen () returns the count of bytes excluding '\\0'. */\n+\t\t result_sval = model->get_manager ()->get_or_create_binop (\n+\t\t lhs_type, MINUS_EXPR, m_num_bytes_with_terminator_sval,\n+\t\t model->get_manager ()->get_or_create_constant_svalue (\n+\t\t lhs_type, build_int_cst (lhs_type, 1)));\n+\t\t}\n+\t }\n+\t else\n+\t {\n+\t /* This bifurcation part is removed once failed. */\n+\t return false;\n+\t }\n+\t}\n+ \n+ /* This sets the return value, if the lhs type is declared. */\n+ if (result_sval && cd.get_lhs_type ())\n+ cd.maybe_set_lhs (result_sval);\n+\n+ /* This checks for buffer over read, and poison bytes as a safety check\n+ for both the lhs data type for null and non-null. */\n+ bytes_to_check = m_truncated_read ? limit_n_sval\n+\t\t\t\t\t: m_num_bytes_with_terminator_sval;\n+\n+ if (bytes_to_check)\n+ model->read_bytes (src_reg, cd.get_arg_tree (0), bytes_to_check, ctxt);\n+\n+ return true;\n+ }\n+\n+ private:\n+ /* This symbolic value representing the number of bytes read up to and\n+ including the first non-terminating character, it can be a null pointer. */\n+ const svalue *m_num_bytes_with_terminator_sval;\n+\n+ /* If true: We are simulating 'truncated read'\n+ If false: We are simulating the 'Full read'. */\n+ bool m_truncated_read;\n+ };\n+\n+ const svalue *limit_n_sval = cd.get_arg_svalue (1);\n+\n+ if (tree n_cst = limit_n_sval->maybe_get_constant ())\n+ {\n+ if (zerop (n_cst))\n+ {\n+\t cd.maybe_set_lhs (limit_n_sval);\n+\t return;\n+\t}\n+ }\n+\n+ if (cd.get_ctxt ())\n+ {\n+ /* First, scan for a null terminator as if there were no limit,\n+ with a null ctxt so no errors reported. */\n+\n+ const region_model *model = cd.get_model ();\n+ const svalue *ptr_arg_sval = cd.get_arg_svalue (0);\n+ const region *buf_reg\n+ = model->deref_rvalue (ptr_arg_sval, cd.get_arg_tree (0), nullptr);\n+\n+ const svalue *num_bytes_with_terminator_sval\n+ = model->scan_for_null_terminator (buf_reg, cd.get_arg_tree (0),\n+\t\t\t\t\t nullptr, nullptr);\n+\n+ cd.get_ctxt ()->bifurcate (\n+\tstd::make_unique<strnlen_call_info> (cd,\n+\t\t\t\t\t num_bytes_with_terminator_sval,\n+\t\t\t\t\t false));\n+ cd.get_ctxt ()->bifurcate (\n+\tstd::make_unique<strnlen_call_info> (cd,\n+\t\t\t\t\t num_bytes_with_terminator_sval,\n+\t\t\t\t\t true));\n+ cd.get_ctxt ()->terminate_path ();\n+ }\n+}\n+\n /* Handler for \"strstr\" and \"__builtin_strstr\".\n extern char *strstr (const char* str, const char* substr);\n See e.g. https://en.cppreference.com/w/c/string/byte/strstr */\n@@ -2337,6 +2504,8 @@ register_known_functions (known_function_manager &kfm,\n kfm.add (\"__builtin_strncpy\", std::make_unique<kf_strncpy> ());\n kfm.add (\"strndup\", std::make_unique<kf_strndup> ());\n kfm.add (\"__builtin_strndup\", std::make_unique<kf_strndup> ());\n+ kfm.add (\"strnlen\", std::make_unique<kf_strnlen> ());\n+ kfm.add (\"__builtin_strnlen\", std::make_unique<kf_strnlen> ());\n kfm.add (\"strlen\", std::make_unique<kf_strlen> ());\n kfm.add (\"__builtin_strlen\", std::make_unique<kf_strlen> ());\n kfm.add (\"strstr\", std::make_unique<kf_strstr> ());\n@@ -2402,6 +2571,7 @@ register_known_functions (known_function_manager &kfm,\n kfm.add_std_ns (\"strcat\", std::make_unique<kf_strcat> (2, false));\n kfm.add_std_ns (\"strcpy\", std::make_unique<kf_strcpy> (2, false));\n kfm.add_std_ns (\"strlen\", std::make_unique<kf_strlen> ());\n+ kfm.add_std_ns (\"strnlen\", std::make_unique<kf_strnlen> ());\n kfm.add_std_ns (\"strncpy\", std::make_unique<kf_strncpy> ());\n kfm.add_std_ns (\"strtok\", std::make_unique<kf_strtok> (rmm));\n }\ndiff --git a/gcc/testsuite/gcc.dg/analyzer/strnlen-1.c b/gcc/testsuite/gcc.dg/analyzer/strnlen-1.c\nnew file mode 100644\nindex 00000000000..15a9abe80e2\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/analyzer/strnlen-1.c\n@@ -0,0 +1,134 @@\n+#include \"analyzer-decls.h\"\n+\n+typedef __SIZE_TYPE__ size_t;\n+extern size_t strnlen (const char *s, size_t maxlen);\n+\n+/* noinline wrapper of test_string. */\n+static size_t __attribute__((noinline))\n+call_strnlen_1 (const char *p, size_t n)\n+{\n+ return __builtin_strnlen (p, n);\n+}\n+\n+void test_string (void)\n+{\n+ /* case 1: n is greater than string length */\n+ __analyzer_eval (call_strnlen_1 (\"abc\", 10) == 3); /* { dg-warning \"TRUE\" } */\n+\n+ /* case 2: n is smaller than the string length */\n+ __analyzer_eval (call_strnlen_1 (\"abc\", 2) == 2); /* { dg-warning \"TRUE\" } */\n+\n+ /* case 3: n is exactly the string length */\n+ __analyzer_eval (call_strnlen_1 (\"abc\", 3) == 3); /* { dg-warning \"TRUE\" } */\n+\n+ /* case 4: n is zero and should return 0 immediately. */\n+ __analyzer_eval (call_strnlen_1 (\"abc\", 0) == 0); /* { dg-warning \"TRUE\" } */\n+}\n+\n+/* checks if pointer is NULL */\n+void test_null_1 (void)\n+{\n+ __builtin_strnlen (NULL, 1); /* { dg-warning \"use of NULL where non-null expected\" } */\n+}\n+\n+void test_null_0 (void)\n+{\n+ /* n == 0 should not trigger a NULL warning in strnlen. */\n+ __analyzer_eval (__builtin_strnlen (NULL, 0) == 0); /* { dg-warning \"TRUE\" } */\n+}\n+\n+/* buffer declared but not initialized yet, warning if read uninitialized values */\n+void test_uninitialized (size_t n)\n+{\n+ char buf[16];\n+ if (n > 0)\n+ __builtin_strnlen (buf, n); /* { dg-warning \"use of uninitialized value\" } */ \n+}\n+\n+/* buffer is declared and partially initialized, warning if read uninitialized values */\n+void test_partially_initialized (void)\n+{\n+ char buf[16];\n+ buf[0] = 'a';\n+ /* TODO: The analyzer currently fails to see the uninitialized read at buf[1]. */\n+ __builtin_strnlen (buf, 2); /* { dg-bogus \"use of uninitialized value\" } */\n+}\n+\n+/* noinline wrapper of test_unterminated case 1 */\n+static size_t __attribute__((noinline))\n+call_strnlen_2 (const char *p, size_t n)\n+{\n+ return __builtin_strnlen (p, n);\n+}\n+\n+/* noinline wrapper of test_unterminated case 2 */\n+static size_t __attribute__((noinline))\n+call_strnlen_3 (const char *p, size_t n)\n+{\n+ return __builtin_strnlen (p, n); /* { dg-warning \"stack-based buffer over-read\" } */\n+}\n+\n+void test_unterminated (void)\n+{\n+ const char buf[3] = {'a', 'b', 'c'};\n+ \n+ /* case 2: SAFE as strnlen stops at n = 1, so never looked for \\0 */\n+ size_t result0 = __builtin_strnlen (buf, 1);\n+ __analyzer_eval (result0 == 1); /* { dg-warning \"TRUE\" } */\n+\n+ /* case 2: SAFE as strnlen stops at n = 3, so never looked for \\0 */\n+ size_t result1 = __builtin_strnlen (buf, 3);\n+ __analyzer_eval (result1 == 3); /* { dg-warning \"TRUE\" } */\n+\n+ /* case 3: Unsafe as n=4 forces the analyzer to look past the 3 bytes buffer */\n+ call_strnlen_3 (buf, 4);\n+}\n+\n+/* noinline wrapper of test_max_n */\n+static size_t __attribute__((noinline))\n+call_strnlen_4 (const char *p, size_t n)\n+{\n+ return __builtin_strnlen (p, n);\n+}\n+\n+/* for abstraction, assures the length l < n */\n+void test_abstract (const char *s, size_t n)\n+{\n+ if (s == NULL)\n+ return;\n+ size_t length = call_strnlen_4 (s, n);\n+\n+ /* TODO: This ideally should be TRUE, but currently returns UNKNOWN. */\n+ __analyzer_eval (length <= n); /* { dg-warning \"UNKNOWN\" } */\n+}\n+\n+/* noinline wrapper of test_array_initialization, case: true */\n+static size_t __attribute__((noinline))\n+call_strnlen_5 (const char *p, size_t n)\n+{\n+ return __builtin_strnlen (p, n);\n+}\n+\n+/* noinline wrapper of test_array_initialized, case: unknown */\n+static size_t __attribute__((noinline))\n+call_strnlen_5a (const char *p, size_t n)\n+{\n+ return __builtin_strnlen (p, n); /* { dg-warning \"stack-based buffer over-read\" } */\n+}\n+\n+/* pointer arithmetic can be performed and warnings for over reading buffer */\n+void test_array_initialization_implicit_length (void)\n+{\n+ const char buf[] = \"abc\";\n+\n+ __analyzer_eval (call_strnlen_5 (buf, 10) == 3); /* { dg-warning \"TRUE\" } */\n+ __analyzer_eval (call_strnlen_5 (buf + 2, 3) == 1); /* { dg-warning \"TRUE\" } */\n+ __analyzer_eval (call_strnlen_5 (buf + 3, 3) == 0); /* { dg-warning \"TRUE\" } */\n+ __analyzer_eval (call_strnlen_5a (buf + 4, 3) == 0); /* { dg-warning \"FALSE\" } */\n+}\n+\n+size_t\n+test_passthrough (const char *s, size_t maxlen)\n+{\n+ return strnlen (s, maxlen);\n+}\n", "prefixes": [ "v2" ] }