Skip to content

Conversation

vszakats
Copy link
Member

@vszakats vszakats commented Mar 19, 2025

  • kex: drop unused assigment.
  • knownhost: error when salt is NULL.
  • mbedtls: avoid unnecessary inline assigments, that were ignored for
    the second block and replaceable with a ret = 0 initialization for
    the first one.
  • mbedtls: fix ignoring an API failure and ending up calling
    mbedtls_rsa_check_privkey() unconditionally.
  • misc: initialize datalen on error in _libssh2_base64_decode().
  • openssl: drop unused assigments.
  • openssl: fix unused static function.
  • packet: avoid NULL deref.
  • packet: avoid NULL in memcpy src.
  • publickey: optimize struct layout to avoid padding.
  • sftp: replace ignored rc error assigment with _libssh2_error() call.
  • transport: fix potential NULL ptr dereferences.
  • transport: silence uninitialized value warnings.
  • userauth: drop unused assigment.
  • userauth: possible use of unitialized pointer.
  • userauth: replace rewind() with fseek().
    rewind() returns an error condition in errno. errno is
    problematic and reduces portability. Use fseek() to avoid it.
  • userauth: replace potential NULL deref by returning error from
    sign_frommemory(). Possible false positive. rc should be set
    upstream if the callback is NULL.
  • userauth: replace potential NULL deref by returning error from
    sign_fromfile(). clang-tidy did not warn about this one, but
    let's match sign_frommemory() anyway.
  • wincng: fix potentially unused macros.
  • wincng: make sure bignum is not NULL before use.

tests:

  • openssh_fixture: drop unused assignment.
  • session_fixture: exit if username not set, to avoid strlen(NULL).
  • session_fixture: replace rewind() with fseek().
    rewind() returns an error condition in errno. errno is
    problematic and reduces portability. Use fseek() to avoid it.
  • test_read: exit if username not set, to avoid strlen(NULL).

examples:

  • scp_write_nonblock: fix file handle leak.
  • sftp_write_nonblock: file handle leak on error.
  • sftp_write_sliding: file handle leak on error.
  • ssh2_agent_forwarding: fix unused error codes.

Details in the subcommits under the PR.

Thanks-to: Michael Buckley
Thanks-to: Will Cosgrove

@vszakats vszakats changed the title cmake: add suppot for clang-tidy cmake: add support for clang-tidy Mar 19, 2025
@vszakats vszakats force-pushed the avoid-c-include branch 2 times, most recently from cc15b6b to 4aafbdf Compare March 19, 2025 18:07
@vszakats vszakats changed the title cmake: add support for clang-tidy cmake: add support for clang-tidy, fix fallouts Mar 20, 2025
@vszakats
Copy link
Member Author

vszakats commented Mar 20, 2025

Remaining 4 detected issues in transport.c:

src/transport.c:259:35: error: Assigned value is garbage or undefined [clang-analyzer-core.uninitialized.Assign,-warnings-as-errors]
  259 |                 p->padding_length = first_block[0];
      |                                   ^
src/transport.c:619:39: error: Assigned value is garbage or undefined [clang-analyzer-core.uninitialized.Assign,-warnings-as-errors]
  619 |                     p->padding_length = block[4];
      |                                       ^ ~~~~~~~~
src/transport.c:627:34: error: Access to field 'mac_len' results in a dereference of a null pointer (loaded from variable 'remote_mac') [clang-analyzer-core.NullDereference,-warnings-as-errors]
  627 |                     (encrypted ? remote_mac->mac_len : 0);
      |                                  ^~~~~~~~~~
src/transport.c:1241:31: error: Access to field 'mac_len' results in a dereference of a null pointer (loaded from variable 'local_mac') [clang-analyzer-core.NullDereference,-warnings-as-errors]
 1241 |                 int authlen = local_mac->mac_len;
      |                               ^~~~~~~~~
Details
src/transport.c:259:35: error: Assigned value is garbage or undefined [clang-analyzer-core.uninitialized.Assign,-warnings-as-errors]
  259 |                 p->padding_length = first_block[0];
      |                                   ^
src/transport.c:400:8: note: Assuming the condition is false
  400 |     if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:400:55: note: Left side of '&&' is false
  400 |     if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
      |                                                       ^
