✓ProveIt
Examples / Report #3749204 Saved analysis

CVE-2026-9080: UAF after pause in socket callback

curl · 2026-05-1916.8s analysis · $0.029 in model calls

What the report claims

Heap-use-after-free in lib/multi_ev.c when curl_easy_pause() is called from a CURLMOPT_SOCKETFUNCTION callback, leading to UAF writes to entry->announced and entry->action after the entry may have been freed.

Compare with curl's recorded outcome

Known vulnerability

A real vulnerability: CVE-2026-9080 UAF after pause in socket callback

Shown for comparison after analysis. The pipeline did not see this label.

ProveIt's finding

Needs human review

The available evidence does not settle the report. A maintainer should investigate.

Judgment withdrawn. The answer failed the evidence check.
See the withdrawn model reasoning

The following reasoning failed the citation check and does not support the final finding.

  • mev_sh_entry_update holds entry pointer across socket_cb call (lines 272-273)
  • curl_easy_pause() is documented as callable from callbacks and re-enters mev_assess()
  • mev_assess() has no guard on multi->in_callback
  • mev_pollset_diff() can free the entry via mev_forget_socket() -> mev_sh_entry_kill()
  • Lines 275 and 280 write to the freed entry after callback returns
  • The reproducer demonstrates a concrete trigger path from attacker-controlled input
How this analysis ran 5 claims · 14 citations verified

