Extensions.cpp:_ZN3uWSL20negotiateCompressionEbiiNSt3__117basic_string_viewIcNS0_11char_traitsIcEEEE:
  144|  1.89k|static inline std::tuple<bool, int, int, std::string_view> negotiateCompression(bool wantCompression, int wantedCompressionWindow, int wantedInflationWindow, std::string_view offer) {
  145|       |
  146|       |    /* If we don't want compression then we are done here */
  147|  1.89k|    if (!wantCompression) {
  ------------------
  |  Branch (147:9): [True: 632, False: 1.26k]
  ------------------
  148|    632|        return {false, 0, 0, ""};
  149|    632|    }
  150|       |
  151|  1.26k|    ExtensionsParser ep(offer.data(), offer.length());
  152|       |
  153|  1.26k|    static thread_local std::string response;
  154|  1.26k|    response = "";
  155|       |
  156|  1.26k|    int compressionWindow = wantedCompressionWindow;
  157|  1.26k|    int inflationWindow = wantedInflationWindow;
  158|  1.26k|    bool compression = false;
  159|       |
  160|  1.26k|    if (ep.xWebKitDeflateFrame) {
  ------------------
  |  Branch (160:9): [True: 64, False: 1.20k]
  ------------------
  161|       |        /* We now have compression */
  162|     64|        compression = true;
  163|     64|        response = "x-webkit-deflate-frame";
  164|       |
  165|       |        /* If the other peer has DEMANDED us no sliding window,
  166|       |         * we cannot compress with anything other than shared compressor */
  167|     64|        if (ep.noContextTakeover) {
  ------------------
  |  Branch (167:13): [True: 2, False: 62]
  ------------------
  168|       |            /* We must fail here right now (fix pub/sub) */
  169|      2|#ifndef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX
  170|      2|            if (wantedCompressionWindow != 0) {
  ------------------
  |  Branch (170:17): [True: 1, False: 1]
  ------------------
  171|      1|                return {false, 0, 0, ""};
  172|      1|            }
  173|      1|#endif
  174|       |
  175|      1|            compressionWindow = 0;
  176|      1|        }
  177|       |
  178|       |        /* If the other peer has DEMANDED us to use a limited sliding window,
  179|       |         * we have to limit out compression sliding window */
  180|     63|        if (ep.maxWindowBits && ep.maxWindowBits < compressionWindow) {
  ------------------
  |  Branch (180:13): [True: 60, False: 3]
  |  Branch (180:33): [True: 7, False: 53]
  ------------------
  181|      7|            compressionWindow = ep.maxWindowBits;
  182|      7|#ifndef UWS_ALLOW_8_WINDOW_BITS
  183|       |            /* We cannot really deny this, so we have to disable compression in this case */
  184|      7|            if (compressionWindow == 8) {
  ------------------
  |  Branch (184:17): [True: 1, False: 6]
  ------------------
  185|      1|                return {false, 0, 0, ""};
  186|      1|            }
  187|      7|#endif
  188|      7|        }
  189|       |
  190|       |        /* We decide our own inflation sliding window (and their compression sliding window) */
  191|     62|        if (wantedInflationWindow < 15) {
  ------------------
  |  Branch (191:13): [True: 62, False: 0]
  ------------------
  192|     62|            if (!wantedInflationWindow) {
  ------------------
  |  Branch (192:17): [True: 62, False: 0]
  ------------------
  193|     62|                response += "; no_context_takeover";
  194|     62|            } else {
  195|      0|                response += "; max_window_bits=" + std::to_string(wantedInflationWindow);
  196|      0|            }
  197|     62|        }
  198|  1.20k|    } else if (ep.perMessageDeflate) {
  ------------------
  |  Branch (198:16): [True: 128, False: 1.07k]
  ------------------
  199|       |        /* We now have compression */
  200|    128|        compression = true;
  201|    128|        response = "permessage-deflate";
  202|       |
  203|    128|        if (ep.clientNoContextTakeover) {
  ------------------
  |  Branch (203:13): [True: 2, False: 126]
  ------------------
  204|      2|            inflationWindow = 0;
  205|    126|        } else if (ep.clientMaxWindowBits && ep.clientMaxWindowBits != 1) {
  ------------------
  |  Branch (205:20): [True: 64, False: 62]
  |  Branch (205:46): [True: 62, False: 2]
  ------------------
  206|     62|            inflationWindow = std::min<int>(ep.clientMaxWindowBits, inflationWindow);
  207|     62|        }
  208|       |
  209|       |        /* Whatever we have now, write */
  210|    128|        if (inflationWindow < 15) {
  ------------------
  |  Branch (210:13): [True: 128, False: 0]
  ------------------
  211|    128|            if (!inflationWindow || !ep.clientMaxWindowBits) {
  ------------------
  |  Branch (211:17): [True: 128, False: 0]
  |  Branch (211:37): [True: 0, False: 0]
  ------------------
  212|    128|                response += "; client_no_context_takeover";
  213|    128|                inflationWindow = 0;
  214|    128|            } else {
  215|      0|                response += "; client_max_window_bits=" + std::to_string(inflationWindow);
  216|      0|            }
  217|    128|        }
  218|       |
  219|       |        /* This block basically lets the client lower it */
  220|    128|        if (ep.serverNoContextTakeover) {
  ------------------
  |  Branch (220:13): [True: 2, False: 126]
  ------------------
  221|       |        /* This is an important (temporary) fix since we haven't allowed
  222|       |         * these two modes to mix, and pub/sub will not handle this case (yet) */
  223|       |#ifdef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX
  224|       |            compressionWindow = 0;
  225|       |#endif
  226|    126|        } else if (ep.serverMaxWindowBits) {
  ------------------
  |  Branch (226:20): [True: 58, False: 68]
  ------------------
  227|     58|            compressionWindow = std::min<int>(ep.serverMaxWindowBits, compressionWindow);
  228|     58|#ifndef UWS_ALLOW_8_WINDOW_BITS
  229|       |            /* Zlib cannot do windowBits=8, memLevel=1 so we raise it up to 9 minimum */
  230|     58|            if (compressionWindow == 8) {
  ------------------
  |  Branch (230:17): [True: 1, False: 57]
  ------------------
  231|      1|                compressionWindow = 9;
  232|      1|            }
  233|     58|#endif
  234|     58|        }
  235|       |
  236|       |        /* Whatever we have now, write */
  237|    128|        if (compressionWindow < 15) {
  ------------------
  |  Branch (237:13): [True: 128, False: 0]
  ------------------
  238|    128|            if (!compressionWindow) {
  ------------------
  |  Branch (238:17): [True: 64, False: 64]
  ------------------
  239|     64|                response += "; server_no_context_takeover";
  240|     64|            } else {
  241|     64|                response += "; server_max_window_bits=" + std::to_string(compressionWindow);
  242|     64|            }
  243|    128|        }
  244|    128|    }
  245|       |
  246|       |    /* A final sanity check (this check does not actually catch too high values!) */
  247|  1.26k|    if ((compressionWindow && compressionWindow < 8) || compressionWindow > 15 || (inflationWindow && inflationWindow < 8) || inflationWindow > 15) {
  ------------------
  |  Branch (247:10): [True: 630, False: 632]
  |  Branch (247:31): [True: 9, False: 621]
  |  Branch (247:57): [True: 0, False: 1.25k]
  |  Branch (247:84): [True: 0, False: 1.25k]
  |  Branch (247:103): [True: 0, False: 0]
  |  Branch (247:127): [True: 0, False: 1.25k]
  ------------------
  248|      9|        return {false, 0, 0, ""};
  249|      9|    }
  250|       |
  251|  1.25k|    return {compression, compressionWindow, inflationWindow, response};
  252|  1.26k|}