src/transport.c:418:8: note: Assuming field 'readPack_state' is equal to libssh2_NB_state_jump1
  418 |     if(session->readPack_state == libssh2_NB_state_jump1) {
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:418:5: note: Taking true branch
  418 |     if(session->readPack_state == libssh2_NB_state_jump1) {
      |     ^
src/transport.c:421:9: note: Control jumps to line 871
  421 |         goto libssh2_transport_read_point1;
      |         ^
src/transport.c:871:18: note: Calling 'fullpacket'
  871 |             rc = fullpacket(session, encrypted);
      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:191:8: note: Assuming 'encrypted' is not equal to 0
  191 |     if(!encrypted || (!CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET) &&
      |        ^~~~~~~~~~
src/transport.c:191:8: note: Left side of '||' is false
src/transport.c:191:24: note: Assuming field 'crypt' is null
  191 |     if(!encrypted || (!CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET) &&
      |                        ^
src/libssh2_priv.h:1076:38: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                      ^~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:191:24: note: Left side of '&&' is false
  191 |     if(!encrypted || (!CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET) &&
      |                        ^
src/libssh2_priv.h:1076:62: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                                              ^
src/transport.c:191:23: note: Left side of '&&' is true
  191 |     if(!encrypted || (!CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET) &&
      |                       ^
src/transport.c:192:24: note: Field 'crypt' is null
  192 |                       !CRYPT_FLAG_R(session, INTEGRATED_MAC))) {
      |                        ^
src/libssh2_priv.h:1076:56: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                                        ^
src/transport.c:192:24: note: Left side of '&&' is false
  192 |                       !CRYPT_FLAG_R(session, INTEGRATED_MAC))) {
      |                        ^
src/libssh2_priv.h:1076:62: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                                              ^
src/transport.c:191:5: note: Taking true branch
  191 |     if(!encrypted || (!CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET) &&
      |     ^
src/transport.c:196:8: note: Assuming field 'fullpacket_state' is equal to libssh2_NB_state_idle
  196 |     if(session->fullpacket_state == libssh2_NB_state_idle) {
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:196:5: note: Taking true branch
  196 |     if(session->fullpacket_state == libssh2_NB_state_idle) {
      |     ^
src/transport.c:200:12: note: 'encrypted' is not equal to 0
  200 |         if(encrypted && remote_mac) {
      |            ^~~~~~~~~
src/transport.c:200:12: note: Left side of '&&' is true
src/transport.c:200:25: note: Assuming 'remote_mac' is non-null
  200 |         if(encrypted && remote_mac) {
      |                         ^~~~~~~~~~
src/transport.c:200:9: note: Taking true branch
  200 |         if(encrypted && remote_mac) {
      |         ^
src/transport.c:205:16: note: Assuming 'etm' is not equal to 0
  205 |             if(etm) {
      |                ^~~
src/transport.c:205:13: note: Taking true branch
  205 |             if(etm) {
      |             ^
src/transport.c:228:16: note: Assuming the condition is false
  228 |             if(memcmp(macbuf, p->payload + p->total_num - mac_len, mac_len)) {
      |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:228:13: note: Taking false branch
  228 |             if(memcmp(macbuf, p->payload + p->total_num - mac_len, mac_len)) {
      |             ^
src/transport.c:234:21: note: 'etm' is not equal to 0
  234 |             else if(etm) {
      |                     ^~~
src/transport.c:234:18: note: Taking true branch
  234 |             else if(etm) {
      |                  ^
src/transport.c:244:22: note: Calling 'decrypt'
  244 |                 rc = decrypt(session, p->payload + 4,
      |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  245 |                              first_block, blocksize, FIRST_BLOCK);
      |                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:137:9: note: Assuming field 'crypt' is non-null
  137 |     if(!CRYPT_FLAG_L(session, PKTLEN_AAD))
      |         ^
src/libssh2_priv.h:1073:38: note: expanded from macro 'CRYPT_FLAG_L'
 1073 | #define CRYPT_FLAG_L(session, flag) ((session)->local.crypt && \
      |                                      ^~~~~~~~~~~~~~~~~~~~~~
src/transport.c:137:9: note: Left side of '&&' is true
  137 |     if(!CRYPT_FLAG_L(session, PKTLEN_AAD))
      |         ^
src/libssh2_priv.h:1073:38: note: expanded from macro 'CRYPT_FLAG_L'
 1073 | #define CRYPT_FLAG_L(session, flag) ((session)->local.crypt && \
      |                                      ^
src/transport.c:137:8: note: Assuming the condition is false
  137 |     if(!CRYPT_FLAG_L(session, PKTLEN_AAD))
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:137:5: note: Taking false branch
  137 |     if(!CRYPT_FLAG_L(session, PKTLEN_AAD))
      |     ^
src/transport.c:140:11: note: Assuming 'len' is <= 0
  140 |     while(len > 0) {
      |           ^~~~~~~
src/transport.c:140:5: note: Loop condition is false. Execution continues on line 174
  140 |     while(len > 0) {
      |     ^
src/transport.c:174:5: note: Returning without writing to '*dest'
  174 |     return LIBSSH2_ERROR_NONE;         /* all is fine */
      |     ^
src/transport.c:174:5: note: Returning zero, which participates in a condition later
  174 |     return LIBSSH2_ERROR_NONE;         /* all is fine */
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:244:22: note: Returning from 'decrypt'
  244 |                 rc = decrypt(session, p->payload + 4,
      |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  245 |                              first_block, blocksize, FIRST_BLOCK);
      |                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:246:20: note: 'rc' is 0
  246 |                 if(rc) {
      |                    ^~
src/transport.c:246:17: note: Taking false branch
  246 |                 if(rc) {
      |                 ^
src/transport.c:253:20: note: Assuming 'decrypt_buffer' is non-null
  253 |                 if(!decrypt_buffer) {
      |                    ^~~~~~~~~~~~~~~
src/transport.c:253:17: note: Taking false branch
  253 |                 if(!decrypt_buffer) {
      |                 ^
src/transport.c:259:35: note: Assigned value is garbage or undefined
  259 |                 p->padding_length = first_block[0];
      |                                   ^ ~~~~~~~~~~~~~~
src/transport.c:619:39: error: Assigned value is garbage or undefined [clang-analyzer-core.uninitialized.Assign,-warnings-as-errors]
  619 |                     p->padding_length = block[4];
      |                                       ^ ~~~~~~~~
src/transport.c:400:8: note: Assuming the condition is false
  400 |     if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:400:55: note: Left side of '&&' is false
  400 |     if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
      |                                                       ^
src/transport.c:418:8: note: Assuming field 'readPack_state' is not equal to libssh2_NB_state_jump1
  418 |     if(session->readPack_state == libssh2_NB_state_jump1) {
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:418:5: note: Taking false branch
  418 |     if(session->readPack_state == libssh2_NB_state_jump1) {
      |     ^
src/transport.c:426:12: note: Assuming the condition is false
  426 |         if(session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:426:9: note: Taking false branch
  426 |         if(session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
      |         ^
src/transport.c:430:12: note: Assuming the condition is true
  430 |         if(session->state & LIBSSH2_STATE_NEWKEYS) {
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:430:9: note: Taking true branch
  430 |         if(session->state & LIBSSH2_STATE_NEWKEYS) {
      |         ^
src/transport.c:439:12: note: 'encrypted' is 1
  439 |         if(encrypted) {
      |            ^~~~~~~~~
src/transport.c:439:9: note: Taking true branch
  439 |         if(encrypted) {
      |         ^
src/transport.c:440:16: note: Field 'crypt' is non-null
  440 |             if(CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                ^
src/libssh2_priv.h:1076:56: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                                        ^
src/transport.c:440:16: note: Left side of '&&' is true
  440 |             if(CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                ^
src/libssh2_priv.h:1076:38: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                      ^
src/transport.c:440:16: note: Assuming the condition is false
  440 |             if(CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                ^
src/libssh2_priv.h:1077:6: note: expanded from macro 'CRYPT_FLAG_R'
 1077 |     ((session)->remote.crypt->flags & LIBSSH2_CRYPT_FLAG_##flag))
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:440:13: note: Taking false branch
  440 |             if(CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |             ^
src/transport.c:448:15: note: 'encrypted' is 1
  448 |         etm = encrypted && remote_mac ? remote_mac->etm : 0;
      |               ^~~~~~~~~
src/transport.c:448:15: note: Left side of '&&' is true
src/transport.c:448:28: note: Assuming 'remote_mac' is null
  448 |         etm = encrypted && remote_mac ? remote_mac->etm : 0;
      |                            ^~~~~~~~~~
src/transport.c:448:15: note: '?' condition is false
  448 |         etm = encrypted && remote_mac ? remote_mac->etm : 0;
      |               ^
src/transport.c:461:16: note: Assuming 'remainbuf' is >= 0
  461 |         assert(remainbuf >= 0);
      |                ^
/Users/vsz/Applications/llvm-mingw/x86_64-w64-mingw32/include/assert.h:52:7: note: expanded from macro 'assert'
   52 |  ((!!(_Expression)) || \
      |       ^~~~~~~~~~~
src/transport.c:461:9: note: Left side of '||' is true
  461 |         assert(remainbuf >= 0);
      |         ^
/Users/vsz/Applications/llvm-mingw/x86_64-w64-mingw32/include/assert.h:52:21: note: expanded from macro 'assert'
   52 |  ((!!(_Expression)) || \
      |                     ^
src/transport.c:463:12: note: Assuming 'remainbuf' is >= 'blocksize'
  463 |         if(remainbuf < blocksize ||
      |            ^~~~~~~~~~~~~~~~~~~~~
src/transport.c:463:12: note: Left side of '||' is false
src/transport.c:464:13: note: Field 'crypt' is non-null
  464 |            (CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)
      |             ^
src/libssh2_priv.h:1076:56: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                                        ^
src/transport.c:464:13: note: Left side of '&&' is true
  464 |            (CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)
      |             ^
src/libssh2_priv.h:1076:38: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                      ^
src/transport.c:465:13: note: Left side of '&&' is false
  465 |             && ((ssize_t)p->total_num) > remainbuf)) {
      |             ^
src/transport.c:517:12: note: Assuming field 'total_num' is 0
  517 |         if(!p->total_num) {
      |            ^~~~~~~~~~~~~
src/transport.c:517:9: note: Taking true branch
  517 |         if(!p->total_num) {
      |         ^
src/transport.c:524:37: note: 'etm' is 0
  524 |             ssize_t required_size = etm ? 4 : blocksize;
      |                                     ^~~
src/transport.c:524:37: note: '?' condition is false
src/transport.c:530:16: note: 'numbytes' is >= 'required_size'
  530 |             if(numbytes < required_size) {
      |                ^~~~~~~~
src/transport.c:530:13: note: Taking false branch
  530 |             if(numbytes < required_size) {
      |             ^
src/transport.c:540:16: note: 'etm' is 0
  540 |             if(etm) {
      |                ^~~
src/transport.c:540:13: note: Taking false branch
  540 |             if(etm) {
      |             ^
src/transport.c:545:21: note: 'encrypted' is 1
  545 |             else if(encrypted && session->remote.crypt->get_len) {
      |                     ^~~~~~~~~
src/transport.c:545:21: note: Left side of '&&' is true
src/transport.c:545:34: note: Assuming field 'get_len' is null
  545 |             else if(encrypted && session->remote.crypt->get_len) {
      |                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:545:18: note: Taking false branch
  545 |             else if(encrypted && session->remote.crypt->get_len) {
      |                  ^
src/transport.c:572:20: note: 'encrypted' is 1
  572 |                 if(encrypted) {
      |                    ^~~~~~~~~
src/transport.c:572:17: note: Taking true branch
  572 |                 if(encrypted) {
      |                 ^
src/transport.c:574:26: note: Calling 'decrypt'
  574 |                     rc = decrypt(session, &p->buf[p->readidx],
      |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  575 |                                  block, blocksize, FIRST_BLOCK);
      |                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:137:9: note: Assuming field 'crypt' is non-null
  137 |     if(!CRYPT_FLAG_L(session, PKTLEN_AAD))
      |         ^
src/libssh2_priv.h:1073:38: note: expanded from macro 'CRYPT_FLAG_L'
 1073 | #define CRYPT_FLAG_L(session, flag) ((session)->local.crypt && \
      |                                      ^~~~~~~~~~~~~~~~~~~~~~
src/transport.c:137:9: note: Left side of '&&' is true
  137 |     if(!CRYPT_FLAG_L(session, PKTLEN_AAD))
      |         ^
src/libssh2_priv.h:1073:38: note: expanded from macro 'CRYPT_FLAG_L'
 1073 | #define CRYPT_FLAG_L(session, flag) ((session)->local.crypt && \
      |                                      ^
src/transport.c:137:8: note: Assuming the condition is false
  137 |     if(!CRYPT_FLAG_L(session, PKTLEN_AAD))
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:137:5: note: Taking false branch
  137 |     if(!CRYPT_FLAG_L(session, PKTLEN_AAD))
      |     ^
src/transport.c:140:11: note: Assuming 'len' is <= 0
  140 |     while(len > 0) {
      |           ^~~~~~~
src/transport.c:140:5: note: Loop condition is false. Execution continues on line 174
  140 |     while(len > 0) {
      |     ^
src/transport.c:574:26: note: Returning from 'decrypt'
  574 |                     rc = decrypt(session, &p->buf[p->readidx],
      |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  575 |                                  block, blocksize, FIRST_BLOCK);
      |                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:576:24: note: 'rc' is equal to LIBSSH2_ERROR_NONE
  576 |                     if(rc != LIBSSH2_ERROR_NONE) {
      |                        ^~
src/transport.c:576:21: note: Taking false branch
  576 |                     if(rc != LIBSSH2_ERROR_NONE) {
      |                     ^
src/transport.c:599:17: note: 'encrypted' is 1
  599 |             if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                 ^~~~~~~~~
src/transport.c:599:16: note: Left side of '||' is false
  599 |             if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                ^
src/transport.c:599:31: note: Field 'crypt' is non-null
  599 |             if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                               ^
src/libssh2_priv.h:1076:56: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                                        ^
src/transport.c:599:31: note: Left side of '&&' is true
  599 |             if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                               ^
src/libssh2_priv.h:1076:38: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                      ^
src/transport.c:599:13: note: Taking true branch
  599 |             if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |             ^
src/transport.c:600:20: note: Assuming field 'packet_length' is >= 1
  600 |                 if(p->packet_length < 1) {
      |                    ^~~~~~~~~~~~~~~~~~~~
src/transport.c:600:17: note: Taking false branch
  600 |                 if(p->packet_length < 1) {
      |                 ^
src/transport.c:603:25: note: Assuming field 'packet_length' is <= LIBSSH2_PACKET_MAXPAYLOAD
  603 |                 else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD) {
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:603:22: note: Taking false branch
  603 |                 else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD) {
      |                      ^
src/transport.c:607:20: note: 'etm' is 0
  607 |                 if(etm) {
      |                    ^~~
src/transport.c:607:17: note: Taking false branch
  607 |                 if(etm) {
      |                 ^
src/transport.c:619:39: note: Assigned value is garbage or undefined
  619 |                     p->padding_length = block[4];
      |                                       ^ ~~~~~~~~
src/transport.c:627:34: error: Access to field 'mac_len' results in a dereference of a null pointer (loaded from variable 'remote_mac') [clang-analyzer-core.NullDereference,-warnings-as-errors]
  627 |                     (encrypted ? remote_mac->mac_len : 0);
      |                                  ^~~~~~~~~~
src/transport.c:400:8: note: Assuming the condition is false
  400 |     if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:400:55: note: Left side of '&&' is false
  400 |     if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
      |                                                       ^
src/transport.c:418:8: note: Assuming field 'readPack_state' is not equal to libssh2_NB_state_jump1
  418 |     if(session->readPack_state == libssh2_NB_state_jump1) {
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:418:5: note: Taking false branch
  418 |     if(session->readPack_state == libssh2_NB_state_jump1) {
      |     ^
src/transport.c:426:12: note: Assuming the condition is false
  426 |         if(session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:426:9: note: Taking false branch
  426 |         if(session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
      |         ^
src/transport.c:430:12: note: Assuming the condition is true
  430 |         if(session->state & LIBSSH2_STATE_NEWKEYS) {
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:430:9: note: Taking true branch
  430 |         if(session->state & LIBSSH2_STATE_NEWKEYS) {
      |         ^
src/transport.c:439:12: note: 'encrypted' is 1
  439 |         if(encrypted) {
      |            ^~~~~~~~~
src/transport.c:439:9: note: Taking true branch
  439 |         if(encrypted) {
      |         ^
src/transport.c:440:16: note: Field 'crypt' is non-null
  440 |             if(CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                ^
src/libssh2_priv.h:1076:56: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                                        ^
src/transport.c:440:16: note: Left side of '&&' is true
  440 |             if(CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                ^
src/libssh2_priv.h:1076:38: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                      ^
src/transport.c:440:16: note: Assuming the condition is false
  440 |             if(CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                ^
src/libssh2_priv.h:1077:6: note: expanded from macro 'CRYPT_FLAG_R'
 1077 |     ((session)->remote.crypt->flags & LIBSSH2_CRYPT_FLAG_##flag))
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:440:13: note: Taking false branch
  440 |             if(CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |             ^
src/transport.c:444:17: note: Value assigned to 'remote_mac'
  444 |                 remote_mac = session->remote.mac;
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:448:15: note: 'encrypted' is 1
  448 |         etm = encrypted && remote_mac ? remote_mac->etm : 0;
      |               ^~~~~~~~~
src/transport.c:448:15: note: Left side of '&&' is true
src/transport.c:448:28: note: Assuming 'remote_mac' is null
  448 |         etm = encrypted && remote_mac ? remote_mac->etm : 0;
      |                            ^~~~~~~~~~
src/transport.c:448:15: note: Assuming pointer value is null
  448 |         etm = encrypted && remote_mac ? remote_mac->etm : 0;
      |               ^~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:448:15: note: '?' condition is false
src/transport.c:461:16: note: Assuming 'remainbuf' is >= 0
  461 |         assert(remainbuf >= 0);
      |                ^
/Users/vsz/Applications/llvm-mingw/x86_64-w64-mingw32/include/assert.h:52:7: note: expanded from macro 'assert'
   52 |  ((!!(_Expression)) || \
      |       ^~~~~~~~~~~
src/transport.c:461:9: note: Left side of '||' is true
  461 |         assert(remainbuf >= 0);
      |         ^
/Users/vsz/Applications/llvm-mingw/x86_64-w64-mingw32/include/assert.h:52:21: note: expanded from macro 'assert'
   52 |  ((!!(_Expression)) || \
      |                     ^
src/transport.c:463:12: note: Assuming 'remainbuf' is >= 'blocksize'
  463 |         if(remainbuf < blocksize ||
      |            ^~~~~~~~~~~~~~~~~~~~~
src/transport.c:463:12: note: Left side of '||' is false
src/transport.c:464:13: note: Field 'crypt' is non-null
  464 |            (CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)
      |             ^
src/libssh2_priv.h:1076:56: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                                        ^
src/transport.c:464:13: note: Left side of '&&' is true
  464 |            (CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)
      |             ^
src/libssh2_priv.h:1076:38: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                      ^
src/transport.c:465:13: note: Left side of '&&' is false
  465 |             && ((ssize_t)p->total_num) > remainbuf)) {
      |             ^
src/transport.c:517:12: note: Assuming field 'total_num' is 0
  517 |         if(!p->total_num) {
      |            ^~~~~~~~~~~~~
src/transport.c:517:9: note: Taking true branch
  517 |         if(!p->total_num) {
      |         ^
src/transport.c:524:37: note: 'etm' is 0
  524 |             ssize_t required_size = etm ? 4 : blocksize;
      |                                     ^~~
src/transport.c:524:37: note: '?' condition is false
src/transport.c:530:16: note: 'numbytes' is >= 'required_size'
  530 |             if(numbytes < required_size) {
      |                ^~~~~~~~
src/transport.c:530:13: note: Taking false branch
  530 |             if(numbytes < required_size) {
      |             ^
src/transport.c:540:16: note: 'etm' is 0
  540 |             if(etm) {
      |                ^~~
src/transport.c:540:13: note: Taking false branch
  540 |             if(etm) {
      |             ^
src/transport.c:545:21: note: 'encrypted' is 1
  545 |             else if(encrypted && session->remote.crypt->get_len) {
      |                     ^~~~~~~~~
src/transport.c:545:21: note: Left side of '&&' is true
src/transport.c:545:34: note: Assuming field 'get_len' is non-null
  545 |             else if(encrypted && session->remote.crypt->get_len) {
      |                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:545:18: note: Taking true branch
  545 |             else if(encrypted && session->remote.crypt->get_len) {
      |                  ^
src/transport.c:556:20: note: Assuming 'rc' is equal to LIBSSH2_ERROR_NONE
  556 |                 if(rc != LIBSSH2_ERROR_NONE) {
      |                    ^~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:556:17: note: Taking false branch
  556 |                 if(rc != LIBSSH2_ERROR_NONE) {
      |                 ^
src/transport.c:599:17: note: 'encrypted' is 1
  599 |             if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                 ^~~~~~~~~
src/transport.c:599:16: note: Left side of '||' is false
  599 |             if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                ^
src/transport.c:599:31: note: Assuming field 'crypt' is null
  599 |             if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                               ^
src/libssh2_priv.h:1076:38: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                      ^~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:599:31: note: Left side of '&&' is false
  599 |             if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                               ^
src/libssh2_priv.h:1076:62: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                                              ^
src/transport.c:599:13: note: Taking true branch
  599 |             if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |             ^
src/transport.c:600:20: note: Assuming field 'packet_length' is >= 1
  600 |                 if(p->packet_length < 1) {
      |                    ^~~~~~~~~~~~~~~~~~~~
src/transport.c:600:17: note: Taking false branch
  600 |                 if(p->packet_length < 1) {
      |                 ^
src/transport.c:603:25: note: Assuming field 'packet_length' is <= LIBSSH2_PACKET_MAXPAYLOAD
  603 |                 else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD) {
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:603:22: note: Taking false branch
  603 |                 else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD) {
      |                      ^
src/transport.c:607:20: note: 'etm' is 0
  607 |                 if(etm) {
      |                    ^~~
src/transport.c:607:17: note: Taking false branch
  607 |                 if(etm) {
      |                 ^
src/transport.c:620:24: note: Assuming the condition is false
  620 |                     if(p->padding_length > p->packet_length - 1) {
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:620:21: note: Taking false branch
  620 |                     if(p->padding_length > p->packet_length - 1) {
      |                     ^
src/transport.c:627:22: note: 'encrypted' is 1
  627 |                     (encrypted ? remote_mac->mac_len : 0);
      |                      ^~~~~~~~~
src/transport.c:627:22: note: '?' condition is true
src/transport.c:627:34: note: Access to field 'mac_len' results in a dereference of a null pointer (loaded from variable 'remote_mac')
  627 |                     (encrypted ? remote_mac->mac_len : 0);
      |                                  ^~~~~~~~~~
src/transport.c:1241:31: error: Access to field 'mac_len' results in a dereference of a null pointer (loaded from variable 'local_mac') [clang-analyzer-core.NullDereference,-warnings-as-errors]
 1241 |                 int authlen = local_mac->mac_len;
      |                               ^~~~~~~~~
src/transport.c:992:10: note: Assuming the condition is false
  992 |         (session->state & LIBSSH2_STATE_NEWKEYS) ?
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:992:9: note: '?' condition is false
  992 |         (session->state & LIBSSH2_STATE_NEWKEYS) ?
      |         ^
src/transport.c:1020:8: note: Assuming the condition is false
 1020 |     if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:1020:55: note: Left side of '&&' is false
 1020 |     if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
      |                                                       ^
src/transport.c:1031:5: note: Calling 'debugdump'
 1031 |     debugdump(session, "libssh2_transport_write plain", data, data_len);
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:67:8: note: Assuming the condition is false
   67 |     if(!(session->showmask & LIBSSH2_TRACE_TRANS)) {
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:67:5: note: Taking false branch
   67 |     if(!(session->showmask & LIBSSH2_TRACE_TRANS)) {
      |     ^
src/transport.c:74:8: note: Assuming field 'tracehandler' is non-null
   74 |     if(session->tracehandler)
      |        ^~~~~~~~~~~~~~~~~~~~~
src/transport.c:74:5: note: Taking true branch
   74 |     if(session->tracehandler)
      |     ^
src/transport.c:75:9: note: Value assigned to field 'crypt', which participates in a condition later
   75 |         (session->tracehandler)(session, session->tracehandler_context,
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   76 |                                 buffer, used);
      |                                 ~~~~~~~~~~~~~
src/transport.c:75:9: note: Value assigned to field 'mac', which participates in a condition later
   75 |         (session->tracehandler)(session, session->tracehandler_context,
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   76 |                                 buffer, used);
      |                                 ~~~~~~~~~~~~~
src/transport.c:75:9: note: Value assigned to field 'mac'
   75 |         (session->tracehandler)(session, session->tracehandler_context,
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   76 |                                 buffer, used);
      |                                 ~~~~~~~~~~~~~
src/transport.c:80:16: note: Assuming 'i' is >= 'size'
   80 |     for(i = 0; i < size; i += width) {
      |                ^~~~~~~~
src/transport.c:80:5: note: Loop condition is false. Execution continues on line 80
   80 |     for(i = 0; i < size; i += width) {
      |     ^
src/transport.c:1031:5: note: Returning from 'debugdump'
 1031 |     debugdump(session, "libssh2_transport_write plain", data, data_len);
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:1032:8: note: Assuming 'data2' is null
 1032 |     if(data2)
      |        ^~~~~
src/transport.c:1032:5: note: Taking false branch
 1032 |     if(data2)
      |     ^
src/transport.c:1037:10: note: Calling 'send_existing'
 1037 |     rc = send_existing(session, data, data_len, &ret);
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:908:8: note: Assuming field 'olen' is 0, which participates in a condition later
  908 |     if(!p->olen) {
      |        ^~~~~~~~
src/transport.c:908:5: note: Taking true branch
  908 |     if(!p->olen) {
      |     ^
src/transport.c:909:9: note: The value 0 is assigned to 'ret', which participates in a condition later
  909 |         *ret = 0;
      |         ^~~~~~~~
src/transport.c:910:9: note: Returning zero, which participates in a condition later
  910 |         return LIBSSH2_ERROR_NONE;
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:1037:10: note: Returning from 'send_existing'
 1037 |     rc = send_existing(session, data, data_len, &ret);
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:1038:8: note: 'rc' is 0
 1038 |     if(rc)
      |        ^~
src/transport.c:1038:5: note: Taking false branch
 1038 |     if(rc)
      |     ^
src/transport.c:1043:8: note: 'ret' is 0
 1043 |     if(ret)
      |        ^~~
src/transport.c:1043:5: note: Taking false branch
 1043 |     if(ret)
      |     ^
src/transport.c:1047:18: note: Assuming the condition is true
 1047 |     encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0;
      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:1047:17: note: '?' condition is true
 1047 |     encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0;
      |                 ^
src/transport.c:1049:8: note: 'encrypted' is 1
 1049 |     if(encrypted && session->local.crypt &&
      |        ^~~~~~~~~
src/transport.c:1049:8: note: Left side of '&&' is true
src/transport.c:1049:21: note: Assuming field 'crypt' is null
 1049 |     if(encrypted && session->local.crypt &&
      |                     ^~~~~~~~~~~~~~~~~~~~
src/transport.c:1049:42: note: Left side of '&&' is false
 1049 |     if(encrypted && session->local.crypt &&
      |                                          ^
src/transport.c:1054:9: note: Value assigned to 'local_mac'
 1054 |         local_mac = session->local.mac;
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:1057:11: note: 'encrypted' is 1
 1057 |     etm = encrypted && local_mac ? local_mac->etm : 0;
      |           ^~~~~~~~~
src/transport.c:1057:11: note: Left side of '&&' is true
src/transport.c:1057:24: note: Assuming 'local_mac' is null
 1057 |     etm = encrypted && local_mac ? local_mac->etm : 0;
      |                        ^~~~~~~~~
src/transport.c:1057:11: note: Assuming pointer value is null
 1057 |     etm = encrypted && local_mac ? local_mac->etm : 0;
      |           ^~~~~~~~~~~~~~~~~~~~~~
src/transport.c:1057:11: note: '?' condition is false
src/transport.c:1059:18: note: Assuming field 'comp' is null
 1059 |     compressed = session->local.comp &&
      |                  ^~~~~~~~~~~~~~~~~~~
src/transport.c:1059:38: note: Left side of '&&' is false
 1059 |     compressed = session->local.comp &&
      |                                      ^
src/transport.c:1064:8: note: 'encrypted' is 1
 1064 |     if(encrypted && compressed && session->local.comp_abstract) {
      |        ^~~~~~~~~
src/transport.c:1064:8: note: Left side of '&&' is true
src/transport.c:1064:21: note: 'compressed' is 0
 1064 |     if(encrypted && compressed && session->local.comp_abstract) {
      |                     ^~~~~~~~~~
src/transport.c:1064:32: note: Left side of '&&' is false
 1064 |     if(encrypted && compressed && session->local.comp_abstract) {
      |                                ^
src/transport.c:1098:12: note: Assuming the condition is false
 1098 |         if((data_len + data2_len) >= (MAX_SSH_PACKET_LEN-0x100))
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:1098:9: note: Taking false branch
 1098 |         if((data_len + data2_len) >= (MAX_SSH_PACKET_LEN-0x100))
      |         ^
src/transport.c:1105:12: note: 'data2' is null
 1105 |         if(data2 && data2_len)
      |            ^~~~~
src/transport.c:1105:18: note: Left side of '&&' is false
 1105 |         if(data2 && data2_len)
      |                  ^
src/transport.c:1122:21: note: 'etm' is 0
 1122 |     crypt_offset = (etm || auth_len ||
      |                     ^~~
src/transport.c:1122:21: note: Left side of '||' is false
src/transport.c:1122:28: note: 'auth_len' is 0
 1122 |     crypt_offset = (etm || auth_len ||
      |                            ^~~~~~~~
src/transport.c:1122:21: note: Left side of '||' is false
 1122 |     crypt_offset = (etm || auth_len ||
      |                     ^
src/transport.c:1123:22: note: 'encrypted' is 1
 1123 |                     (encrypted && CRYPT_FLAG_R(session, PKTLEN_AAD)))
      |                      ^~~~~~~~~
src/transport.c:1123:22: note: Left side of '&&' is true
src/transport.c:1123:35: note: Assuming field 'crypt' is null
 1123 |                     (encrypted && CRYPT_FLAG_R(session, PKTLEN_AAD)))
      |                                   ^
src/libssh2_priv.h:1076:38: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                      ^~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:1123:35: note: Left side of '&&' is false
 1123 |                     (encrypted && CRYPT_FLAG_R(session, PKTLEN_AAD)))
      |                                   ^
src/libssh2_priv.h:1076:62: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                                              ^
src/transport.c:1125:24: note: 'etm' is 0
 1125 |     etm_crypt_offset = etm ? 4 : 0;
      |                        ^~~
src/transport.c:1125:24: note: '?' condition is false
src/transport.c:1136:8: note: Assuming 'padding_length' is >= 4
 1136 |     if(padding_length < 4) {
      |        ^~~~~~~~~~~~~~~~~~
src/transport.c:1136:5: note: Taking false branch
 1136 |     if(padding_length < 4) {
      |     ^
src/transport.c:1154:26: note: 'encrypted' is 1
 1154 |         packet_length + (encrypted && local_mac ? local_mac->mac_len : 0);
      |                          ^~~~~~~~~
src/transport.c:1154:26: note: Left side of '&&' is true
src/transport.c:1154:39: note: 'local_mac' is null
 1154 |         packet_length + (encrypted && local_mac ? local_mac->mac_len : 0);
      |                                       ^~~~~~~~~
src/transport.c:1154:26: note: '?' condition is false
 1154 |         packet_length + (encrypted && local_mac ? local_mac->mac_len : 0);
      |                          ^
src/transport.c:1165:8: note: Assuming the condition is false
 1165 |     if(_libssh2_random(p->outbuf + 5 + data_len, padding_length)) {
      |        ^
src/wincng.h:157:5: note: expanded from macro '_libssh2_random'
  157 |     _libssh2_wincng_random(buf, len)
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:1165:5: note: Taking false branch
 1165 |     if(_libssh2_random(p->outbuf + 5 + data_len, padding_length)) {
      |     ^
src/transport.c:1170:8: note: 'encrypted' is 1
 1170 |     if(encrypted) {
      |        ^~~~~~~~~
src/transport.c:1170:5: note: Taking true branch
 1170 |     if(encrypted) {
      |     ^
src/transport.c:1179:13: note: 'etm' is 0
 1179 |         if(!etm && local_mac && !CRYPT_FLAG_L(session, INTEGRATED_MAC)) {
      |             ^~~
src/transport.c:1179:12: note: Left side of '&&' is true
 1179 |         if(!etm && local_mac && !CRYPT_FLAG_L(session, INTEGRATED_MAC)) {
      |            ^
src/transport.c:1179:20: note: 'local_mac' is null
 1179 |         if(!etm && local_mac && !CRYPT_FLAG_L(session, INTEGRATED_MAC)) {
      |                    ^~~~~~~~~
src/transport.c:1179:30: note: Left side of '&&' is false
 1179 |         if(!etm && local_mac && !CRYPT_FLAG_L(session, INTEGRATED_MAC)) {
      |                              ^
src/transport.c:1188:12: note: Assuming field 'crypt' is non-null
 1188 |         if(CRYPT_FLAG_L(session, REQUIRES_FULL_PACKET)) {
      |            ^
src/libssh2_priv.h:1073:38: note: expanded from macro 'CRYPT_FLAG_L'
 1073 | #define CRYPT_FLAG_L(session, flag) ((session)->local.crypt && \
      |                                      ^~~~~~~~~~~~~~~~~~~~~~
src/transport.c:1188:12: note: Left side of '&&' is true
 1188 |         if(CRYPT_FLAG_L(session, REQUIRES_FULL_PACKET)) {
      |            ^
src/libssh2_priv.h:1073:38: note: expanded from macro 'CRYPT_FLAG_L'
 1073 | #define CRYPT_FLAG_L(session, flag) ((session)->local.crypt && \
      |                                      ^
src/transport.c:1188:12: note: Assuming the condition is false
 1188 |         if(CRYPT_FLAG_L(session, REQUIRES_FULL_PACKET)) {
      |            ^
src/libssh2_priv.h:1074:6: note: expanded from macro 'CRYPT_FLAG_L'
 1074 |     ((session)->local.crypt->flags & LIBSSH2_CRYPT_FLAG_##flag))
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:1188:9: note: Taking false branch
 1188 |         if(CRYPT_FLAG_L(session, REQUIRES_FULL_PACKET)) {
      |         ^
src/transport.c:1204:39: note: Assuming 'i' is >= 'packet_length'
 1204 |             for(i = etm_crypt_offset; i < packet_length;
      |                                       ^~~~~~~~~~~~~~~~~
src/transport.c:1204:13: note: Loop condition is false. Execution continues on line 1240
 1204 |             for(i = etm_crypt_offset; i < packet_length;
      |             ^
src/transport.c:1240:16: note: Field 'crypt' is non-null
 1240 |             if(CRYPT_FLAG_L(session, INTEGRATED_MAC)) {
      |                ^
src/libssh2_priv.h:1073:55: note: expanded from macro 'CRYPT_FLAG_L'
 1073 | #define CRYPT_FLAG_L(session, flag) ((session)->local.crypt && \
      |                                                       ^
src/transport.c:1240:16: note: Left side of '&&' is true
 1240 |             if(CRYPT_FLAG_L(session, INTEGRATED_MAC)) {
      |                ^
src/libssh2_priv.h:1073:38: note: expanded from macro 'CRYPT_FLAG_L'
 1073 | #define CRYPT_FLAG_L(session, flag) ((session)->local.crypt && \
      |                                      ^
src/transport.c:1240:16: note: Assuming the condition is true
 1240 |             if(CRYPT_FLAG_L(session, INTEGRATED_MAC)) {
      |                ^
src/libssh2_priv.h:1074:6: note: expanded from macro 'CRYPT_FLAG_L'
 1074 |     ((session)->local.crypt->flags & LIBSSH2_CRYPT_FLAG_##flag))
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:1240:13: note: Taking true branch
 1240 |             if(CRYPT_FLAG_L(session, INTEGRATED_MAC)) {
      |             ^
src/transport.c:1241:31: note: Access to field 'mac_len' results in a dereference of a null pointer (loaded from variable 'local_mac')
 1241 |                 int authlen = local_mac->mac_len;
      |                               ^~~~~~~~~

in CI:
https://github.com/libssh2/libssh2/actions/runs/13981762088/job/39148285348?pr=1561#step:29:70 (Linux)
https://github.com/libssh2/libssh2/actions/runs/13981604140/job/39147800965?pr=1561#step:6:39 (mingw-w64)

@vszakats vszakats force-pushed the avoid-c-include branch 3 times, most recently from 6d859b6 to 3164745 Compare March 21, 2025 00:52
@vszakats
Copy link
Member Author

I silenced the 4, valid-looking issues in tranport.c, but
those are highly likely the wrong fixes, and only serve to
pass CI.

Would there be better ways to fix them?

@vszakats vszakats changed the title cmake: add support for clang-tidy, fix fallouts cmake: add support for clang-tidy, fix fallouts, silence 4 transport.c issues Mar 21, 2025
@willco007
Copy link
Member

@vszakats I have a bit of time today, I will look at them and see if I can figure out where things would go off the rails.

@willco007
Copy link
Member

Warning: p->padding_length = first_block[0]; would require blocksize to be zero which can't happen. Assigning first_block to zero seems like a fine fix in this case.

@willco007
Copy link
Member

Warning: p->padding_length = block[4]; would also require block size to be zero.

@willco007
Copy link
Member

Warning: (encrypted ? remote_mac->mac_len : 0); assumes remote.crypt goes from non-null to null...magically. Code reviewed with @MichaelBuckley and we couldn't see how this would be possible. Adding additional null check is a fine fix.

@willco007
Copy link
Member

Warning: local_mac->mac_len could potentially be hit if a crypt method was defined incorrectly. However, none of the crypt methods can hit this in reality. NULL check here is fine, it will prevent the crash and just fail to encrypt the value.

@vszakats
Copy link
Member Author

Warning: (encrypted ? remote_mac->mac_len : 0); assumes remote.crypt goes from non-null to null...magically. Code reviewed with @MichaelBuckley and we couldn't see how this would be possible. Adding additional null check is a fine fix.

clang-tidy is coming up with a plausible trace, at least, but it can be wrong, or miss context. (in #1561 (comment) under Details)

@vszakats
Copy link
Member Author

vszakats commented Mar 21, 2025

@willco007, @MichaelBuckley Thanks for looking into these! If I hear you right, all 4 fixes are fine, and 3 seem impossible combinations in reality. They also won't ruin anything. Therefore, I'm going for a merge after cleaning up, making a PR msg, etc.

@vszakats vszakats changed the title cmake: add support for clang-tidy, fix fallouts, silence 4 transport.c issues cmake: add support for clang-tidy, fix/silence fallouts Mar 21, 2025
vszakats added 11 commits March 24, 2025 14:07
```
src/misc.c:375:18: warning: Assigned value is garbage or undefined [clang-analyzer-core.uninitialized.Assign]
  375 |         *datalen = (unsigned int)dlen;
      |                  ^ ~~~~~~~~~~~~~~~~~~
```
```
src/publickey.c:53:16: warning: Excessive padding in 'struct _LIBSSH2_PUBLICKEY_CODE_LIST' (8 padding bytes, where 0 is optimal). Optimal fields order: name, code, name_len, consider reordering the fields or adding explicit padding members [clang-analyzer-optin.performance.Padding]
   53 | typedef struct _LIBSSH2_PUBLICKEY_CODE_LIST
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   54 | {
      | ~
   55 |     int code;
      |     ~~~~~~~~~
   56 |     const char *name;
      |     ~~~~~~~~~~~~~~~~~
   57 |     int name_len;
      |     ~~~~~~~~~~~~~
   58 | } LIBSSH2_PUBLICKEY_CODE_LIST;
      | ~
```
```
src/packet.c:883:25: warning: Null pointer passed as 1st argument to memory comparison function [clang-analyzer-unix.cstring.NullArg]
  883 |                         memcmp(name, "server-sig-algs", 15) == 0) {
      |                         ^      ~~~~
```
```
src/packet.c:894:29: warning: Null pointer passed as 2nd argument to memory copy function [clang-analyzer-unix.cstring.NullArg]
  894 |                             memcpy(session->server_sign_algorithms,
      |                             ^
```
```
src/openssl.c:1098:9: warning: Value stored to 'rc' is never read [clang-analyzer-deadcode.DeadStores]
 1098 |         rc = 0;
      |         ^    ~
src/openssl.c:1098:9: note: Value stored to 'rc' is never read
 1098 |         rc = 0;
      |         ^    ~
src/openssl.c:2279:9: warning: Value stored to 'ret' is never read [clang-analyzer-deadcode.DeadStores]
 2279 |         ret = -1;
      |         ^     ~~
src/openssl.c:2279:9: note: Value stored to 'ret' is never read
 2279 |         ret = -1;
      |         ^     ~~
src/openssl.c:2293:9: warning: Value stored to 'ret' is never read [clang-analyzer-deadcode.DeadStores]
 2293 |         ret = -1;
      |         ^     ~~
src/openssl.c:2293:9: note: Value stored to 'ret' is never read
 2293 |         ret = -1;
      |         ^     ~~
src/openssl.c:2316:13: warning: Value stored to 'ret' is never read [clang-analyzer-deadcode.DeadStores]
 2316 |             ret = -1;
      |             ^     ~~
src/openssl.c:2316:13: note: Value stored to 'ret' is never read
 2316 |             ret = -1;
      |             ^     ~~
```
```
src/knownhost.c:182:43: warning: Null pointer passed as 1st argument to string length function [clang-analyzer-unix.cstring.NullArg]
  182 |                                     salt, strlen(salt));
      |                                           ^
```
```
src/sftp.c:957:9: warning: Value stored to 'rc' is never read [clang-analyzer-deadcode.DeadStores]
  957 |         rc = LIBSSH2_ERROR_BUFFER_TOO_SMALL;
      |         ^
```
```
example/ssh2_agent_forwarding.c:153:9: warning: Value stored to 'rc' is never read [clang-analyzer-deadcode.DeadStores]
  153 |         rc = 1;
      |         ^    ~
```
```
tests/test_read.c:48:57: warning: Null pointer passed as 1st argument to string length function [clang-analyzer-unix.cstring.NullArg]
   48 |                                           (unsigned int)strlen(username));
      |                                                         ^      ~~~~~~~~
```
```
tests/session_fixture.c:487:57: warning: Null pointer passed as 1st argument to string length function [clang-analyzer-unix.cstring.NullArg]
  487 |                                           (unsigned int)strlen(username));
      |                                                         ^      ~~~~~~~~
```
```
src/userauth.c:1776:13: warning: Value stored to 'rc' is never read [clang-analyzer-deadcode.DeadStores]
 1776 |             rc = LIBSSH2_ERROR_NONE;
      |             ^
```
vszakats added 15 commits March 24, 2025 14:07
```
src/kex.c:3484:13: warning: Value stored to 'p' is never read [clang-analyzer-deadcode.DeadStores]
 3484 |             p += lang_sc_len + 4;
      |             ^    ~~~~~~~~~~~~~~~
```
```
src/wincng.c:79:9: error: macro is not used [clang-diagnostic-unused-macros,-warnings-as-errors]
   79 | #define PEM_ECDSA_HEADER "-----BEGIN OPENSSH PRIVATE KEY-----"
      |         ^
src/wincng.c:80:9: error: macro is not used [clang-diagnostic-unused-macros,-warnings-as-errors]
   80 | #define PEM_ECDSA_FOOTER "-----END OPENSSH PRIVATE KEY-----"
      |         ^
```
```
src/wincng.c:3614:15: error: Array access (from variable 'bignum') results in a null pointer dereference [clang-analyzer-core.NullDereference,-warnings-as-errors]
 3614 |     bignum[0] &= (unsigned char)((1 << bits) - 1);
      |               ^
```
```
example/scp_write_nonblock.c:142:9: error: Opened stream never closed. Potential resource leak [clang-analyzer-unix.Stream,-warnings-as-errors]
  142 |         fprintf(stderr, "failed to create socket.\n");
      |         ^~~~~~~
```
rewind returns an error condition in errno. errno is problematic
and reduces portability. Use fseek to avoid errno.

```
tests/session_fixture.c:443:14: error: Value of 'errno' was not checked and may be overwritten by function 'calloc' [clang-analyzer-unix.Errno,-warnings-as-errors]
  443 |     buffer = calloc(1, (size_t)len + 1);
      |              ^
```
rewind returns an error condition in errno. errno is problematic
and reduces portability. Use fseek to avoid errno.

```
src/userauth.c:683:9: error: Value of 'errno' was not checked and may be overwritten by function 'fclose' [clang-analyzer-unix.Errno,-warnings-as-errors]
  683 |         fclose(fd);
      |         ^
```
```
example/scp_write_nonblock.c:142:9: error: Opened stream never closed. Potential resource leak [clang-analyzer-unix.Stream,-warnings-as-errors]
  142 |         fprintf(stderr, "failed to create socket.\n");
      |         ^~~~~~~
```
```
example/sftp_write_sliding.c:148:9: error: Opened stream never closed. Potential resource leak [clang-analyzer-unix.Stream,-warnings-as-errors]
  148 |         fprintf(stderr, "failed to create socket.\n");
      |         ^~~~~~~
```
```
../../src/openssl.c:247:1: error: unused function '_libssh2_swap_bytes' [-Werror,-Wunused-function]
_libssh2_swap_bytes(unsigned char *buf, unsigned long len)
^
```

Detected now that openssl.c is no longer #included.
Avoid unnecessary inline assigments, that were ignored for the second
block and replaceable with a `ret = 0` initialization for the first.

Fix ignoring the failure of the second block, and calling
mbedtls_rsa_check_privkey unconditionally.
Assessment by @willco007:
Warning: `p->padding_length = first_block[0];` would require `blocksize`
to be zero which can't happen. Assigning first_block to zero seems like
a fine fix in this case.

```
src/transport.c:259:35: warning: Assigned value is garbage or undefined [clang-analyzer-core.uninitialized.Assign]
  259 |                 p->padding_length = first_block[0];
      |                                   ^
```

Full breakdown:
```
src/transport.c:259:35: warning: Assigned value is garbage or undefined [clang-analyzer-core.uninitialized.Assign]
  259 |                 p->padding_length = first_block[0];
      |                                   ^
src/transport.c:400:8: note: Assuming the condition is false
  400 |     if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:400:55: note: Left side of '&&' is false
  400 |     if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
      |                                                       ^
src/transport.c:418:8: note: Assuming field 'readPack_state' is equal to libssh2_NB_state_jump1
  418 |     if(session->readPack_state == libssh2_NB_state_jump1) {
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:418:5: note: Taking true branch
  418 |     if(session->readPack_state == libssh2_NB_state_jump1) {
      |     ^
src/transport.c:421:9: note: Control jumps to line 871
  421 |         goto libssh2_transport_read_point1;
      |         ^
src/transport.c:871:18: note: Calling 'fullpacket'
  871 |             rc = fullpacket(session, encrypted);
      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:191:8: note: Assuming 'encrypted' is not equal to 0
  191 |     if(!encrypted || (!CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET) &&
      |        ^~~~~~~~~~
src/transport.c:191:8: note: Left side of '||' is false
src/transport.c:191:24: note: Assuming field 'crypt' is null
  191 |     if(!encrypted || (!CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET) &&
      |                        ^
src/libssh2_priv.h:1076:38: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                      ^~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:191:24: note: Left side of '&&' is false
  191 |     if(!encrypted || (!CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET) &&
      |                        ^
src/libssh2_priv.h:1076:62: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                                              ^
src/transport.c:191:23: note: Left side of '&&' is true
  191 |     if(!encrypted || (!CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET) &&
      |                       ^
src/transport.c:192:24: note: Field 'crypt' is null
  192 |                       !CRYPT_FLAG_R(session, INTEGRATED_MAC))) {
      |                        ^
src/libssh2_priv.h:1076:56: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                                        ^
src/transport.c:192:24: note: Left side of '&&' is false
  192 |                       !CRYPT_FLAG_R(session, INTEGRATED_MAC))) {
      |                        ^
src/libssh2_priv.h:1076:62: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                                              ^
src/transport.c:191:5: note: Taking true branch
  191 |     if(!encrypted || (!CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET) &&
      |     ^
src/transport.c:196:8: note: Assuming field 'fullpacket_state' is equal to libssh2_NB_state_idle
  196 |     if(session->fullpacket_state == libssh2_NB_state_idle) {
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:196:5: note: Taking true branch
  196 |     if(session->fullpacket_state == libssh2_NB_state_idle) {
      |     ^
src/transport.c:200:12: note: 'encrypted' is not equal to 0
  200 |         if(encrypted && remote_mac) {
      |            ^~~~~~~~~
src/transport.c:200:12: note: Left side of '&&' is true
src/transport.c:200:25: note: Assuming 'remote_mac' is non-null
  200 |         if(encrypted && remote_mac) {
      |                         ^~~~~~~~~~
src/transport.c:200:9: note: Taking true branch
  200 |         if(encrypted && remote_mac) {
      |         ^
src/transport.c:205:16: note: Assuming 'etm' is not equal to 0
  205 |             if(etm) {
      |                ^~~
src/transport.c:205:13: note: Taking true branch
  205 |             if(etm) {
      |             ^
src/transport.c:228:16: note: Assuming the condition is false
  228 |             if(memcmp(macbuf, p->payload + p->total_num - mac_len, mac_len)) {
      |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:228:13: note: Taking false branch
  228 |             if(memcmp(macbuf, p->payload + p->total_num - mac_len, mac_len)) {
      |             ^
src/transport.c:234:21: note: 'etm' is not equal to 0
  234 |             else if(etm) {
      |                     ^~~
src/transport.c:234:18: note: Taking true branch
  234 |             else if(etm) {
      |                  ^
src/transport.c:244:22: note: Calling 'decrypt'
  244 |                 rc = decrypt(session, p->payload + 4,
      |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  245 |                              first_block, blocksize, FIRST_BLOCK);
      |                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:137:9: note: Assuming field 'crypt' is non-null
  137 |     if(!CRYPT_FLAG_L(session, PKTLEN_AAD))
      |         ^
src/libssh2_priv.h:1073:38: note: expanded from macro 'CRYPT_FLAG_L'
 1073 | #define CRYPT_FLAG_L(session, flag) ((session)->local.crypt && \
      |                                      ^~~~~~~~~~~~~~~~~~~~~~
src/transport.c:137:9: note: Left side of '&&' is true
  137 |     if(!CRYPT_FLAG_L(session, PKTLEN_AAD))
      |         ^
src/libssh2_priv.h:1073:38: note: expanded from macro 'CRYPT_FLAG_L'
 1073 | #define CRYPT_FLAG_L(session, flag) ((session)->local.crypt && \
      |                                      ^
src/transport.c:137:8: note: Assuming the condition is false
  137 |     if(!CRYPT_FLAG_L(session, PKTLEN_AAD))
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:137:5: note: Taking false branch
  137 |     if(!CRYPT_FLAG_L(session, PKTLEN_AAD))
      |     ^
src/transport.c:140:11: note: Assuming 'len' is <= 0
  140 |     while(len > 0) {
      |           ^~~~~~~
src/transport.c:140:5: note: Loop condition is false. Execution continues on line 174
  140 |     while(len > 0) {
      |     ^
src/transport.c:174:5: note: Returning without writing to '*dest'
  174 |     return LIBSSH2_ERROR_NONE;         /* all is fine */
      |     ^
src/transport.c:174:5: note: Returning zero, which participates in a condition later
  174 |     return LIBSSH2_ERROR_NONE;         /* all is fine */
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:244:22: note: Returning from 'decrypt'
  244 |                 rc = decrypt(session, p->payload + 4,
      |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  245 |                              first_block, blocksize, FIRST_BLOCK);
      |                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:246:20: note: 'rc' is 0
  246 |                 if(rc) {
      |                    ^~
src/transport.c:246:17: note: Taking false branch
  246 |                 if(rc) {
      |                 ^
src/transport.c:253:20: note: Assuming 'decrypt_buffer' is non-null
  253 |                 if(!decrypt_buffer) {
      |                    ^~~~~~~~~~~~~~~
src/transport.c:253:17: note: Taking false branch
  253 |                 if(!decrypt_buffer) {
      |                 ^
src/transport.c:259:35: note: Assigned value is garbage or undefined
  259 |                 p->padding_length = first_block[0];
      |                                   ^ ~~~~~~~~~~~~~~
```
Assessment by @willco007:
Warning: `p->padding_length = block[4];` would also require block size
to be zero.

```
src/transport.c:619:39: warning: Assigned value is garbage or undefined [clang-analyzer-core.uninitialized.Assign]
  619 |                     p->padding_length = block[4];
      |                                       ^ ~~~~~~~~
src/transport.c:400:8: note: Assuming the condition is false
  400 |     if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:400:55: note: Left side of '&&' is false
  400 |     if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
      |                                                       ^
src/transport.c:418:8: note: Assuming field 'readPack_state' is not equal to libssh2_NB_state_jump1
  418 |     if(session->readPack_state == libssh2_NB_state_jump1) {
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:418:5: note: Taking false branch
  418 |     if(session->readPack_state == libssh2_NB_state_jump1) {
      |     ^
src/transport.c:426:12: note: Assuming the condition is false
  426 |         if(session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:426:9: note: Taking false branch
  426 |         if(session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
      |         ^
src/transport.c:430:12: note: Assuming the condition is true
  430 |         if(session->state & LIBSSH2_STATE_NEWKEYS) {
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:430:9: note: Taking true branch
  430 |         if(session->state & LIBSSH2_STATE_NEWKEYS) {
      |         ^
src/transport.c:439:12: note: 'encrypted' is 1
  439 |         if(encrypted) {
      |            ^~~~~~~~~
src/transport.c:439:9: note: Taking true branch
  439 |         if(encrypted) {
      |         ^
src/transport.c:440:16: note: Field 'crypt' is non-null
  440 |             if(CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                ^
src/libssh2_priv.h:1076:56: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                                        ^
src/transport.c:440:16: note: Left side of '&&' is true
  440 |             if(CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                ^
src/libssh2_priv.h:1076:38: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                      ^
src/transport.c:440:16: note: Assuming the condition is false
  440 |             if(CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                ^
src/libssh2_priv.h:1077:6: note: expanded from macro 'CRYPT_FLAG_R'
 1077 |     ((session)->remote.crypt->flags & LIBSSH2_CRYPT_FLAG_##flag))
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:440:13: note: Taking false branch
  440 |             if(CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |             ^
src/transport.c:448:15: note: 'encrypted' is 1
  448 |         etm = encrypted && remote_mac ? remote_mac->etm : 0;
      |               ^~~~~~~~~
src/transport.c:448:15: note: Left side of '&&' is true
src/transport.c:448:28: note: Assuming 'remote_mac' is null
  448 |         etm = encrypted && remote_mac ? remote_mac->etm : 0;
      |                            ^~~~~~~~~~
src/transport.c:448:15: note: '?' condition is false
  448 |         etm = encrypted && remote_mac ? remote_mac->etm : 0;
      |               ^
src/transport.c:461:16: note: Assuming 'remainbuf' is >= 0
  461 |         assert(remainbuf >= 0);
      |                ^
/Library/Developer/CommandLineTools/SDKs/MacOSX13.1.sdk/usr/include/assert.h:99:25: note: expanded from macro 'assert'
   99 |     (__builtin_expect(!(e), 0) ? __assert_rtn(__func__, __ASSERT_FILE_NAME, __LINE__, #e) : (void)0)
      |                         ^
src/transport.c:461:9: note: '?' condition is false
  461 |         assert(remainbuf >= 0);
      |         ^
/Library/Developer/CommandLineTools/SDKs/MacOSX13.1.sdk/usr/include/assert.h:99:6: note: expanded from macro 'assert'
   99 |     (__builtin_expect(!(e), 0) ? __assert_rtn(__func__, __ASSERT_FILE_NAME, __LINE__, #e) : (void)0)
      |      ^
src/transport.c:463:12: note: Assuming 'remainbuf' is >= 'blocksize'
  463 |         if(remainbuf < blocksize ||
      |            ^~~~~~~~~~~~~~~~~~~~~
src/transport.c:463:12: note: Left side of '||' is false
src/transport.c:464:13: note: Field 'crypt' is non-null
  464 |            (CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)
      |             ^
src/libssh2_priv.h:1076:56: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                                        ^
src/transport.c:464:13: note: Left side of '&&' is true
  464 |            (CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)
      |             ^
src/libssh2_priv.h:1076:38: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                      ^
src/transport.c:465:13: note: Left side of '&&' is false
  465 |             && ((ssize_t)p->total_num) > remainbuf)) {
      |             ^
src/transport.c:517:12: note: Assuming field 'total_num' is 0
  517 |         if(!p->total_num) {
      |            ^~~~~~~~~~~~~
src/transport.c:517:9: note: Taking true branch
  517 |         if(!p->total_num) {
      |         ^
src/transport.c:524:37: note: 'etm' is 0
  524 |             ssize_t required_size = etm ? 4 : blocksize;
      |                                     ^~~
src/transport.c:524:37: note: '?' condition is false
src/transport.c:530:16: note: 'numbytes' is >= 'required_size'
  530 |             if(numbytes < required_size) {
      |                ^~~~~~~~
src/transport.c:530:13: note: Taking false branch
  530 |             if(numbytes < required_size) {
      |             ^
src/transport.c:540:16: note: 'etm' is 0
  540 |             if(etm) {
      |                ^~~
src/transport.c:540:13: note: Taking false branch
  540 |             if(etm) {
      |             ^
src/transport.c:545:21: note: 'encrypted' is 1
  545 |             else if(encrypted && session->remote.crypt->get_len) {
      |                     ^~~~~~~~~
src/transport.c:545:21: note: Left side of '&&' is true
src/transport.c:545:34: note: Assuming field 'get_len' is null
  545 |             else if(encrypted && session->remote.crypt->get_len) {
      |                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:545:18: note: Taking false branch
  545 |             else if(encrypted && session->remote.crypt->get_len) {
      |                  ^
src/transport.c:572:20: note: 'encrypted' is 1
  572 |                 if(encrypted) {
      |                    ^~~~~~~~~
src/transport.c:572:17: note: Taking true branch
  572 |                 if(encrypted) {
      |                 ^
src/transport.c:574:26: note: Calling 'decrypt'
  574 |                     rc = decrypt(session, &p->buf[p->readidx],
      |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  575 |                                  block, blocksize, FIRST_BLOCK);
      |                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:137:9: note: Assuming field 'crypt' is non-null
  137 |     if(!CRYPT_FLAG_L(session, PKTLEN_AAD))
      |         ^
src/libssh2_priv.h:1073:38: note: expanded from macro 'CRYPT_FLAG_L'
 1073 | #define CRYPT_FLAG_L(session, flag) ((session)->local.crypt && \
      |                                      ^~~~~~~~~~~~~~~~~~~~~~
src/transport.c:137:9: note: Left side of '&&' is true
  137 |     if(!CRYPT_FLAG_L(session, PKTLEN_AAD))
      |         ^
src/libssh2_priv.h:1073:38: note: expanded from macro 'CRYPT_FLAG_L'
 1073 | #define CRYPT_FLAG_L(session, flag) ((session)->local.crypt && \
      |                                      ^
src/transport.c:137:8: note: Assuming the condition is false
  137 |     if(!CRYPT_FLAG_L(session, PKTLEN_AAD))
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:137:5: note: Taking false branch
  137 |     if(!CRYPT_FLAG_L(session, PKTLEN_AAD))
      |     ^
src/transport.c:140:11: note: Assuming 'len' is <= 0
  140 |     while(len > 0) {
      |           ^~~~~~~
src/transport.c:140:5: note: Loop condition is false. Execution continues on line 174
  140 |     while(len > 0) {
      |     ^
src/transport.c:574:26: note: Returning from 'decrypt'
  574 |                     rc = decrypt(session, &p->buf[p->readidx],
      |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  575 |                                  block, blocksize, FIRST_BLOCK);
      |                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:576:24: note: 'rc' is equal to LIBSSH2_ERROR_NONE
  576 |                     if(rc != LIBSSH2_ERROR_NONE) {
      |                        ^~
src/transport.c:576:21: note: Taking false branch
  576 |                     if(rc != LIBSSH2_ERROR_NONE) {
      |                     ^
src/transport.c:599:17: note: 'encrypted' is 1
  599 |             if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                 ^~~~~~~~~
src/transport.c:599:16: note: Left side of '||' is false
  599 |             if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                ^
src/transport.c:599:31: note: Field 'crypt' is non-null
  599 |             if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                               ^
src/libssh2_priv.h:1076:56: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                                        ^
src/transport.c:599:31: note: Left side of '&&' is true
  599 |             if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |                               ^
src/libssh2_priv.h:1076:38: note: expanded from macro 'CRYPT_FLAG_R'
 1076 | #define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \
      |                                      ^
src/transport.c:599:13: note: Taking true branch
  599 |             if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) {
      |             ^
src/transport.c:600:20: note: Assuming field 'packet_length' is >= 1
  600 |                 if(p->packet_length < 1) {
      |                    ^~~~~~~~~~~~~~~~~~~~
src/transport.c:600:17: note: Taking false branch
  600 |                 if(p->packet_length < 1) {
      |                 ^
src/transport.c:603:25: note: Assuming field 'packet_length' is <= LIBSSH2_PACKET_MAXPAYLOAD
  603 |                 else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD) {
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/transport.c:603:22: note: Taking false branch
  603 |                 else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD) {
      |                      ^
src/transport.c:607:20: note: 'etm' is 0
  607 |                 if(etm) {
      |                    ^~~
src/transport.c:607:17: note: Taking false branch
  607 |                 if(etm) {
      |                 ^
src/transport.c:619:39: note: Assigned value is garbage or undefined
  619 |                     p->padding_length = block[4];
      |                                       ^ ~~~~~~~~
```
Assessment by @willco007:
Warning: `(encrypted ? remote_mac->mac_len : 0);` assumes `remote.crypt`
goes from non-null to null...magically. Code reviewed with
@MichaelBuckley and we couldn't see how this would be possible. Adding
additional null check is a fine fix.

```
src/transport.c:627:34: error: Access to field 'mac_len' results in a dereference of a null pointer (loaded from variable 'remote_mac') [clang-analyzer-core.NullDereference,-warnings-as-errors]
  627 |                     (encrypted ? remote_mac->mac_len : 0);
      |                                  ^~~~~~~~~~
```
Assessment by @willco007:
Warning: `local_mac->mac_len` could potentially be hit if a crypt method
was defined incorrectly. However, none of the crypt methods can hit this
in reality. NULL check here is fine, it will prevent the crash and just
fail to encrypt the value.

```
src/transport.c:1241:31: error: Access to field 'mac_len' results in a dereference of a null pointer (loaded from variable 'local_mac') [clang-analyzer-core.NullDereference,-warnings-as-errors]
 1241 |                 int authlen = local_mac->mac_len;
      |                               ^~~~~~~~~
```
vszakats added a commit that referenced this pull request Mar 24, 2025
To play better with code checkers and compilers that are blind to
included C sources, e.g. clang with certain compiler warnings and
clang-tidy.

Follow-up to 4f0f4bf #941
Cherry-picked from #1561
vszakats added a commit that referenced this pull request Mar 24, 2025
Instead build all crypto backend sources always, and exclude inactive
ones with guards.

To play better with code checkers and compilers that are blind to
included C sources, e.g. clang with certain compiler warnings and
clang-tidy.

We continue to include `blowfish.c`.

Follow-up to 4f0f4bf #941
Cherry-picked from #1561
vszakats added a commit that referenced this pull request Mar 24, 2025
vszakats added a commit that referenced this pull request Mar 24, 2025
Cherry-picked from #1561
vszakats added a commit that referenced this pull request Mar 24, 2025
To prepare for the addition of a clang-tidy job for Windows.

Cherry-picked from #1561
@vszakats vszakats changed the title cmake: add support for clang-tidy, fix/silence fallouts clang-tidy: fix and/or silence all issues found, and some more Mar 24, 2025
@vszakats vszakats changed the title clang-tidy: fix and/or silence all issues found, and some more clang-tidy: fix and/or silence issues found, and some more Mar 24, 2025
@vszakats vszakats changed the title clang-tidy: fix and/or silence issues found, and some more clang-tidy: fix and/or silence issues found, and more Mar 24, 2025
@vszakats vszakats closed this in a1a28ac Mar 24, 2025
@vszakats vszakats deleted the avoid-c-include branch March 24, 2025 13:38
vszakats added a commit that referenced this pull request Mar 24, 2025
With their supported crypto backends.

Cherry-picked from #1561

Closes #1566
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants