client:
   47|      1|void *client(void *args){ 
   48|       |
   49|      1|    Fuzzer *fuzzer = (Fuzzer*)args;
   50|      1|    int sockfd;
   51|      1|    struct sockaddr_in serv_addr;
   52|       |
   53|      1|    sockfd = socket(AF_INET, SOCK_STREAM, 0);
   54|      1|    serv_addr.sin_family = AF_INET;
   55|      1|    serv_addr.sin_port = htons(fuzzer->port);
   56|      1|    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
   57|       |
   58|      1|    while(1){/* Try until connect*/
  ------------------
  |  Branch (58:11): [True: 1, Folded]
  ------------------
   59|      1|        if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
  ------------------
  |  Branch (59:13): [True: 0, False: 1]
  ------------------
   60|      0|            continue;
   61|      1|        }else{
   62|      1|            break;
   63|      1|        }
   64|      1|    }
   65|       |
   66|      1|    send(sockfd,fuzzer->buffer,fuzzer->size,0);
   67|       |
   68|      1|    close(sockfd);
   69|       |    pthread_exit(NULL);
   70|      1|}
LLVMFuzzerTestOneInput:
   72|     41|extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
   73|       |
   74|     41|    if (size < kMinInputLength || size > kMaxInputLength){
  ------------------
  |  |   29|     82|#define kMinInputLength 9
  ------------------
                  if (size < kMinInputLength || size > kMaxInputLength){
  ------------------
  |  |   30|     36|#define kMaxInputLength MODBUS_RTU_MAX_ADU_LENGTH
  |  |  ------------------
  |  |  |  |   17|     36|#define MODBUS_RTU_MAX_ADU_LENGTH 256
  |  |  ------------------
  ------------------
  |  Branch (74:9): [True: 5, False: 36]
  |  Branch (74:35): [True: 35, False: 1]
  ------------------
   75|     40|        return 0;
   76|     40|    }
   77|       |
   78|      1|    Fuzzer *fuzzer = (Fuzzer*)malloc(sizeof(Fuzzer));
   79|      1|    fuzzer->port = PORT;
  ------------------
  |  |   28|      1|#define PORT 8080
  ------------------
   80|       |
   81|      1|    fuzzer->size = size;
   82|      1|    fuzzer->buffer = data;
   83|       |
   84|      1|    pthread_create(&fuzzer->thread, NULL,client,fuzzer);
   85|      1|    server(fuzzer);
   86|      1|    pthread_join(fuzzer->thread, NULL); /* Avoid UAF*/
   87|       |
   88|      1|    free(fuzzer);
   89|      1|    return 0;
   90|     41|}
server:
   93|      1|{
   94|      1|    int s = -1;
   95|      1|    modbus_t *ctx;
   96|      1|    modbus_mapping_t *mb_mapping;
   97|      1|    int rc;
   98|      1|    int i;
   99|      1|    uint8_t *query;
  100|       |
  101|      1|    ctx = modbus_new_tcp("127.0.0.1", fuzzer->port);
  102|      1|    query = malloc(MODBUS_TCP_MAX_ADU_LENGTH);
  ------------------
  |  |   40|      1|#define MODBUS_TCP_MAX_ADU_LENGTH 260
  ------------------
  103|       |
  104|      1|    mb_mapping = modbus_mapping_new_start_address(
  105|      1|        UT_BITS_ADDRESS, UT_BITS_NB,
  ------------------
  |  |   31|      1|#define UT_BITS_NB 0x25
  ------------------
  106|      1|        UT_INPUT_BITS_ADDRESS, UT_INPUT_BITS_NB,
  107|      1|        UT_REGISTERS_ADDRESS, UT_REGISTERS_NB_MAX,
  108|      1|        UT_INPUT_REGISTERS_ADDRESS, UT_INPUT_REGISTERS_NB);
  109|      1|    if (mb_mapping == NULL) {
  ------------------
  |  Branch (109:9): [True: 0, False: 1]
  ------------------
  110|      0|        fprintf(stderr, "Failed to allocate the mapping: %s\n",
  111|      0|                modbus_strerror(errno));
  112|      0|        modbus_free(ctx);
  113|      0|        return -1;
  114|      0|    }
  115|       |
  116|       |    /* Initialize input values that's can be only done server side. */
  117|      1|    modbus_set_bits_from_bytes(mb_mapping->tab_input_bits, 0, UT_INPUT_BITS_NB,
  118|      1|                               UT_INPUT_BITS_TAB);
  119|       |
  120|       |    /* Initialize values of INPUT REGISTERS */
  121|      2|    for (i=0; i < UT_INPUT_REGISTERS_NB; i++) {
  ------------------
  |  Branch (121:15): [True: 1, False: 1]
  ------------------
  122|      1|        mb_mapping->tab_input_registers[i] = UT_INPUT_REGISTERS_TAB[i];
  123|      1|    }
  124|       |
  125|      1|    s = modbus_tcp_listen(ctx, 1);
  126|      1|    modbus_tcp_accept(ctx, &s);
  127|       |
  128|      1|    rc = modbus_receive(ctx, query);
  129|       |
  130|      1|    if (s != -1) {
  ------------------
  |  Branch (130:9): [True: 1, False: 0]
  ------------------
  131|      1|        close(s);
  132|      1|    }
  133|       |
  134|      1|    modbus_mapping_free(mb_mapping);
  135|      1|    free(query);
  136|       |    /* For RTU */
  137|      1|    modbus_close(ctx);
  138|      1|    modbus_free(ctx);
  139|       |
  140|      1|    return rc;
  141|      1|}

modbus_set_bits_from_bytes:
   47|      1|{
   48|      1|    unsigned int i;
   49|      1|    int shift = 0;
   50|       |
   51|     23|    for (i = idx; i < idx + nb_bits; i++) {
  ------------------
  |  Branch (51:19): [True: 22, False: 1]
  ------------------
   52|     22|        dest[i] = tab_byte[(i - idx) / 8] & (1 << shift) ? 1 : 0;
  ------------------
  |  Branch (52:19): [True: 14, False: 8]
  ------------------
   53|       |        /* gcc doesn't like: shift = (++shift) % 8; */
   54|     22|        shift++;
   55|     22|        shift %= 8;
   56|     22|    }
   57|      1|}