_ZN3uWS16ExtensionsParserC2EPKcm:
   93|  1.26k|    ExtensionsParser(const char *data, size_t length) {
   94|  1.26k|        const char *stop = data + length;
   95|  1.26k|        int token = 1;
   96|       |
   97|       |        /* Ignore anything before permessage-deflate or x-webkit-deflate-frame */
   98|  3.27k|        for (; token && token != TOK_PERMESSAGE_DEFLATE && token != TOK_X_WEBKIT_DEFLATE_FRAME; token = getToken(data, stop));
  ------------------
  |  Branch (98:16): [True: 2.19k, False: 1.07k]
  |  Branch (98:25): [True: 2.07k, False: 128]
  |  Branch (98:60): [True: 2.00k, False: 64]
  ------------------
   99|       |
  100|       |        /* What protocol are we going to use? */
  101|  1.26k|        perMessageDeflate = (token == TOK_PERMESSAGE_DEFLATE);
  102|  1.26k|        xWebKitDeflateFrame = (token == TOK_X_WEBKIT_DEFLATE_FRAME);
  103|       |
  104|  4.08k|        while ((token = getToken(data, stop))) {
  ------------------
  |  Branch (104:16): [True: 2.82k, False: 1.26k]
  ------------------
  105|  2.82k|            switch (token) {
  106|      2|            case TOK_X_WEBKIT_DEFLATE_FRAME:
  ------------------
  |  Branch (106:13): [True: 2, False: 2.82k]
  ------------------
  107|       |                /* Duplicates not allowed/supported */
  108|      2|                return;
  109|    192|            case TOK_NO_CONTEXT_TAKEOVER:
  ------------------
  |  Branch (109:13): [True: 192, False: 2.63k]
  ------------------
  110|    192|                noContextTakeover = true;
  111|    192|                break;
  112|    250|            case TOK_MAX_WINDOW_BITS:
  ------------------
  |  Branch (112:13): [True: 250, False: 2.57k]
  ------------------
  113|    250|                maxWindowBits = 1;
  114|    250|                lastInteger = &maxWindowBits;
  115|    250|                break;
  116|      2|            case TOK_PERMESSAGE_DEFLATE:
  ------------------
  |  Branch (116:13): [True: 2, False: 2.82k]
  ------------------
  117|       |                /* Duplicates not allowed/supported */
  118|      2|                return;
  119|    192|            case TOK_SERVER_NO_CONTEXT_TAKEOVER:
  ------------------
  |  Branch (119:13): [True: 192, False: 2.63k]
  ------------------
  120|    192|                serverNoContextTakeover = true;
  121|    192|                break;
  122|    192|            case TOK_CLIENT_NO_CONTEXT_TAKEOVER:
  ------------------
  |  Branch (122:13): [True: 192, False: 2.63k]
  ------------------
  123|    192|                clientNoContextTakeover = true;
  124|    192|                break;
  125|    256|            case TOK_SERVER_MAX_WINDOW_BITS:
  ------------------
  |  Branch (125:13): [True: 256, False: 2.56k]
  ------------------
  126|    256|                serverMaxWindowBits = 1;
  127|    256|                lastInteger = &serverMaxWindowBits;
  128|    256|                break;
  129|    258|            case TOK_CLIENT_MAX_WINDOW_BITS:
  ------------------
  |  Branch (129:13): [True: 258, False: 2.56k]
  ------------------
  130|    258|                clientMaxWindowBits = 1;
  131|    258|                lastInteger = &clientMaxWindowBits;
  132|    258|                break;
  133|  1.48k|            default:
  ------------------
  |  Branch (133:13): [True: 1.48k, False: 1.34k]
  ------------------
  134|  1.48k|                if (token < 0 && lastInteger) {
  ------------------
  |  Branch (134:21): [True: 834, False: 646]
  |  Branch (134:34): [True: 366, False: 468]
  ------------------
  135|    366|                    *lastInteger = -token;
  136|    366|                }
  137|  1.48k|                break;
  138|  2.82k|            }
  139|  2.82k|        }
  140|  1.26k|    }
