| 74 | } |
| 75 | |
| 76 | ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const |
| 77 | { |
| 78 | // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted |
| 79 | // SetFuzzedErrNo() will always return the first element and we want to avoid Recv() |
| 80 | // returning -1 and setting errno to EAGAIN repeatedly. |
| 81 | constexpr std::array recv_errnos{ |
| 82 | ECONNREFUSED, |
| 83 | EAGAIN, |
| 84 | EBADF, |
| 85 | EFAULT, |
| 86 | EINTR, |
| 87 | EINVAL, |
| 88 | ENOMEM, |
| 89 | ENOTCONN, |
| 90 | ENOTSOCK, |
| 91 | EWOULDBLOCK, |
| 92 | }; |
| 93 | assert(buf != nullptr || len == 0); |
| 94 | if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) { |
| 95 | const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; |
| 96 | if (r == -1) { |
| 97 | SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); |
| 98 | } |
| 99 | return r; |
| 100 | } |
| 101 | std::vector<uint8_t> random_bytes; |
| 102 | bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()}; |
| 103 | if (m_peek_data.has_value()) { |
| 104 | // `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`. |
| 105 | random_bytes.assign({m_peek_data.value()}); |
| 106 | if ((flags & MSG_PEEK) == 0) { |
| 107 | m_peek_data.reset(); |
| 108 | } |
| 109 | pad_to_len_bytes = false; |
| 110 | } else if ((flags & MSG_PEEK) != 0) { |
| 111 | // New call with `MSG_PEEK`. |
| 112 | random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(1); |
| 113 | if (!random_bytes.empty()) { |
| 114 | m_peek_data = random_bytes[0]; |
| 115 | pad_to_len_bytes = false; |
| 116 | } |
| 117 | } else { |
| 118 | random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>( |
| 119 | m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, len)); |
| 120 | } |
| 121 | if (random_bytes.empty()) { |
| 122 | const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; |
| 123 | if (r == -1) { |
| 124 | SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); |
| 125 | } |
| 126 | return r; |
| 127 | } |
| 128 | std::memcpy(buf, random_bytes.data(), random_bytes.size()); |
| 129 | if (pad_to_len_bytes) { |
| 130 | if (len > random_bytes.size()) { |
| 131 | std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size()); |
| 132 | } |
| 133 | return len; |
no test coverage detected