Commit 021c85c7aa for asterisk.org

commit 021c85c7aac4c9a2be7fac049131422dc8b9a9f1
Author: Enes Gür <enesgur@users.noreply.github.com>
Date:   Tue Sep 22 07:13:05 2026 +0300

    res_pjsip: Fix crash on NULL endpoint snapshot in CLI output

    ast_sip_get_endpoint_snapshot() returns NULL when an endpoint has no
    entry in the Stasis cache, which can happen for an endpoint that is
    still in the sorcery container but whose snapshot has already been
    removed. cli_endpoint_print_body() dereferenced the result without
    checking, crashing the process on 'pjsip show endpoints',
    'pjsip list endpoints' and 'pjsip show endpoint <id>'.

    ast_sip_for_each_channel_snapshot() takes the same pointer and has the
    same unchecked dereference. 'pjsip show endpoints' reaches it through
    the recursive channel formatter, using a separately fetched snapshot,
    so guarding only the CLI formatter would move the crash rather than
    remove it. Guard both.

    active_channels_to_str() in the same file already handles a NULL
    snapshot this way.

    Assisted-by: Claude Opus 5

    Resolves: #2172

diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 0eebc14b12..17cbf4d981 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -3381,7 +3381,7 @@ const char *ast_sip_get_device_state(const struct ast_sip_endpoint *endpoint);
  * \brief For every channel snapshot on an endpoint snapshot call the given
  *        'on_channel_snapshot' handler.
  *
- * \param endpoint_snapshot snapshot of an endpoint
+ * \param endpoint_snapshot snapshot of an endpoint, may be NULL
  * \param on_channel_snapshot callback for each channel snapshot
  * \param arg user data passed to handler
  * \retval 0 Success, non-zero on failure
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 4d4d06a9b6..7056b7a2a3 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -1801,7 +1801,7 @@ int ast_sip_for_each_channel_snapshot(
 	const struct ast_endpoint_snapshot *endpoint_snapshot,
 	ao2_callback_fn on_channel_snapshot, void *arg)
 {
-	int num, num_channels = endpoint_snapshot->num_channels;
+	int num, num_channels = endpoint_snapshot ? endpoint_snapshot->num_channels : 0;

 	if (!on_channel_snapshot || !num_channels) {
 		return 0;
@@ -2163,7 +2163,7 @@ static int cli_endpoint_print_body(void *obj, void *arg, int flags)
 		indent, "Endpoint",
 		flexwidth, flexwidth, print_name ? print_name : id,
 		ast_sip_get_device_state(endpoint),
-		endpoint_snapshot->num_channels,
+		endpoint_snapshot ? endpoint_snapshot->num_channels : 0,
 		(double) endpoint->devicestate_busy_at ? endpoint->devicestate_busy_at :
 														INFINITY
 														);