_ZN3uWS16ExtensionsParser8getTokenERPKcS2_:
   69|  6.09k|    int getToken(const char *&in, const char *stop) {
   70|  9.77k|        while (in != stop && !isalnum(*in)) {
  ------------------
  |  Branch (70:16): [True: 8.13k, False: 1.64k]
  |  Branch (70:30): [True: 3.68k, False: 4.45k]
  ------------------
   71|  3.68k|            in++;
   72|  3.68k|        }
   73|       |
   74|       |        /* Don't care more than this for now */
   75|  6.09k|        static_assert(SHRT_MIN > INT_MIN, "Integer overflow fix is invalid for this platform, report this as a bug!");
   76|       |
   77|  6.09k|        int hashedToken = 0;
   78|  6.41M|        while (in != stop && (isalnum(*in) || *in == '-' || *in == '_')) {
  ------------------
  |  Branch (78:16): [True: 6.41M, False: 2.81k]
  |  Branch (78:31): [True: 6.40M, False: 4.37k]
  |  Branch (78:47): [True: 536, False: 3.83k]
  |  Branch (78:61): [True: 560, False: 3.27k]
  ------------------
   79|  6.40M|            if (isdigit(*in)) {
  ------------------
  |  Branch (79:17): [True: 6.92k, False: 6.40M]
  ------------------
   80|       |                /* This check is a quick and incorrect fix for integer overflow
   81|       |                 * in oss-fuzz but we don't care as it doesn't matter either way */
   82|  6.92k|                if (hashedToken > SHRT_MIN && hashedToken < SHRT_MAX) {
  ------------------
  |  Branch (82:21): [True: 6.41k, False: 502]
  |  Branch (82:47): [True: 5.88k, False: 538]
  ------------------
   83|  5.88k|                    hashedToken = hashedToken * 10 - (*in - '0');
   84|  5.88k|                }
   85|  6.40M|            } else {
   86|  6.40M|                hashedToken += *in;
   87|  6.40M|            }
   88|  6.40M|            in++;
   89|  6.40M|        }
   90|  6.09k|        return hashedToken;
   91|  6.09k|    }