Evidence check: judge quoted an external source that does not say that (https://curl.se/libcurl/c/curl_easy_pause.html)

Checked against curl master on 2026-05-19 (7541ae569d82). Dev evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.

1 · Grounding
partially grounded
no model · 22 references checked out, 1 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
5 claims · 5653 tokens · $0.0004
3 · Evidence
10 code snippets
real curl source at 7541ae569d82 · 5 docs via Tavily
4 · Judgment
Nemotron-3-Ultra-550b-a55b
20381 tokens · 14.5s · $0.0288
5 · Receipts
14 of 15 citations verified
every citation must point at code the judge was shown
Inspect the withdrawn draft reply

This draft belongs to the withdrawn judgment. It may contain unsupported claims.

Thank you for the detailed report and reproducer. The UAF in mev_sh_entry_update is confirmed: the entry pointer is held across the socket_cb call, curl_easy_pause() can re-enter mev_assess() which may free the entry via mev_pollset_diff -> mev_forget_socket -> mev_sh_entry_kill, and lines 275/280 then write to freed memory. The fix of re-fetching the entry from the hash after the callback returns is correct. This is a valid security vulnerability (heap-use-after-free reachable via documented API use from a callback).

Inspect all claims and source code 5 claims · 10 code excerpts

This model judgment was withdrawn. The claim assessments below are preserved for inspection and may be wrong.

Report claims

C1flaw supported

entry->announced = TRUE; entry->action = (unsigned int)comboaction; are performed on a freed mev_sh_entry pointer after curl_easy_pause() may have freed it

Read the reasoning

The code confirms the UAF path: mev_sh_entry_update fires the socket callback (line 272-273), which can call curl_easy_pause() -> Curl_multi_ev_assess_xfer() -> mev_assess() -> mev_pollset_diff() -> mev_forget_socket() -> mev_sh_entry_kill() -> free(entry). After the callback returns, lines 275 and 280 write to the now-freed entry pointer. mev_assess() does not check multi->in_callback.

C2location supported

lines 275 and 280 in lib/multi_ev.c

Read the reasoning

Lines 275 and 280 in lib/multi_ev.c are the exact writes identified in the report.

C3trigger supported

calling curl_easy_pause() from within a CURLMOPT_SOCKETFUNCTION callback

Read the reasoning

curl_easy_pause() explicitly checks for and handles being called from within a callback (line 1146), and the CURLMOPT_SOCKETFUNCTION callback is a documented callback entry point. The deterministic checks confirm both symbols exist in curl.

C4impact supported

heap-use-after-free causing potential memory corruption or crash

Read the reasoning

Heap-use-after-free is confirmed by the code path; writes to freed memory can cause memory corruption or crash.

C5reproduction supported

use the provided self-contained reproducer that spins up an HTTP server and calls curl_easy_pause() in the socket callback

Read the reasoning

The provided reproducer demonstrates the exact trigger condition: calling curl_easy_pause() from the socket callback when the socket transitions to POLL_IN, causing the poll set to empty and the entry to be freed.

poc_uaf.c:181

Deterministic checks that failed

  • quote 3 of 6 quoted lines appear nowhere in curl, e.g. 'multi->socket_userp, entry->user_data); /* fires app callbac'

What the report says about other projects

confirmed curl_easy_pause(3) can be used from within callbacks

“Unlike most other libcurl functions, curl_easy_pause(3) can be used from within callbacks.” source

not addressed CURLMOPT_SOCKETFUNCTION documentation adds no restriction on calling curl_easy_pause()

Read the original report (excerpt)

Full report on HackerOne ↗

Hi all, We've found a heap-use-after-free in `lib/multi_ev.c` triggered by calling `curl_easy_pause()` from within a `CURLMOPT_SOCKETFUNCTION` callback. ASAN-confirmed with the self-contained reproducer below. **Affected versions:** 8.13.0 – 8.20.0 (current). The `entry->action` write (line 280) has been vulnerable since the `multi_ev` rewrite in 8.13.0 (commit `cfc657a48d`, 2025-04-02). The `entry->announced` bit-field write (line 275) was added in 8.16.0 (commit `3d302250ec`, 2025-09-10) and is what ASAN catches first, because a bit-field write compiles to a read-modify-write. --- ## Root cause `mev_sh_entry_update()` fires the socket callback, then writes to the `mev_sh_entry` it was passed: ```c /* lib/multi_ev.c */ mev_in_callback(multi, TRUE); rc = multi->socket_cb(data, s, comboaction, multi->socket_userp, entry->user_data); /* fires app callback */ mev_in_callback(multi, FALSE); entry->announced = TRUE; /* UAF WRITE — entry may be freed (line 275) */ if(rc == -1) { ... } entry->action = (unsigned int)comboaction; /* UAF WRITE (line 280) */ ``` `curl_easy_pause()` is [documented](https://curl.se/libcurl/c/curl_easy_pause.html) as legal to call from any callback: > "Unlike most other libcurl functions, curl_easy_pause(3) can be used from > within callbacks." `CURLMOPT_SOCKETFUNCTION` documentation adds no restriction on this. When called from the socket callback, `curl_easy_pause()` invokes `Curl_multi_ev_assess_xfer()` (easy.c:1183), which calls `mev_assess()`. **`mev_assess()` has no guard on `multi->in_callback`** — the flag is set by `mev_in_callback()` but never checked inside `multi_ev.c`. If the pause empties the transfer's poll-set (recv paused, nothing left to send), `mev_pollset_diff()` calls `mev_forget_socket()` → `mev_sh_entry_kill()` → `free(entry)`. The writes at lines 275 and 280 then land on freed memory. --- ## ASAN output ``` ================================================================= ==59330==ERROR: AddressSanitizer: heap-use-after-free on address 0x60b00000342c at pc 0x000100c9bde4 bp 0x00016fb5d390 sp 0x00016fb5d388 READ of size 1 at 0x60b00000342c thread T0 #0 0x000100c9bde0 in mev_sh_entry_update multi_ev.c:275 #1 0x000100c99c14 in mev_pollset_diff multi_ev.c:360 #2 0x000100c97900 in mev_assess multi_ev.c:512 #3 0x000100c97634 in Curl_mult …

Source code

lib/easy.clines 1133–1208 · lines 1183-1183 cited by the report; definition of curl_easy_pause
1133CURLcode curl_easy_pause(CURL *curl, int action)
1134{
1135 CURLcode result = CURLE_OK;
1136 bool recursive = FALSE;
1137 bool changed = FALSE;
1138 struct Curl_easy *data = curl;
1139 bool recv_paused, recv_paused_new;
1140 bool send_paused, send_paused_new;
1141
1142 if(!GOOD_EASY_HANDLE(data) || !data->conn)
1143 /* crazy input, do not continue */
1144 return CURLE_BAD_FUNCTION_ARGUMENT;
1145
1146 if(Curl_is_in_callback(data))
C3: curl_easy_pause checks Curl_is_in_callback(data) and handles recursive calls
1147 recursive = TRUE;
1148
1149 recv_paused = Curl_xfer_recv_is_paused(data);
1150 recv_paused_new = (action & CURLPAUSE_RECV);
1151 send_paused = Curl_xfer_send_is_paused(data);
1152 send_paused_new = (action & CURLPAUSE_SEND);
1153
1154 if((send_paused != send_paused_new) ||
1155 (send_paused_new != Curl_creader_is_paused(data))) {
1156 changed = TRUE;
1157 result = Curl_1st_fatal(
1158 result, Curl_xfer_pause_send(data, send_paused_new));
1159 }
1160
1161 if(recv_paused != recv_paused_new) {
1162 changed = TRUE;
1163 result = Curl_1st_fatal(
1164 result, Curl_xfer_pause_recv(data, recv_paused_new));
1165 }
1166
1167 /* If not completely pausing both directions now, run again in any case. */
1168 if(!Curl_xfer_is_blocked(data)) {
1169 /* reset the too-slow time keeper */
1170 data->state.keeps_speed.tv_sec = 0;
1171 if(data->multi) {
1172 Curl_multi_mark_dirty(data); /* make it run */
1173 /* On changes, tell application to update its timers. */
1174 if(changed) {
1175 if(Curl_update_timer(data->multi) && !result)
1176 result = CURLE_ABORTED_BY_CALLBACK;
1177 }
1178 }
1179 }
1180
1181 if(!result && changed && !data->state.done && data->multi)
1182 /* pause/unpausing may result in multi event changes */
1183 if(Curl_multi_ev_assess_xfer(data->multi, data) && !result)
C3: curl_easy_pause calls Curl_multi_ev_assess_xfer when not completely paused
1184 result = CURLE_ABORTED_BY_CALLBACK;
1185
1186 if(recursive)
1187 /* this might have called a callback recursively which might have set this
1188 to false again on exit */
1189 Curl_set_in_callback(data, TRUE);
1190
1191 return result;
1192}
1193
1194static CURLcode easy_connection(struct Curl_easy *data,
1195 struct connectdata **connp)
1196{
1197 curl_socket_t sfd;
1198
1199 if(!data)
1200 return CURLE_BAD_FUNCTION_ARGUMENT;
1201
1202 /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
1203 if(!data->set.connect_only) {
1204 failf(data, "CONNECT_ONLY is required");
1205 return CURLE_UNSUPPORTED_PROTOCOL;
1206 }
1207
1208 sfd = Curl_getconnectinfo(data, connp);
lib/multi_ev.clines 520–524 · definition of Curl_multi_ev_assess_xfer
520CURLMcode Curl_multi_ev_assess_xfer(struct Curl_multi *multi,
521 struct Curl_easy *data)
522{
523 return mev_assess(multi, data, NULL);
C3: Curl_multi_ev_assess_xfer calls mev_assess
524}
lib/multi_ev.clines 477–518 · definition of mev_assess
477static CURLMcode mev_assess(struct Curl_multi *multi,
478 struct Curl_easy *data,
479 struct connectdata *conn)
480{
481 struct easy_pollset ps, *last_ps;
482 CURLMcode mresult = CURLM_OK;
483
484 if(!multi || !multi->socket_cb)
485 return CURLM_OK;
486
487 Curl_pollset_init(&ps);
488 if(conn) {
489 CURLcode result = Curl_conn_adjust_pollset(data, conn, &ps);
490 if(result) {
491 mresult = (result == CURLE_OUT_OF_MEMORY) ?
492 CURLM_OUT_OF_MEMORY : CURLM_INTERNAL_ERROR;
493 goto out;
494 }
495 }
496 else
497 Curl_multi_pollset(data, &ps);
498 last_ps = mev_get_last_pollset(data, conn);
499
500 if(!last_ps && ps.n) {
501 if(conn)
502 last_ps = mev_add_new_conn_pollset(conn);
503 else
504 last_ps = mev_add_new_xfer_pollset(data);
505 if(!last_ps) {
506 mresult = CURLM_OUT_OF_MEMORY;
507 goto out;
508 }
509 }
510
511 if(last_ps)
512 mresult = mev_pollset_diff(multi, data, conn, &ps, last_ps);
C1: mev_assess calls mev_pollset_diff which can free the entry via mev_forget_socket -> mev_sh_entry_kill
513 else
514 DEBUGASSERT(!ps.n);
515out:
516 Curl_pollset_cleanup(&ps);
517 return mresult;
518}
lib/multi_ev.clines 185–213 · definition of mev_forget_socket
185static CURLMcode mev_forget_socket(struct Curl_multi *multi,
186 struct Curl_easy *data,
187 curl_socket_t s,
188 const char *cause)
189{
190 struct mev_sh_entry *entry = mev_sh_entry_get(&multi->ev.sh_entries, s);
191 int rc = 0;
192
193 if(!entry) /* we never knew or already forgot about this socket */
194 return CURLM_OK;
195
196 /* We managed this socket before, tell the socket callback to forget it. */
197 if(entry->announced && multi->socket_cb) {
198 NOVERBOSE((void)cause);
199 CURL_TRC_M(data, "ev %s, call(fd=%" FMT_SOCKET_T ", ev=REMOVE)", cause, s);
200 mev_in_callback(multi, TRUE);
201 rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
202 multi->socket_userp, entry->user_data);
203 mev_in_callback(multi, FALSE);
204 entry->announced = FALSE;
205 }
206
207 mev_sh_entry_kill(multi, s);
C1: mev_forget_socket calls mev_sh_entry_kill which frees the entry
208 if(rc == -1) {
209 multi->dead = TRUE;
210 return CURLM_ABORTED_BY_CALLBACK;
211 }
212 return CURLM_OK;
213}
lib/multi_ev.clines 284–429 · definition of mev_pollset_diff
284static CURLMcode mev_pollset_diff(struct Curl_multi *multi,
285 struct Curl_easy *data,
286 struct connectdata *conn,
287 struct easy_pollset *ps,
288 struct easy_pollset *prev_ps)
289{
290 struct mev_sh_entry *entry;
291 curl_socket_t s;
292 unsigned int i, j;
293 CURLMcode mresult;
294
295 /* The transfer `data` reports in `ps` the sockets it is interested
296 * in and which combination of CURL_POLL_IN/CURL_POLL_OUT it wants
297 * to have monitored for events.
298 * There can be more than 1 transfer interested in the same socket
299 * and 1 transfer might be interested in more than 1 socket.
300 * `prev_ps` is the pollset copy from the previous call here. On
301 * the 1st call it will be empty.
302 */
303 DEBUGASSERT(ps);
304 DEBUGASSERT(prev_ps);
305
306 /* Handle changes to sockets the transfer is interested in. */
307 for(i = 0; i < ps->n; i++) {
308 unsigned char last_action;
309 bool first_time = FALSE; /* data/conn appears first time on socket */
310
311 s = ps->sockets[i];
312 /* Have we handled this socket before? */
313 entry = mev_sh_entry_get(&multi->ev.sh_entries, s);
314 if(!entry) {
315 /* new socket, add new entry */
316 first_time = TRUE;
317 entry = mev_sh_entry_add(&multi->ev.sh_entries, s);
318 if(!entry) /* fatal */
319 return CURLM_OUT_OF_MEMORY;
320 CURL_TRC_M(data, "ev new entry fd=%" FMT_SOCKET_T, s);
321 }
322 else if(conn) {
323 first_time = !mev_sh_entry_conn_known(entry, conn);
324 }
325 else {
326 first_time = !mev_sh_entry_xfer_known(entry, data);
327 }
328
329 /* What was the previous action the transfer had regarding this socket?
330 * If the transfer is new to the socket, disregard the information
331 * in `last_poll`, because the socket might have been destroyed and
332 * reopened. We would have cleared the sh_entry for that, but the socket
333 * might still be mentioned in the hashed pollsets. */
334 last_action = 0;
335 if(first_time) {
336 if(conn) {
337 if(!mev_sh_entry_conn_add(entry, conn))
338 return CURLM_OUT_OF_MEMORY;
339 }
340 else {
341 if(!mev_sh_entry_xfer_add(entry, data))
342 return CURLM_OUT_OF_MEMORY;
343 }
344 CURL_TRC_M(data, "ev entry fd=%" FMT_SOCKET_T ", added %s #%" FMT_OFF_T
345 ", total=%u/%d (xfer/conn)", s,
346 conn ? "connection" : "transfer",
347 conn ? conn->connection_id : data->mid,
348 Curl_uint32_spbset_count(&entry->xfers),
349 entry->conn ? 1 : 0);
350 }
351 else {
352 for(j = 0; j < prev_ps->n; j++) {
353 if(s == prev_ps->sockets[j]) {
354 last_action = prev_ps->actions[j];
355 break;
356 }
357 }
358 }
359 /* track readers/writers changes and report to socket callback */
360 mresult = mev_sh_entry_update(multi, data, entry, s,
361 last_action, ps->actions[i]);
362 if(mresult)
363 return mresult;
364 }
365
366 /* Handle changes to sockets the transfer is NO LONGER interested in. */
367 for(i = 0; i < prev_ps->n; i++) {
368 bool stillused = FALSE;
369
370 s = prev_ps->sockets[i];
371 for(j = 0; j < ps->n; j++) {
372 if(s == ps->sockets[j]) {
373 /* socket is still supervised */
374 stillused = TRUE;
375 break;
376 }
377 }
378 if(stillused)
379 continue;
380
381 entry = mev_sh_entry_get(&multi->ev.sh_entries, s);
382 /* if entry does not exist, we were either never told about it or
383 * have already cleaned up this socket via Curl_multi_ev_socket_done().
384 * In other words: this is perfectly normal */
385 if(!entry)
386 continue;
387
388 if(conn && !mev_sh_entry_conn_remove(entry, conn)) {
389 /* `conn` says in `prev_ps` that it had been using a socket,
390 * but `conn` has not been registered for it.
391 * This should not happen if our book-keeping is correct? */
392 CURL_TRC_M(data, "ev entry fd=%" FMT_SOCKET_T ", conn lost "
393 "interest but is not registered", s);
394 DEBUGASSERT(NULL);
395 continue;
396 }
397
398 if(!conn && !mev_sh_entry_xfer_remove(entry, data)) {
399 /* `data` says in `prev_ps` that it had been using a socket,
400 * but `data` has not been registered for it.
401 * This should not happen if our book-keeping is correct? */
402 CURL_TRC_M(data, "ev entry fd=%" FMT_SOCKET_T ", transfer lost "
403 "interest but is not registered", s);
404 DEBUGASSERT(NULL);
405 continue;
406 }
407
408 if(mev_sh_entry_user_count(entry)) {
409 /* track readers/writers changes and report to socket callback */
410 mresult = mev_sh_entry_update(multi, data, entry, s,
411 prev_ps->actions[i], 0);
412 if(mresult)
413 return mresult;
414 CURL_TRC_M(data, "ev entry fd=%" FMT_SOCKET_T ", removed transfer, "
415 "total=%u/%d (xfer/conn)", s,
416 Curl_uint32_spbset_count(&entry->xfers),
417 entry->conn ? 1 : 0);
418 }
419 else {
420 mresult = mev_forget_socket(multi, data, s, "last user gone");
C1: mev_pollset_diff calls mev_forget_socket when entry has no users
421 if(mresult)
422 return mresult;
423 }
424 } /* for loop over num */
425
426 /* Remember for next time */
427 Curl_pollset_move(prev_ps, ps);
428 return CURLM_OK;
429}
lib/multi_ev.clines 121–124 · definition of mev_sh_entry_kill
121static void mev_sh_entry_kill(struct Curl_multi *multi, curl_socket_t s)
122{
123 Curl_hash_delete(&multi->ev.sh_entries, (char *)&s, sizeof(curl_socket_t));
C1: mev_sh_entry_kill deletes entry from hash, freeing it
124}
lib/multi_ev.clines 215–282 · definition of mev_sh_entry_update
215static CURLMcode mev_sh_entry_update(struct Curl_multi *multi,
216 struct Curl_easy *data,
217 struct mev_sh_entry *entry,
218 curl_socket_t s,
219 unsigned char last_action,
220 unsigned char cur_action)
221{
222 int rc, comboaction;
223
224 /* we should only be called when the callback exists */
225 DEBUGASSERT(multi->socket_cb);
226 if(!multi->socket_cb)
227 return CURLM_OK;
228
229 /* Transfer `data` goes from `last_action` to `cur_action` on socket `s`
230 * with `multi->ev.sh_entries` entry `entry`. Update `entry` and trigger
231 * `multi->socket_cb` on change, if the callback is set. */
232 if(last_action == cur_action) /* nothing from `data` changed */
233 return CURLM_OK;
234
235 if(last_action & CURL_POLL_IN) {
236 DEBUGASSERT(entry->readers);
237 if(!(cur_action & CURL_POLL_IN))
238 entry->readers--;
239 }
240 else if(cur_action & CURL_POLL_IN)
241 entry->readers++;
242
243 if(last_action & CURL_POLL_OUT) {
244 DEBUGASSERT(entry->writers);
245 if(!(cur_action & CURL_POLL_OUT))
246 entry->writers--;
247 }
248 else if(cur_action & CURL_POLL_OUT)
249 entry->writers++;
250
251 DEBUGASSERT(entry->readers <= mev_sh_entry_user_count(entry));
252 DEBUGASSERT(entry->writers <= mev_sh_entry_user_count(entry));
253 DEBUGASSERT(entry->writers + entry->readers);
254
255 CURL_TRC_M(data, "ev update fd=%" FMT_SOCKET_T ", action '%s%s' -> '%s%s'"
256 " (%u/%u r/w)", s,
257 (last_action & CURL_POLL_IN) ? "IN" : "",
258 (last_action & CURL_POLL_OUT) ? "OUT" : "",
259 (cur_action & CURL_POLL_IN) ? "IN" : "",
260 (cur_action & CURL_POLL_OUT) ? "OUT" : "",
261 entry->readers, entry->writers);
262
263 comboaction = (entry->writers ? CURL_POLL_OUT : 0) |
264 (entry->readers ? CURL_POLL_IN : 0);
265 if(((int)entry->action == comboaction)) /* nothing for socket changed */
266 return CURLM_OK;
267
268 CURL_TRC_M(data, "ev update call(fd=%" FMT_SOCKET_T ", ev=%s%s)",
269 s, (comboaction & CURL_POLL_IN) ? "IN" : "",
270 (comboaction & CURL_POLL_OUT) ? "OUT" : "");
271 mev_in_callback(multi, TRUE);
272 rc = multi->socket_cb(data, s, comboaction, multi->socket_userp,
C1: mev_sh_entry_update calls socket_cb while holding entry pointer
273 entry->user_data);
274 mev_in_callback(multi, FALSE);
275 entry->announced = TRUE;
C1: entry->announced = TRUE; writes to entry after callback returns
C2: entry->announced = TRUE;
C4: Write to freed memory (entry->announced)
276 if(rc == -1) {
277 multi->dead = TRUE;
278 return CURLM_ABORTED_BY_CALLBACK;
279 }
280 entry->action = (unsigned int)comboaction;
C1: entry->action = (unsigned int)comboaction; second write to entry
C2: entry->action = (unsigned int)comboaction;
C4: Write to freed memory (entry->action)
281 return CURLM_OK;
282}
lib/multi_ev.c@curl-8_20_0lines 477–518 · definition of mev_assess as in release curl-8_20_0; differs from master; commits that changed it since: 000de81fb1 tidy-up: rename more `CURLcode` variables to `result`
Show 42 lines (not cited by the judge)
477static CURLMcode mev_assess(struct Curl_multi *multi,
478 struct Curl_easy *data,
479 struct connectdata *conn)
480{
481 struct easy_pollset ps, *last_ps;
482 CURLMcode mresult = CURLM_OK;
483
484 if(!multi || !multi->socket_cb)
485 return CURLM_OK;
486
487 Curl_pollset_init(&ps);
488 if(conn) {
489 CURLcode r = Curl_conn_adjust_pollset(data, conn, &ps);
490 if(r) {
491 mresult = (r == CURLE_OUT_OF_MEMORY) ?
492 CURLM_OUT_OF_MEMORY : CURLM_INTERNAL_ERROR;
493 goto out;
494 }
495 }
496 else
497 Curl_multi_pollset(data, &ps);
498 last_ps = mev_get_last_pollset(data, conn);
499
500 if(!last_ps && ps.n) {
501 if(conn)
502 last_ps = mev_add_new_conn_pollset(conn);
503 else
504 last_ps = mev_add_new_xfer_pollset(data);
505 if(!last_ps) {
506 mresult = CURLM_OUT_OF_MEMORY;
507 goto out;
508 }
509 }
510
511 if(last_ps)
512 mresult = mev_pollset_diff(multi, data, conn, &ps, last_ps);
513 else
514 DEBUGASSERT(!ps.n);
515out:
516 Curl_pollset_cleanup(&ps);
517 return mresult;
518}
lib/multi_ev.clines 38–41 · definition of mev_in_callback
Show 4 lines (not cited by the judge)
38static void mev_in_callback(struct Curl_multi *multi, bool value)
39{
40 multi->in_callback = value;
41}
lib/multi_ev.clines 82–90 · definition of mev_sh_entry_get
Show 9 lines (not cited by the judge)
82static struct mev_sh_entry *mev_sh_entry_get(struct Curl_hash *sh,
83 curl_socket_t s)
84{
85 if(s != CURL_SOCKET_BAD) {
86 /* only look for proper sockets */
87 return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
88 }
89 return NULL;
90}