modbus_tcp_listen:
  586|      1|{
  587|      1|    int new_s;
  588|      1|    int enable;
  589|      1|    int flags;
  590|      1|    struct sockaddr_in addr;
  591|      1|    modbus_tcp_t *ctx_tcp;
  592|      1|    int rc;
  593|       |
  594|      1|    if (ctx == NULL) {
  ------------------
  |  Branch (594:9): [True: 0, False: 1]
  ------------------
  595|      0|        errno = EINVAL;
  596|      0|        return -1;
  597|      0|    }
  598|       |
  599|      1|    ctx_tcp = ctx->backend_data;
  600|       |
  601|       |#ifdef OS_WIN32
  602|       |    if (_modbus_tcp_init_win32() == -1) {
  603|       |        return -1;
  604|       |    }
  605|       |#endif
  606|       |
  607|      1|    flags = SOCK_STREAM;
  608|       |
  609|      1|#ifdef SOCK_CLOEXEC
  610|      1|    flags |= SOCK_CLOEXEC;
  611|      1|#endif
  612|       |
  613|      1|    new_s = socket(PF_INET, flags, IPPROTO_TCP);
  614|      1|    if (new_s == -1) {
  ------------------
  |  Branch (614:9): [True: 0, False: 1]
  ------------------
  615|      0|        return -1;
  616|      0|    }
  617|       |
  618|      1|    enable = 1;
  619|       |#ifdef _WIN32
  620|       |    if (setsockopt(new_s, SOL_SOCKET, SO_REUSEADDR, (const char *)&enable, sizeof(enable)) == -1) {
  621|       |#else
  622|      1|    if (setsockopt(new_s, SOL_SOCKET, SO_REUSEADDR, (const void *)&enable, sizeof(enable)) == -1) {
  ------------------
  |  Branch (622:9): [True: 0, False: 1]
  ------------------
  623|      0|#endif
  624|      0|        close(new_s);
  625|      0|        return -1;
  626|      0|    }
  627|       |
  628|      1|    memset(&addr, 0, sizeof(addr));
  629|      1|    addr.sin_family = AF_INET;
  630|       |    /* If the modbus port is < to 1024, we need the setuid root. */
  631|      1|    addr.sin_port = htons(ctx_tcp->port);
  632|      1|    if (ctx_tcp->ip[0] == '0') {
  ------------------
  |  Branch (632:9): [True: 0, False: 1]
  ------------------
  633|       |        /* Listen any addresses */
  634|      0|        addr.sin_addr.s_addr = htonl(INADDR_ANY);
  635|      1|    } else {
  636|       |        /* Listen only specified IP address */
  637|      1|        rc = inet_pton(addr.sin_family, ctx_tcp->ip, &(addr.sin_addr));
  638|      1|        if (rc <= 0) {
  ------------------
  |  Branch (638:13): [True: 0, False: 1]
  ------------------
  639|      0|            if (ctx->debug) {
  ------------------
  |  Branch (639:17): [True: 0, False: 0]
  ------------------
  640|      0|                fprintf(stderr, "Invalid IP address: %s\n", ctx_tcp->ip);
  641|      0|            }
  642|      0|            close(new_s);
  643|      0|            return -1;
  644|      0|        }
  645|      1|    }
  646|       |
  647|      1|    if (bind(new_s, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
  ------------------
  |  Branch (647:9): [True: 0, False: 1]
  ------------------
  648|      0|        close(new_s);
  649|      0|        return -1;
  650|      0|    }
  651|       |
  652|      1|    if (listen(new_s, nb_connection) == -1) {
  ------------------
  |  Branch (652:9): [True: 0, False: 1]
  ------------------
  653|      0|        close(new_s);
  654|      0|        return -1;
  655|      0|    }
  656|       |
  657|      1|    return new_s;
  658|      1|}
modbus_tcp_accept:
  787|      1|{
  788|      1|    struct sockaddr_in addr;
  789|      1|    socklen_t addrlen;
  790|       |
  791|      1|    if (ctx == NULL) {
  ------------------
  |  Branch (791:9): [True: 0, False: 1]
  ------------------
  792|      0|        errno = EINVAL;
  793|      0|        return -1;
  794|      0|    }
  795|       |
  796|      1|    addrlen = sizeof(addr);
  797|      1|#ifdef HAVE_ACCEPT4
  798|       |    /* Inherit socket flags and use accept4 call */
  799|      1|    ctx->s = accept4(*s, (struct sockaddr *) &addr, &addrlen, SOCK_CLOEXEC);
  800|       |#else
  801|       |    ctx->s = accept(*s, (struct sockaddr *) &addr, &addrlen);
  802|       |#endif
  803|       |
  804|      1|    if (ctx->s < 0) {
  ------------------
  |  Branch (804:9): [True: 0, False: 1]
  ------------------
  805|      0|        return -1;
  806|      0|    }
  807|       |
  808|      1|    if (ctx->s >= FD_SETSIZE) {
  ------------------
  |  Branch (808:9): [True: 0, False: 1]
  ------------------
  809|      0|        if (ctx->debug) {
  ------------------
  |  Branch (809:13): [True: 0, False: 0]
  ------------------
  810|      0|            fprintf(
  811|      0|                stderr,
  812|      0|                "ERROR Socket descriptor %d exceeds FD_SETSIZE (%d)\n",
  813|      0|                ctx->s,
  814|      0|                FD_SETSIZE);
  815|      0|        }
  816|      0|        close(ctx->s);
  817|      0|        ctx->s = -1;
  818|      0|        errno = EINVAL;
  819|      0|        return -1;
  820|      0|    }
  821|       |
  822|      1|    if (ctx->debug) {
  ------------------
  |  Branch (822:9): [True: 0, False: 1]
  ------------------
  823|      0|        char buf[INET_ADDRSTRLEN];
  824|      0|        if (inet_ntop(AF_INET, &(addr.sin_addr), buf, INET_ADDRSTRLEN) == NULL) {
  ------------------
  |  Branch (824:13): [True: 0, False: 0]
  ------------------
  825|      0|            fprintf(stderr, "Client connection accepted from unparsable IP.\n");
  826|      0|        } else {
  827|      0|            printf("Client connection accepted from %s.\n", buf);
  828|      0|        }
  829|      0|    }
  830|       |
  831|      1|    return ctx->s;
  832|      1|}
modbus_new_tcp:
  981|      1|{
  982|      1|    modbus_t *ctx;
  983|      1|    modbus_tcp_t *ctx_tcp;
  984|      1|    size_t dest_size;
  985|      1|    size_t ret_size;
  986|       |
  987|       |#if defined(OS_BSD)
  988|       |    /* MSG_NOSIGNAL is unsupported on *BSD so we install an ignore
  989|       |       handler for SIGPIPE. */
  990|       |    struct sigaction sa;
  991|       |
  992|       |    memset(&sa, 0, sizeof(sa));
  993|       |    sa.sa_handler = SIG_IGN;
  994|       |    sigemptyset(&sa.sa_mask);
  995|       |    if (sigaction(SIGPIPE, &sa, NULL) < 0) {
  996|       |        /* The debug flag can't be set here... */
  997|       |        fprintf(stderr, "Could not install SIGPIPE handler.\n");
  998|       |        return NULL;
  999|       |    }
 1000|       |#endif
 1001|       |
 1002|      1|    ctx = (modbus_t *) malloc(sizeof(modbus_t));
 1003|      1|    if (ctx == NULL) {
  ------------------
  |  Branch (1003:9): [True: 0, False: 1]
  ------------------
 1004|      0|        return NULL;
 1005|      0|    }
 1006|      1|    _modbus_init_common(ctx);
 1007|       |
 1008|       |    /* Could be changed after to reach a remote serial Modbus device */
 1009|      1|    ctx->slave = MODBUS_TCP_SLAVE;
  ------------------
  |  |   35|      1|#define MODBUS_TCP_SLAVE        0xFF
  ------------------
 1010|       |
 1011|      1|    ctx->backend = &_modbus_tcp_backend;
 1012|       |
 1013|      1|    ctx->backend_data = (modbus_tcp_t *) malloc(sizeof(modbus_tcp_t));
 1014|      1|    if (ctx->backend_data == NULL) {
  ------------------
  |  Branch (1014:9): [True: 0, False: 1]
  ------------------
 1015|      0|        modbus_free(ctx);
 1016|      0|        errno = ENOMEM;
 1017|      0|        return NULL;
 1018|      0|    }
 1019|      1|    ctx_tcp = (modbus_tcp_t *) ctx->backend_data;
 1020|       |
 1021|      1|    if (ip != NULL) {
  ------------------
  |  Branch (1021:9): [True: 1, False: 0]
  ------------------
 1022|      1|        dest_size = sizeof(char) * 16;
 1023|      1|        ret_size = strlcpy(ctx_tcp->ip, ip, dest_size);
 1024|      1|        if (ret_size == 0) {
  ------------------
  |  Branch (1024:13): [True: 0, False: 1]
  ------------------
 1025|      0|            fprintf(stderr, "The IP string is empty\n");
 1026|      0|            modbus_free(ctx);
 1027|      0|            errno = EINVAL;
 1028|      0|            return NULL;
 1029|      0|        }
 1030|       |
 1031|      1|        if (ret_size >= dest_size) {
  ------------------
  |  Branch (1031:13): [True: 0, False: 1]
  ------------------
 1032|      0|            fprintf(stderr, "The IP string has been truncated\n");
 1033|      0|            modbus_free(ctx);
 1034|      0|            errno = EINVAL;
 1035|      0|            return NULL;
 1036|      0|        }
 1037|      1|    } else {
 1038|      0|        ctx_tcp->ip[0] = '0';
 1039|      0|        ctx_tcp->ip[1] = '\0';
 1040|      0|    }
 1041|      1|    ctx_tcp->port = port;
 1042|      1|    ctx_tcp->t_id = 0;
 1043|       |
 1044|      1|    return ctx;
 1045|      1|}
modbus-tcp.c:_modbus_tcp_receive:
  186|      1|{
  187|      1|    return _modbus_receive_msg(ctx, req, MSG_INDICATION);
  188|      1|}
modbus-tcp.c:_modbus_tcp_recv:
  191|      1|{
  192|      1|    return recv(ctx->s, (char *) rsp, rsp_length, 0);
  193|      1|}
modbus-tcp.c:_modbus_tcp_check_integrity:
  196|      1|{
  197|      1|    return msg_length;
  198|      1|}
modbus-tcp.c:_modbus_tcp_is_connected:
  519|      1|{
  520|      1|    return ctx->s >= 0;
  521|      1|}
modbus-tcp.c:_modbus_tcp_close:
  525|      1|{
  526|      1|    if (ctx->s >= 0) {
  ------------------
  |  Branch (526:9): [True: 1, False: 0]
  ------------------
  527|       |        shutdown(ctx->s, SHUT_RDWR);
  528|      1|        close(ctx->s);
  529|      1|        ctx->s = -1;
  530|      1|    }
  531|      1|}
modbus-tcp.c:_modbus_tcp_select:
  884|      1|{
  885|      1|    int s_rc;
  886|      1|    while ((s_rc = select(ctx->s + 1, rset, NULL, NULL, tv)) == -1) {
  ------------------
  |  Branch (886:12): [True: 0, False: 1]
  ------------------
  887|      0|        if (errno == EINTR) {
  ------------------
  |  Branch (887:13): [True: 0, False: 0]
  ------------------
  888|      0|            if (ctx->debug) {
  ------------------
  |  Branch (888:17): [True: 0, False: 0]
  ------------------
  889|      0|                fprintf(stderr, "A non blocked signal was caught\n");
  890|      0|            }
  891|       |            /* Necessary after an error */
  892|      0|            FD_ZERO(rset);
  ------------------
  |  Branch (892:13): [Folded, False: 0]
  ------------------
  893|      0|            if (ctx->s < 0 || ctx->s >= FD_SETSIZE) {
  ------------------
  |  Branch (893:17): [True: 0, False: 0]
  |  Branch (893:31): [True: 0, False: 0]
  ------------------
  894|      0|                errno = EINVAL;
  895|      0|                return -1;
  896|      0|            }
  897|      0|            FD_SET(ctx->s, rset);
  898|      0|        } else {
  899|      0|            return -1;
  900|      0|        }
  901|      0|    }
  902|       |
  903|      1|    if (s_rc == 0) {
  ------------------
  |  Branch (903:9): [True: 0, False: 1]
  ------------------
  904|      0|        errno = ETIMEDOUT;
  905|      0|        return -1;
  906|      0|    }
  907|       |
  908|      1|    return s_rc;
  909|      1|}
modbus-tcp.c:_modbus_tcp_free:
  912|      1|{
  913|      1|    if (ctx->backend_data) {
  ------------------
  |  Branch (913:9): [True: 1, False: 0]
  ------------------
  914|      1|        free(ctx->backend_data);
  915|      1|    }
  916|      1|    free(ctx);
  917|      1|}

_modbus_receive_msg:
  366|      1|{
  367|      1|    int rc;
  368|      1|    fd_set rset;
  369|      1|    struct timeval tv;
  370|      1|    struct timeval *p_tv;
  371|      1|    unsigned int length_to_read;
  372|      1|    int msg_length = 0;
  373|      1|    _step_t step;
  374|       |#ifdef _WIN32
  375|       |    int wsa_err;
  376|       |#endif
  377|       |
  378|      1|    if (ctx->debug) {
  ------------------
  |  Branch (378:9): [True: 0, False: 1]
  ------------------
  379|      0|        if (msg_type == MSG_INDICATION) {
  ------------------
  |  Branch (379:13): [True: 0, False: 0]
  ------------------
  380|      0|            printf("Waiting for an indication...\n");
  381|      0|        } else {
  382|      0|            printf("Waiting for a confirmation...\n");
  383|      0|        }
  384|      0|    }
  385|       |
  386|      1|    if (!ctx->backend->is_connected(ctx)) {
  ------------------
  |  Branch (386:9): [True: 0, False: 1]
  ------------------
  387|      0|        if (ctx->debug) {
  ------------------
  |  Branch (387:13): [True: 0, False: 0]
  ------------------
  388|      0|            fprintf(stderr, "ERROR The connection is not established.\n");
  389|      0|        }
  390|      0|        return -1;
  391|      0|    }
  392|       |
  393|       |    /* Add a file descriptor to the set */
  394|      1|    FD_ZERO(&rset);
  ------------------
  |  Branch (394:5): [Folded, False: 1]
  ------------------
  395|      1|    if (ctx->s < 0 || ctx->s >= FD_SETSIZE) {
  ------------------
  |  Branch (395:9): [True: 0, False: 1]
  |  Branch (395:23): [True: 0, False: 1]
  ------------------
  396|      0|        if (ctx->debug) {
  ------------------
  |  Branch (396:13): [True: 0, False: 0]
  ------------------
  397|      0|            fprintf(stderr, "ERROR Invalid socket descriptor %d\n", ctx->s);
  398|      0|        }
  399|      0|        errno = EINVAL;
  400|      0|        return -1;
  401|      0|    }
  402|      1|    FD_SET(ctx->s, &rset);
  403|       |
  404|       |    /* We need to analyse the message step by step.  At the first step, we want
  405|       |     * to reach the function code because all packets contain this
  406|       |     * information. */
  407|      1|    step = _STEP_FUNCTION;
  408|      1|    length_to_read = ctx->backend->header_length + 1;
  409|       |
  410|      1|    if (msg_type == MSG_INDICATION) {
  ------------------
  |  Branch (410:9): [True: 1, False: 0]
  ------------------
  411|       |        /* Wait for a message, we don't know when the message will be received */
  412|      1|        if (ctx->indication_timeout.tv_sec == 0 && ctx->indication_timeout.tv_usec == 0) {
  ------------------
  |  Branch (412:13): [True: 1, False: 0]
  |  Branch (412:52): [True: 1, False: 0]
  ------------------
  413|       |            /* By default, the indication timeout isn't set */
  414|      1|            p_tv = NULL;
  415|      1|        } else {
  416|       |            /* Wait for an indication (name of a received request by a server, see schema)
  417|       |             */
  418|      0|            tv.tv_sec = ctx->indication_timeout.tv_sec;
  419|      0|            tv.tv_usec = ctx->indication_timeout.tv_usec;
  420|      0|            p_tv = &tv;
  421|      0|        }
  422|      1|    } else {
  423|      0|        tv.tv_sec = ctx->response_timeout.tv_sec;
  424|      0|        tv.tv_usec = ctx->response_timeout.tv_usec;
  425|      0|        p_tv = &tv;
  426|      0|    }
  427|       |
  428|      2|    while (length_to_read != 0) {
  ------------------
  |  Branch (428:12): [True: 1, False: 1]
  ------------------
  429|      1|        rc = ctx->backend->select(ctx, &rset, p_tv, length_to_read);
  430|      1|        if (rc == -1) {
  ------------------
  |  Branch (430:13): [True: 0, False: 1]
  ------------------
  431|      0|            _error_print(ctx, "select");
  432|      0|            if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) {
  ------------------
  |  Branch (432:17): [True: 0, False: 0]
  ------------------
  433|       |#ifdef _WIN32
  434|       |                int saved_errno = errno;
  435|       |
  436|       |                wsa_err = WSAGetLastError();
  437|       |
  438|       |                // no equivalent to ETIMEDOUT when select fails on Windows
  439|       |                if (wsa_err == WSAENETDOWN || wsa_err == WSAENOTSOCK) {
  440|       |                    modbus_close(ctx);
  441|       |                    modbus_connect(ctx);
  442|       |                }
  443|       |                errno = saved_errno;
  444|       |#else
  445|      0|                int saved_errno = errno;
  446|       |
  447|      0|                if (errno == ETIMEDOUT) {
  ------------------
  |  Branch (447:21): [True: 0, False: 0]
  ------------------
  448|      0|                    _sleep_response_timeout(ctx);
  449|      0|                    modbus_flush(ctx);
  450|      0|                } else if (errno == EBADF) {
  ------------------
  |  Branch (450:28): [True: 0, False: 0]
  ------------------
  451|      0|                    modbus_close(ctx);
  452|      0|                    modbus_connect(ctx);
  453|      0|                }
  454|      0|                errno = saved_errno;
  455|      0|#endif
  456|      0|            }
  457|      0|            return -1;
  458|      0|        }
  459|       |
  460|      1|        rc = ctx->backend->recv(ctx, msg + msg_length, length_to_read);
  461|      1|        if (rc == 0) {
  ------------------
  |  Branch (461:13): [True: 0, False: 1]
  ------------------
  462|      0|            errno = ECONNRESET;
  463|      0|            rc = -1;
  464|      0|        }
  465|       |
  466|      1|        if (rc == -1) {
  ------------------
  |  Branch (466:13): [True: 0, False: 1]
  ------------------
  467|      0|            _error_print(ctx, "read");
  468|       |#ifdef _WIN32
  469|       |            wsa_err = WSAGetLastError();
  470|       |            if ((ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) &&
  471|       |                (wsa_err == WSAENOTCONN || wsa_err == WSAENETRESET ||
  472|       |                 wsa_err == WSAENOTSOCK || wsa_err == WSAESHUTDOWN ||
  473|       |                 wsa_err == WSAECONNABORTED || wsa_err == WSAETIMEDOUT ||
  474|       |                 wsa_err == WSAECONNRESET)) {
  475|       |                int saved_errno = errno;
  476|       |                modbus_close(ctx);
  477|       |                modbus_connect(ctx);
  478|       |                /* Could be removed by previous calls */
  479|       |                errno = saved_errno;
  480|       |            }
  481|       |#else
  482|      0|            if ((ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) &&
  ------------------
  |  Branch (482:17): [True: 0, False: 0]
  ------------------
  483|      0|                (errno == ECONNRESET || errno == ECONNREFUSED || errno == EBADF)) {
  ------------------
  |  Branch (483:18): [True: 0, False: 0]
  |  Branch (483:41): [True: 0, False: 0]
  |  Branch (483:66): [True: 0, False: 0]
  ------------------
  484|      0|                int saved_errno = errno;
  485|      0|                modbus_close(ctx);
  486|      0|                modbus_connect(ctx);
  487|       |                /* Could be removed by previous calls */
  488|      0|                errno = saved_errno;
  489|      0|            }
  490|      0|#endif
  491|      0|            return -1;
  492|      0|        }
  493|       |
  494|       |        /* Display the hex code of each character received */
  495|      1|        if (ctx->debug) {
  ------------------
  |  Branch (495:13): [True: 0, False: 1]
  ------------------
  496|      0|            int i;
  497|      0|            for (i = 0; i < rc; i++)
  ------------------
  |  Branch (497:25): [True: 0, False: 0]
  ------------------
  498|      0|                printf("<%.2X>", msg[msg_length + i]);
  499|      0|        }
  500|       |
  501|       |        /* Sums bytes received */
  502|      1|        msg_length += rc;
  503|       |        /* Computes remaining bytes */
  504|      1|        length_to_read -= rc;
  505|       |
  506|      1|        if (length_to_read == 0) {
  ------------------
  |  Branch (506:13): [True: 1, False: 0]
  ------------------
  507|      1|            switch (step) {
  508|      1|            case _STEP_FUNCTION:
  ------------------
  |  Branch (508:13): [True: 1, False: 0]
  ------------------
  509|       |                /* Function code position */
  510|      1|                length_to_read = compute_meta_length_after_function(
  511|      1|                    msg[ctx->backend->header_length], msg_type);
  512|      1|                if (length_to_read != 0) {
  ------------------
  |  Branch (512:21): [True: 0, False: 1]
  ------------------
  513|      0|                    step = _STEP_META;
  514|      0|                    break;
  515|      0|                } /* else switches straight to the next step */
  516|      1|            case _STEP_META:
  ------------------
  |  Branch (516:13): [True: 0, False: 1]
  ------------------
  517|      1|                length_to_read = compute_data_length_after_meta(ctx, msg, msg_type);
  518|      1|                if ((msg_length + length_to_read) > ctx->backend->max_adu_length) {
  ------------------
  |  Branch (518:21): [True: 0, False: 1]
  ------------------
  519|      0|                    errno = EMBBADDATA;
  ------------------
  |  |  147|      0|#define EMBBADDATA  (EMBXGTAR + 2)
  |  |  ------------------
  |  |  |  |  143|      0|#define EMBXGTAR   (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_TARGET)
  |  |  |  |  ------------------
  |  |  |  |  |  |  116|      0|#define MODBUS_ENOBASE 112345678
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  520|      0|                    _error_print(ctx, "too many data");
  521|      0|                    return -1;
  522|      0|                }
  523|      1|                step = _STEP_DATA;
  524|      1|                break;
  525|      0|            default:
  ------------------
  |  Branch (525:13): [True: 0, False: 1]
  ------------------
  526|      0|                break;
  527|      1|            }
  528|      1|        }
  529|       |
  530|      1|        if (length_to_read > 0 &&
  ------------------
  |  Branch (530:13): [True: 0, False: 1]
  ------------------
  531|      0|            (ctx->byte_timeout.tv_sec > 0 || ctx->byte_timeout.tv_usec > 0)) {
  ------------------
  |  Branch (531:14): [True: 0, False: 0]
  |  Branch (531:46): [True: 0, False: 0]
  ------------------
  532|       |            /* If there is no character in the buffer, the allowed timeout
  533|       |               interval between two consecutive bytes is defined by
  534|       |               byte_timeout */
  535|      0|            tv.tv_sec = ctx->byte_timeout.tv_sec;
  536|      0|            tv.tv_usec = ctx->byte_timeout.tv_usec;
  537|      0|            p_tv = &tv;
  538|      0|        }
  539|       |        /* else timeout isn't set again, the full response must be read before
  540|       |           expiration of response timeout (for CONFIRMATION only) */
  541|      1|    }
  542|       |
  543|      1|    if (ctx->debug)
  ------------------
  |  Branch (543:9): [True: 0, False: 1]
  ------------------
  544|      0|        printf("\n");
  545|       |
  546|      1|    return ctx->backend->check_integrity(ctx, msg, msg_length);
  547|      1|}
modbus_receive:
  551|      1|{
  552|      1|    if (ctx == NULL) {
  ------------------
  |  Branch (552:9): [True: 0, False: 1]
  ------------------
  553|      0|        errno = EINVAL;
  554|      0|        return -1;
  555|      0|    }
  556|       |
  557|      1|    return ctx->backend->receive(ctx, req);
  558|      1|}
_modbus_init_common:
 1980|      1|{
 1981|       |    /* Slave and socket are initialized to -1 */
 1982|      1|    ctx->slave = -1;
 1983|      1|    ctx->s = -1;
 1984|       |
 1985|      1|    ctx->debug = FALSE;
  ------------------
  |  |   47|      1|#define FALSE 0
  ------------------
 1986|      1|    ctx->error_recovery = MODBUS_ERROR_RECOVERY_NONE;
 1987|      1|    ctx->quirks = MODBUS_QUIRK_NONE;
 1988|       |
 1989|      1|    ctx->response_timeout.tv_sec = 0;
 1990|      1|    ctx->response_timeout.tv_usec = _RESPONSE_TIMEOUT;
  ------------------
  |  |   41|      1|#define _RESPONSE_TIMEOUT 500000
  ------------------
 1991|       |
 1992|      1|    ctx->byte_timeout.tv_sec = 0;
 1993|      1|    ctx->byte_timeout.tv_usec = _BYTE_TIMEOUT;
  ------------------
  |  |   42|      1|#define _BYTE_TIMEOUT     500000
  ------------------
 1994|       |
 1995|      1|    ctx->indication_timeout.tv_sec = 0;
 1996|      1|    ctx->indication_timeout.tv_usec = 0;
 1997|      1|}
modbus_close:
 2177|      1|{
 2178|      1|    if (ctx == NULL)
  ------------------
  |  Branch (2178:9): [True: 0, False: 1]
  ------------------
 2179|      0|        return;
 2180|       |
 2181|      1|    ctx->backend->close(ctx);
 2182|      1|}
modbus_free:
 2185|      1|{
 2186|      1|    if (ctx == NULL)
  ------------------
  |  Branch (2186:9): [True: 0, False: 1]
  ------------------
 2187|      0|        return;
 2188|       |
 2189|      1|    ctx->backend->free(ctx);
 2190|      1|}
modbus_mapping_new_start_address:
 2217|      1|{
 2218|      1|    modbus_mapping_t *mb_mapping;
 2219|       |
 2220|       |    /* Reject dimensions larger than the addressable space to avoid excessively
 2221|       |       large allocations driven by untrusted configuration. */
 2222|      1|    if (nb_bits > MODBUS_MAX_TABLE_SIZE || nb_input_bits > MODBUS_MAX_TABLE_SIZE ||
  ------------------
  |  |   31|      2|#define MODBUS_MAX_TABLE_SIZE 65536
  ------------------
                  if (nb_bits > MODBUS_MAX_TABLE_SIZE || nb_input_bits > MODBUS_MAX_TABLE_SIZE ||
  ------------------
  |  |   31|      2|#define MODBUS_MAX_TABLE_SIZE 65536
  ------------------
  |  Branch (2222:9): [True: 0, False: 1]
  |  Branch (2222:44): [True: 0, False: 1]
  ------------------
 2223|      1|        nb_registers > MODBUS_MAX_TABLE_SIZE ||
  ------------------
  |  |   31|      2|#define MODBUS_MAX_TABLE_SIZE 65536
  ------------------
  |  Branch (2223:9): [True: 0, False: 1]
  ------------------
 2224|      1|        nb_input_registers > MODBUS_MAX_TABLE_SIZE) {
  ------------------
  |  |   31|      1|#define MODBUS_MAX_TABLE_SIZE 65536
  ------------------
  |  Branch (2224:9): [True: 0, False: 1]
  ------------------
 2225|      0|        errno = EINVAL;
 2226|      0|        return NULL;
 2227|      0|    }
 2228|       |
 2229|      1|    mb_mapping = (modbus_mapping_t *) malloc(sizeof(modbus_mapping_t));
 2230|      1|    if (mb_mapping == NULL) {
  ------------------
  |  Branch (2230:9): [True: 0, False: 1]
  ------------------
 2231|      0|        return NULL;
 2232|      0|    }
 2233|       |
 2234|       |    /* 0X */
 2235|      1|    mb_mapping->nb_bits = nb_bits;
 2236|      1|    mb_mapping->start_bits = start_bits;
 2237|      1|    if (nb_bits == 0) {
  ------------------
  |  Branch (2237:9): [True: 0, False: 1]
  ------------------
 2238|      0|        mb_mapping->tab_bits = NULL;
 2239|      1|    } else {
 2240|      1|        mb_mapping->tab_bits = (uint8_t *) malloc(nb_bits * sizeof(uint8_t));
 2241|      1|        if (mb_mapping->tab_bits == NULL) {
  ------------------
  |  Branch (2241:13): [True: 0, False: 1]
  ------------------
 2242|      0|            free(mb_mapping);
 2243|      0|            return NULL;
 2244|      0|        }
 2245|      1|        memset(mb_mapping->tab_bits, 0, nb_bits * sizeof(uint8_t));
 2246|      1|    }
 2247|       |
 2248|       |    /* 1X */
 2249|      1|    mb_mapping->nb_input_bits = nb_input_bits;
 2250|      1|    mb_mapping->start_input_bits = start_input_bits;
 2251|      1|    if (nb_input_bits == 0) {
  ------------------
  |  Branch (2251:9): [True: 0, False: 1]
  ------------------
 2252|      0|        mb_mapping->tab_input_bits = NULL;
 2253|      1|    } else {
 2254|      1|        mb_mapping->tab_input_bits = (uint8_t *) malloc(nb_input_bits * sizeof(uint8_t));
 2255|      1|        if (mb_mapping->tab_input_bits == NULL) {
  ------------------
  |  Branch (2255:13): [True: 0, False: 1]
  ------------------
 2256|      0|            free(mb_mapping->tab_bits);
 2257|      0|            free(mb_mapping);
 2258|      0|            return NULL;
 2259|      0|        }
 2260|      1|        memset(mb_mapping->tab_input_bits, 0, nb_input_bits * sizeof(uint8_t));
 2261|      1|    }
 2262|       |
 2263|       |    /* 4X */
 2264|      1|    mb_mapping->nb_registers = nb_registers;
 2265|      1|    mb_mapping->start_registers = start_registers;
 2266|      1|    if (nb_registers == 0) {
  ------------------
  |  Branch (2266:9): [True: 0, False: 1]
  ------------------
 2267|      0|        mb_mapping->tab_registers = NULL;
 2268|      1|    } else {
 2269|      1|        mb_mapping->tab_registers = (uint16_t *) malloc(nb_registers * sizeof(uint16_t));
 2270|      1|        if (mb_mapping->tab_registers == NULL) {
  ------------------
  |  Branch (2270:13): [True: 0, False: 1]
  ------------------
 2271|      0|            free(mb_mapping->tab_input_bits);
 2272|      0|            free(mb_mapping->tab_bits);
 2273|      0|            free(mb_mapping);
 2274|      0|            return NULL;
 2275|      0|        }
 2276|      1|        memset(mb_mapping->tab_registers, 0, nb_registers * sizeof(uint16_t));
 2277|      1|    }
 2278|       |
 2279|       |    /* 3X */
 2280|      1|    mb_mapping->nb_input_registers = nb_input_registers;
 2281|      1|    mb_mapping->start_input_registers = start_input_registers;
 2282|      1|    if (nb_input_registers == 0) {
  ------------------
  |  Branch (2282:9): [True: 0, False: 1]
  ------------------
 2283|      0|        mb_mapping->tab_input_registers = NULL;
 2284|      1|    } else {
 2285|      1|        mb_mapping->tab_input_registers =
 2286|      1|            (uint16_t *) malloc(nb_input_registers * sizeof(uint16_t));
 2287|      1|        if (mb_mapping->tab_input_registers == NULL) {
  ------------------
  |  Branch (2287:13): [True: 0, False: 1]
  ------------------
 2288|      0|            free(mb_mapping->tab_registers);
 2289|      0|            free(mb_mapping->tab_input_bits);
 2290|      0|            free(mb_mapping->tab_bits);
 2291|      0|            free(mb_mapping);
 2292|      0|            return NULL;
 2293|      0|        }
 2294|      1|        memset(mb_mapping->tab_input_registers, 0, nb_input_registers * sizeof(uint16_t));
 2295|      1|    }
 2296|       |
 2297|      1|    return mb_mapping;
 2298|      1|}
modbus_mapping_free:
 2319|      1|{
 2320|      1|    if (mb_mapping == NULL) {
  ------------------
  |  Branch (2320:9): [True: 0, False: 1]
  ------------------
 2321|      0|        return;
 2322|      0|    }
 2323|       |
 2324|      1|    free(mb_mapping->tab_input_registers);
 2325|      1|    free(mb_mapping->tab_registers);
 2326|      1|    free(mb_mapping->tab_input_bits);
 2327|      1|    free(mb_mapping->tab_bits);
 2328|      1|    free(mb_mapping);
 2329|      1|}
strlcpy:
 2345|      1|{
 2346|      1|    register char *d = dest;
 2347|      1|    register const char *s = src;
 2348|      1|    register size_t n = dest_size;
 2349|       |
 2350|       |    /* Copy as many bytes as will fit */
 2351|      1|    if (n != 0 && --n != 0) {
  ------------------
  |  Branch (2351:9): [True: 1, False: 0]
  |  Branch (2351:19): [True: 1, False: 0]
  ------------------
 2352|     10|        do {
 2353|     10|            if ((*d++ = *s++) == 0)
  ------------------
  |  Branch (2353:17): [True: 1, False: 9]
  ------------------
 2354|      1|                break;
 2355|     10|        } while (--n != 0);
  ------------------
  |  Branch (2355:18): [True: 9, False: 0]
  ------------------
 2356|      1|    }
 2357|       |
 2358|       |    /* Not enough room in dest, add NUL and traverse rest of src */
 2359|      1|    if (n == 0) {
  ------------------
  |  Branch (2359:9): [True: 0, False: 1]
  ------------------
 2360|      0|        if (dest_size != 0)
  ------------------
  |  Branch (2360:13): [True: 0, False: 0]
  ------------------
 2361|      0|            *d = '\0'; /* NUL-terminate dest */
 2362|      0|        while (*s++)
  ------------------
  |  Branch (2362:16): [True: 0, False: 0]
  ------------------
 2363|      0|            ;
 2364|      0|    }
 2365|       |
 2366|      1|    return (s - src - 1); /* count does not include NUL */
 2367|      1|}
modbus.c:compute_meta_length_after_function:
  281|      1|{
  282|      1|    int length;
  283|       |
  284|      1|    if (msg_type == MSG_INDICATION) {
  ------------------
  |  Branch (284:9): [True: 1, False: 0]
  ------------------
  285|      1|        if (function <= MODBUS_FC_WRITE_SINGLE_REGISTER) {
  ------------------
  |  |   68|      1|#define MODBUS_FC_WRITE_SINGLE_REGISTER    0x06
  ------------------
  |  Branch (285:13): [True: 0, False: 1]
  ------------------
  286|      0|            length = 4;
  287|      1|        } else if (function == MODBUS_FC_WRITE_MULTIPLE_COILS ||
  ------------------
  |  |   70|      2|#define MODBUS_FC_WRITE_MULTIPLE_COILS     0x0F
  ------------------
  |  Branch (287:20): [True: 0, False: 1]
  ------------------
  288|      1|                   function == MODBUS_FC_WRITE_MULTIPLE_REGISTERS) {
  ------------------
  |  |   71|      1|#define MODBUS_FC_WRITE_MULTIPLE_REGISTERS 0x10
  ------------------
  |  Branch (288:20): [True: 0, False: 1]
  ------------------
  289|      0|            length = 5;
  290|      1|        } else if (function == MODBUS_FC_MASK_WRITE_REGISTER) {
  ------------------
  |  |   73|      1|#define MODBUS_FC_MASK_WRITE_REGISTER      0x16
  ------------------
  |  Branch (290:20): [True: 0, False: 1]
  ------------------
  291|      0|            length = 6;
  292|      1|        } else if (function == MODBUS_FC_WRITE_AND_READ_REGISTERS) {
  ------------------
  |  |   74|      1|#define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17
  ------------------
  |  Branch (292:20): [True: 0, False: 1]
  ------------------
  293|      0|            length = 9;
  294|      1|        } else {
  295|       |            /* MODBUS_FC_READ_EXCEPTION_STATUS, MODBUS_FC_REPORT_SLAVE_ID */
  296|      1|            length = 0;
  297|      1|        }
  298|      1|    } else {
  299|       |        /* MSG_CONFIRMATION */
  300|      0|        switch (function) {
  301|      0|        case MODBUS_FC_WRITE_SINGLE_COIL:
  ------------------
  |  |   67|      0|#define MODBUS_FC_WRITE_SINGLE_COIL        0x05
  ------------------
  |  Branch (301:9): [True: 0, False: 0]
  ------------------
  302|      0|        case MODBUS_FC_WRITE_SINGLE_REGISTER:
  ------------------
  |  |   68|      0|#define MODBUS_FC_WRITE_SINGLE_REGISTER    0x06
  ------------------
  |  Branch (302:9): [True: 0, False: 0]
  ------------------
  303|      0|        case MODBUS_FC_WRITE_MULTIPLE_COILS:
  ------------------
  |  |   70|      0|#define MODBUS_FC_WRITE_MULTIPLE_COILS     0x0F
  ------------------
  |  Branch (303:9): [True: 0, False: 0]
  ------------------
  304|      0|        case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
  ------------------
  |  |   71|      0|#define MODBUS_FC_WRITE_MULTIPLE_REGISTERS 0x10
  ------------------
  |  Branch (304:9): [True: 0, False: 0]
  ------------------
  305|      0|            length = 4;
  306|      0|            break;
  307|      0|        case MODBUS_FC_MASK_WRITE_REGISTER:
  ------------------
  |  |   73|      0|#define MODBUS_FC_MASK_WRITE_REGISTER      0x16
  ------------------
  |  Branch (307:9): [True: 0, False: 0]
  ------------------
  308|      0|            length = 6;
  309|      0|            break;
  310|      0|        default:
  ------------------
  |  Branch (310:9): [True: 0, False: 0]
  ------------------
  311|      0|            length = 1;
  312|      0|        }
  313|      0|    }
  314|       |
  315|      1|    return length;
  316|      1|}
modbus.c:compute_data_length_after_meta:
  321|      1|{
  322|      1|    int function = msg[ctx->backend->header_length];
  323|      1|    int length;
  324|       |
  325|      1|    if (msg_type == MSG_INDICATION) {
  ------------------
  |  Branch (325:9): [True: 1, False: 0]
  ------------------
  326|      1|        switch (function) {
  327|      0|        case MODBUS_FC_WRITE_MULTIPLE_COILS:
  ------------------
  |  |   70|      0|#define MODBUS_FC_WRITE_MULTIPLE_COILS     0x0F
  ------------------
  |  Branch (327:9): [True: 0, False: 1]
  ------------------
  328|      0|        case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
  ------------------
  |  |   71|      0|#define MODBUS_FC_WRITE_MULTIPLE_REGISTERS 0x10
  ------------------
  |  Branch (328:9): [True: 0, False: 1]
  ------------------
  329|      0|            length = msg[ctx->backend->header_length + 5];
  330|      0|            break;
  331|      0|        case MODBUS_FC_WRITE_AND_READ_REGISTERS:
  ------------------
  |  |   74|      0|#define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17
  ------------------
  |  Branch (331:9): [True: 0, False: 1]
  ------------------
  332|      0|            length = msg[ctx->backend->header_length + 9];
  333|      0|            break;
  334|      1|        default:
  ------------------
  |  Branch (334:9): [True: 1, False: 0]
  ------------------
  335|      1|            length = 0;
  336|      1|        }
  337|      1|    } else {
  338|       |        /* MSG_CONFIRMATION */
  339|      0|        if (function <= MODBUS_FC_READ_INPUT_REGISTERS ||
  ------------------
  |  |   66|      0|#define MODBUS_FC_READ_INPUT_REGISTERS     0x04
  ------------------
  |  Branch (339:13): [True: 0, False: 0]
  ------------------
  340|      0|            function == MODBUS_FC_REPORT_SLAVE_ID ||
  ------------------
  |  |   72|      0|#define MODBUS_FC_REPORT_SLAVE_ID          0x11
  ------------------
  |  Branch (340:13): [True: 0, False: 0]
  ------------------
  341|      0|            function == MODBUS_FC_WRITE_AND_READ_REGISTERS) {
  ------------------
  |  |   74|      0|#define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17
  ------------------
  |  Branch (341:13): [True: 0, False: 0]
  ------------------
  342|      0|            length = msg[ctx->backend->header_length + 1];
  343|      0|        } else {
  344|      0|            length = 0;
  345|      0|        }
  346|      0|    }
  347|       |
  348|      1|    length += ctx->backend->checksum_length;
  349|       |
  350|      1|    return length;
  351|      1|}

