libfetch: fix races in the cache connection code.

Tested by @Gottox.
This commit is contained in:
Juan RP 2014-12-23 10:52:54 +01:00
parent 6a985190aa
commit 4ee6f943dd
3 changed files with 11 additions and 16 deletions

4
NEWS
View File

@ -1,8 +1,6 @@
xbps-0.43 (???): xbps-0.43 (???):
* libxbps: xbps_archive_fetch_xxx() are now protected with a mutex to avoid * libfetch: fix races in the cache connection code.
data races with 8 threads or more. Reproducable by @chneukirchen on a
8 core machine.
xbps-0.42 (2014-12-22): xbps-0.42 (2014-12-22):

View File

@ -66,6 +66,8 @@
#include <signal.h> #include <signal.h>
#endif #endif
#include <pthread.h>
#include "fetch.h" #include "fetch.h"
#include "common.h" #include "common.h"
@ -333,6 +335,7 @@ fetch_connect(struct url *url, int af, int verbose)
return (conn); return (conn);
} }
static pthread_mutex_t cache_mtx = PTHREAD_MUTEX_INITIALIZER;
static conn_t *connection_cache; static conn_t *connection_cache;
static int cache_global_limit = 0; static int cache_global_limit = 0;
static int cache_per_host_limit = 0; static int cache_per_host_limit = 0;
@ -379,6 +382,7 @@ fetch_cache_get(const struct url *url, int af)
{ {
conn_t *conn, *last_conn = NULL; conn_t *conn, *last_conn = NULL;
pthread_mutex_lock(&cache_mtx);
for (conn = connection_cache; conn; conn = conn->next_cached) { for (conn = connection_cache; conn; conn = conn->next_cached) {
if (conn->cache_url->port == url->port && if (conn->cache_url->port == url->port &&
strcmp(conn->cache_url->scheme, url->scheme) == 0 && strcmp(conn->cache_url->scheme, url->scheme) == 0 &&
@ -391,9 +395,12 @@ fetch_cache_get(const struct url *url, int af)
last_conn->next_cached = conn->next_cached; last_conn->next_cached = conn->next_cached;
else else
connection_cache = conn->next_cached; connection_cache = conn->next_cached;
pthread_mutex_unlock(&cache_mtx);
return conn; return conn;
} }
} }
pthread_mutex_unlock(&cache_mtx);
return NULL; return NULL;
} }
@ -414,6 +421,7 @@ fetch_cache_put(conn_t *conn, int (*closecb)(conn_t *))
return; return;
} }
pthread_mutex_lock(&cache_mtx);
global_count = host_count = 0; global_count = host_count = 0;
last = NULL; last = NULL;
for (iter = connection_cache; iter; for (iter = connection_cache; iter;
@ -435,6 +443,7 @@ fetch_cache_put(conn_t *conn, int (*closecb)(conn_t *))
conn->cache_close = closecb; conn->cache_close = closecb;
conn->next_cached = connection_cache; conn->next_cached = connection_cache;
connection_cache = conn; connection_cache = conn;
pthread_mutex_unlock(&cache_mtx);
} }
/* /*

View File

@ -30,7 +30,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <pthread.h>
#include "xbps_api_impl.h" #include "xbps_api_impl.h"
@ -44,7 +43,6 @@ struct fetch_archive {
struct url *url; struct url *url;
struct fetchIO *fetch; struct fetchIO *fetch;
char buffer[32768]; char buffer[32768];
pthread_mutex_t mtx;
}; };
static int static int
@ -52,9 +50,7 @@ fetch_archive_open(struct archive *a _unused, void *client_data)
{ {
struct fetch_archive *f = client_data; struct fetch_archive *f = client_data;
pthread_mutex_lock(&f->mtx);
f->fetch = fetchGet(f->url, NULL); f->fetch = fetchGet(f->url, NULL);
pthread_mutex_unlock(&f->mtx);
if (f->fetch == NULL) if (f->fetch == NULL)
return ENOENT; return ENOENT;
@ -66,13 +62,9 @@ static ssize_t
fetch_archive_read(struct archive *a _unused, void *client_data, const void **buf) fetch_archive_read(struct archive *a _unused, void *client_data, const void **buf)
{ {
struct fetch_archive *f = client_data; struct fetch_archive *f = client_data;
ssize_t res;
*buf = f->buffer; *buf = f->buffer;
pthread_mutex_lock(&f->mtx); return fetchIO_read(f->fetch, f->buffer, sizeof(f->buffer));
res = fetchIO_read(f->fetch, f->buffer, sizeof(f->buffer));
pthread_mutex_unlock(&f->mtx);
return res;
} }
static int static int
@ -80,11 +72,8 @@ fetch_archive_close(struct archive *a _unused, void *client_data)
{ {
struct fetch_archive *f = client_data; struct fetch_archive *f = client_data;
pthread_mutex_lock(&f->mtx);
if (f->fetch != NULL) if (f->fetch != NULL)
fetchIO_close(f->fetch); fetchIO_close(f->fetch);
pthread_mutex_unlock(&f->mtx);
pthread_mutex_destroy(&f->mtx);
free(f); free(f);
return 0; return 0;
@ -101,7 +90,6 @@ open_archive_by_url(struct url *url)
return NULL; return NULL;
f->url = url; f->url = url;
pthread_mutex_init(&f->mtx, NULL);
if ((a = archive_read_new()) == NULL) { if ((a = archive_read_new()) == NULL) {
free(f); free(f);