get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2217873/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "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"
    ]
}