LLVMFuzzerTestOneInput:
   12|    632|extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
   13|       |
   14|       |    /* This one must not return shared compressor, or above 13 */
   15|    632|    {
   16|    632|        auto [negCompression, negCompressionWindow, negInflationWindow, response] = uWS::negotiateCompression(true, 13, 0, std::string_view((char *) data, size));
   17|       |
   18|    632|        if (negCompression) {
  ------------------
  |  Branch (18:13): [True: 85, False: 547]
  ------------------
   19|       |            /* If we want dedicated compression, we must not end up here! */
   20|     85|            free((void *) (negCompressionWindow == 0));
   21|       |
   22|       |            /* Some more checks (freeing 0 does nothing) */
   23|     85|            free((void *) (negCompressionWindow > 13));
   24|     85|            free((void *) (negInflationWindow != 0));
   25|     85|            free((void *) (negInflationWindow < 0 || negInflationWindow > 15 || negCompressionWindow < 0 || negCompressionWindow > 15));
  ------------------
  |  Branch (25:28): [True: 0, False: 85]
  |  Branch (25:54): [True: 0, False: 85]
  |  Branch (25:81): [True: 0, False: 85]
  |  Branch (25:109): [True: 0, False: 85]
  ------------------
   26|     85|        }
   27|    632|    }
   28|       |
   29|       |    /* This one must not return anything over 0 (only shared) */
   30|    632|    {
   31|    632|        auto [negCompression, negCompressionWindow, negInflationWindow, response] = uWS::negotiateCompression(true, 0, 0, std::string_view((char *) data, size));
   32|       |
   33|    632|        if (negCompression) {
  ------------------
  |  Branch (33:13): [True: 96, False: 536]
  ------------------
   34|       |            /* If we want shared compression, we must not end up here! */
   35|     96|            free((void *) (negCompressionWindow != 0));
   36|     96|        }
   37|    632|    }
   38|       |
   39|       |
   40|       |    /* Whatever, this one must not negotiate anything */
   41|    632|    {
   42|    632|        auto [negCompression, negCompressionWindow, negInflationWindow, response] = uWS::negotiateCompression(false, 13, 15, std::string_view((char *) data, size));
   43|       |
   44|    632|        if (negCompression) {
  ------------------
  |  Branch (44:13): [True: 0, False: 632]
  ------------------
   45|      0|            free((void *) -1);
   46|      0|        }
   47|    632|    }
   48|       |
   49|    632|    return 0;
   50|    632|}

