mirror of
https://git.sr.ht/~sircmpwn/gmni
synced 2024-11-23 04:51:59 +01:00
Fix memory leaks
This commit is contained in:
parent
0976b0e446
commit
174fbd5d09
@ -44,5 +44,6 @@ struct gemini_tofu {
|
|||||||
|
|
||||||
void gemini_tofu_init(struct gemini_tofu *tofu,
|
void gemini_tofu_init(struct gemini_tofu *tofu,
|
||||||
SSL_CTX *ssl_ctx, tofu_callback_t *cb, void *data);
|
SSL_CTX *ssl_ctx, tofu_callback_t *cb, void *data);
|
||||||
|
void gemini_tofu_finish(struct gemini_tofu *tofu);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
14
src/client.c
14
src/client.c
@ -118,11 +118,14 @@ gemini_request(const char *url, struct gemini_options *options,
|
|||||||
} else {
|
} else {
|
||||||
if (strcmp(scheme, "gemini") != 0) {
|
if (strcmp(scheme, "gemini") != 0) {
|
||||||
res = GEMINI_ERR_NOT_GEMINI;
|
res = GEMINI_ERR_NOT_GEMINI;
|
||||||
|
free(scheme);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
free(scheme);
|
||||||
}
|
}
|
||||||
if (curl_url_get(uri, CURLUPART_HOST, &host, 0) != CURLUE_OK) {
|
if (curl_url_get(uri, CURLUPART_HOST, &host, 0) != CURLUE_OK) {
|
||||||
res = GEMINI_ERR_INVALID_URL;
|
res = GEMINI_ERR_INVALID_URL;
|
||||||
|
free(host);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,6 +142,7 @@ gemini_request(const char *url, struct gemini_options *options,
|
|||||||
BIO *sbio = BIO_new(BIO_f_ssl());
|
BIO *sbio = BIO_new(BIO_f_ssl());
|
||||||
res = gemini_connect(uri, options, resp, &resp->fd);
|
res = gemini_connect(uri, options, resp, &resp->fd);
|
||||||
if (res != GEMINI_OK) {
|
if (res != GEMINI_OK) {
|
||||||
|
free(host);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,11 +150,14 @@ gemini_request(const char *url, struct gemini_options *options,
|
|||||||
assert(resp->ssl);
|
assert(resp->ssl);
|
||||||
SSL_set_connect_state(resp->ssl);
|
SSL_set_connect_state(resp->ssl);
|
||||||
if ((r = SSL_set1_host(resp->ssl, host)) != 1) {
|
if ((r = SSL_set1_host(resp->ssl, host)) != 1) {
|
||||||
|
free(host);
|
||||||
goto ssl_error;
|
goto ssl_error;
|
||||||
}
|
}
|
||||||
if ((r = SSL_set_tlsext_host_name(resp->ssl, host)) != 1) {
|
if ((r = SSL_set_tlsext_host_name(resp->ssl, host)) != 1) {
|
||||||
|
free(host);
|
||||||
goto ssl_error;
|
goto ssl_error;
|
||||||
}
|
}
|
||||||
|
free(host);
|
||||||
if ((r = SSL_set_fd(resp->ssl, resp->fd)) != 1) {
|
if ((r = SSL_set_fd(resp->ssl, resp->fd)) != 1) {
|
||||||
goto ssl_error;
|
goto ssl_error;
|
||||||
}
|
}
|
||||||
@ -235,15 +242,16 @@ gemini_response_finish(struct gemini_response *resp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (resp->bio) {
|
if (resp->bio) {
|
||||||
BIO_free(BIO_pop(resp->bio)); // ssl bio
|
BIO_free_all(resp->bio);
|
||||||
BIO_free(resp->bio); // buffered bio
|
|
||||||
resp->bio = NULL;
|
resp->bio = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resp->ssl) {
|
if (resp->ssl) {
|
||||||
SSL_free(resp->ssl);
|
SSL_free(resp->ssl);
|
||||||
}
|
}
|
||||||
SSL_CTX_free(resp->ssl_ctx);
|
if (resp->ssl_ctx) {
|
||||||
|
SSL_CTX_free(resp->ssl_ctx);
|
||||||
|
}
|
||||||
free(resp->meta);
|
free(resp->meta);
|
||||||
|
|
||||||
resp->ssl = NULL;
|
resp->ssl = NULL;
|
||||||
|
@ -336,6 +336,8 @@ next:
|
|||||||
gemini_response_finish(&resp);
|
gemini_response_finish(&resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SSL_CTX_free(opts.ssl_ctx);
|
||||||
free(url);
|
free(url);
|
||||||
|
gemini_tofu_finish(&cfg.tofu);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
50
src/gmnlm.c
50
src/gmnlm.c
@ -83,6 +83,7 @@ history_free(struct history *history)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
history_free(history->next);
|
history_free(history->next);
|
||||||
|
free(history->url);
|
||||||
free(history);
|
free(history);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,6 +94,9 @@ set_url(struct browser *browser, char *new_url, struct history **history)
|
|||||||
fprintf(stderr, "Error: invalid URL\n");
|
fprintf(stderr, "Error: invalid URL\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (browser->plain_url != NULL) {
|
||||||
|
free(browser->plain_url);
|
||||||
|
}
|
||||||
curl_url_get(browser->url, CURLUPART_URL, &browser->plain_url, 0);
|
curl_url_get(browser->url, CURLUPART_URL, &browser->plain_url, 0);
|
||||||
if (history) {
|
if (history) {
|
||||||
struct history *next = calloc(1, sizeof(struct history));
|
struct history *next = calloc(1, sizeof(struct history));
|
||||||
@ -130,17 +134,19 @@ trim_ws(char *in)
|
|||||||
static void
|
static void
|
||||||
save_bookmark(struct browser *browser)
|
save_bookmark(struct browser *browser)
|
||||||
{
|
{
|
||||||
const char *path_fmt = get_data_pathfmt();
|
char *path_fmt = get_data_pathfmt();
|
||||||
static char path[PATH_MAX+1];
|
static char path[PATH_MAX+1];
|
||||||
snprintf(path, sizeof(path), path_fmt, "bookmarks.gmi");
|
snprintf(path, sizeof(path), path_fmt, "bookmarks.gmi");
|
||||||
if (mkdirs(dirname(path), 0755) != 0) {
|
if (mkdirs(dirname(path), 0755) != 0) {
|
||||||
snprintf(path, sizeof(path), path_fmt, "bookmarks.gmi");
|
snprintf(path, sizeof(path), path_fmt, "bookmarks.gmi");
|
||||||
|
free(path_fmt);
|
||||||
fprintf(stderr, "Error creating directory %s: %s\n",
|
fprintf(stderr, "Error creating directory %s: %s\n",
|
||||||
dirname(path), strerror(errno));
|
dirname(path), strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(path, sizeof(path), path_fmt, "bookmarks.gmi");
|
snprintf(path, sizeof(path), path_fmt, "bookmarks.gmi");
|
||||||
|
free(path_fmt);
|
||||||
FILE *f = fopen(path, "a");
|
FILE *f = fopen(path, "a");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
fprintf(stderr, "Error opening %s for writing: %s\n",
|
fprintf(stderr, "Error opening %s for writing: %s\n",
|
||||||
@ -150,7 +156,7 @@ save_bookmark(struct browser *browser)
|
|||||||
|
|
||||||
char *title = browser->page_title;
|
char *title = browser->page_title;
|
||||||
if (title) {
|
if (title) {
|
||||||
title = trim_ws(browser->page_title);
|
title = trim_ws(strdup(browser->page_title));
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(f, "=> %s%s%s\n", browser->plain_url,
|
fprintf(f, "=> %s%s%s\n", browser->plain_url,
|
||||||
@ -159,6 +165,9 @@ save_bookmark(struct browser *browser)
|
|||||||
|
|
||||||
fprintf(browser->tty, "Bookmark saved: %s\n",
|
fprintf(browser->tty, "Bookmark saved: %s\n",
|
||||||
title ? title : browser->plain_url);
|
title ? title : browser->plain_url);
|
||||||
|
if (title != NULL) {
|
||||||
|
free(title);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -411,12 +420,14 @@ repeat:
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GEMINI_PREFORMATTED_BEGIN:
|
case GEMINI_PREFORMATTED_BEGIN:
|
||||||
|
gemini_token_finish(&tok);
|
||||||
|
/* fallthrough */
|
||||||
case GEMINI_PREFORMATTED_END:
|
case GEMINI_PREFORMATTED_END:
|
||||||
continue; // Not used
|
continue; // Not used
|
||||||
case GEMINI_PREFORMATTED_TEXT:
|
case GEMINI_PREFORMATTED_TEXT:
|
||||||
col += fprintf(out, "` ");
|
col += fprintf(out, "` ");
|
||||||
if (text == NULL) {
|
if (text == NULL) {
|
||||||
text = tok.text;
|
text = tok.preformatted;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GEMINI_HEADING:
|
case GEMINI_HEADING:
|
||||||
@ -484,6 +495,9 @@ repeat:
|
|||||||
text = NULL;
|
text = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (text == NULL) {
|
||||||
|
gemini_token_finish(&tok);
|
||||||
|
}
|
||||||
|
|
||||||
while (col >= ws.ws_col) {
|
while (col >= ws.ws_col) {
|
||||||
col -= ws.ws_col;
|
col -= ws.ws_col;
|
||||||
@ -510,8 +524,16 @@ repeat:
|
|||||||
break;
|
break;
|
||||||
case PROMPT_QUIT:
|
case PROMPT_QUIT:
|
||||||
browser->running = false;
|
browser->running = false;
|
||||||
|
if (text != NULL) {
|
||||||
|
gemini_token_finish(&tok);
|
||||||
|
}
|
||||||
|
gemini_parser_finish(&p);
|
||||||
return true;
|
return true;
|
||||||
case PROMPT_ANSWERED:
|
case PROMPT_ANSWERED:
|
||||||
|
if (text != NULL) {
|
||||||
|
gemini_token_finish(&tok);
|
||||||
|
}
|
||||||
|
gemini_parser_finish(&p);
|
||||||
return true;
|
return true;
|
||||||
case PROMPT_NEXT:
|
case PROMPT_NEXT:
|
||||||
searching = true;
|
searching = true;
|
||||||
@ -523,6 +545,7 @@ repeat:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gemini_token_finish(&tok);
|
||||||
gemini_parser_finish(&p);
|
gemini_parser_finish(&p);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -617,6 +640,7 @@ do_requests(struct browser *browser, struct gemini_response *resp)
|
|||||||
CURLUPART_SCHEME, &scheme, 0);
|
CURLUPART_SCHEME, &scheme, 0);
|
||||||
assert(uc == CURLUE_OK); // Invariant
|
assert(uc == CURLUE_OK); // Invariant
|
||||||
if (strcmp(scheme, "file") == 0) {
|
if (strcmp(scheme, "file") == 0) {
|
||||||
|
free(scheme);
|
||||||
requesting = false;
|
requesting = false;
|
||||||
|
|
||||||
char *path;
|
char *path;
|
||||||
@ -630,6 +654,7 @@ do_requests(struct browser *browser, struct gemini_response *resp)
|
|||||||
FILE *fp = fopen(path, "r");
|
FILE *fp = fopen(path, "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
resp->status = GEMINI_STATUS_NOT_FOUND;
|
resp->status = GEMINI_STATUS_NOT_FOUND;
|
||||||
|
free(path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -643,9 +668,14 @@ do_requests(struct browser *browser, struct gemini_response *resp)
|
|||||||
} else {
|
} else {
|
||||||
resp->meta = strdup("application/x-octet-stream");
|
resp->meta = strdup("application/x-octet-stream");
|
||||||
}
|
}
|
||||||
|
free(path);
|
||||||
resp->status = GEMINI_STATUS_SUCCESS;
|
resp->status = GEMINI_STATUS_SUCCESS;
|
||||||
|
resp->fd = -1;
|
||||||
|
resp->ssl = NULL;
|
||||||
|
resp->ssl_ctx = NULL;
|
||||||
return display_response(browser, resp);
|
return display_response(browser, resp);
|
||||||
}
|
}
|
||||||
|
free(scheme);
|
||||||
|
|
||||||
enum gemini_result res = gemini_request(browser->plain_url,
|
enum gemini_result res = gemini_request(browser->plain_url,
|
||||||
&browser->opts, resp);
|
&browser->opts, resp);
|
||||||
@ -672,7 +702,7 @@ do_requests(struct browser *browser, struct gemini_response *resp)
|
|||||||
case GEMINI_STATUS_CLASS_REDIRECT:
|
case GEMINI_STATUS_CLASS_REDIRECT:
|
||||||
if (++nredir >= 5) {
|
if (++nredir >= 5) {
|
||||||
requesting = false;
|
requesting = false;
|
||||||
fprintf(stderr, "Error: maximum redirects (5) exceeded");
|
fprintf(stderr, "Error: maximum redirects (5) exceeded\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "Following redirect to %s\n", resp->meta);
|
fprintf(stderr, "Following redirect to %s\n", resp->meta);
|
||||||
@ -816,6 +846,7 @@ main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "fatal: unknown flag %c\n", c);
|
fprintf(stderr, "fatal: unknown flag %c\n", c);
|
||||||
|
curl_url_cleanup(browser.url);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -841,6 +872,7 @@ main(int argc, char *argv[])
|
|||||||
static char prompt[4096];
|
static char prompt[4096];
|
||||||
if (do_requests(&browser, &resp)) {
|
if (do_requests(&browser, &resp)) {
|
||||||
// Skip prompts
|
// Skip prompts
|
||||||
|
gemini_response_finish(&resp);
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -880,8 +912,16 @@ next:;
|
|||||||
browser.links = NULL;
|
browser.links = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
history_free(browser.history);
|
gemini_tofu_finish(&browser.tofu);
|
||||||
|
struct history *hist = browser.history;
|
||||||
|
while (hist && hist->prev) {
|
||||||
|
hist = hist->prev;
|
||||||
|
}
|
||||||
|
history_free(hist);
|
||||||
SSL_CTX_free(browser.opts.ssl_ctx);
|
SSL_CTX_free(browser.opts.ssl_ctx);
|
||||||
curl_url_cleanup(browser.url);
|
curl_url_cleanup(browser.url);
|
||||||
|
free(browser.page_title);
|
||||||
|
free(browser.plain_url);
|
||||||
|
fclose(browser.tty);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
13
src/parser.c
13
src/parser.c
@ -35,15 +35,14 @@ gemini_parser_next(struct gemini_parser *p, struct gemini_token *tok)
|
|||||||
memset(tok, 0, sizeof(*tok));
|
memset(tok, 0, sizeof(*tok));
|
||||||
|
|
||||||
int eof = 0;
|
int eof = 0;
|
||||||
while (!strstr(p->buf, "\n")) {
|
while (!strchr(p->buf, '\n')) {
|
||||||
if (p->bufln == p->bufsz) {
|
while (p->bufln >= p->bufsz - 1) {
|
||||||
p->bufsz *= 2;
|
p->bufsz *= 2;
|
||||||
char *buf = realloc(p->buf, p->bufsz);
|
p->buf = realloc(p->buf, p->bufsz);
|
||||||
assert(buf);
|
assert(p->buf);
|
||||||
p->buf = buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int n = BIO_read(p->f, &p->buf[p->bufln], p->bufsz - p->bufln);
|
ssize_t n = BIO_read(p->f, &p->buf[p->bufln], p->bufsz - p->bufln - 1);
|
||||||
if (n == -1) {
|
if (n == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (n == 0) {
|
} else if (n == 0) {
|
||||||
@ -55,7 +54,7 @@ gemini_parser_next(struct gemini_parser *p, struct gemini_token *tok)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *end;
|
char *end;
|
||||||
if ((end = strstr(p->buf, "\n")) != NULL) {
|
if ((end = strchr(p->buf, '\n')) != NULL) {
|
||||||
*end = 0;
|
*end = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
src/tofu.c
20
src/tofu.c
@ -150,7 +150,7 @@ gemini_tofu_init(struct gemini_tofu *tofu,
|
|||||||
{.var = "XDG_DATA_HOME", .path = "/gmni/%s"},
|
{.var = "XDG_DATA_HOME", .path = "/gmni/%s"},
|
||||||
{.var = "HOME", .path = "/.local/share/gmni/%s"}
|
{.var = "HOME", .path = "/.local/share/gmni/%s"}
|
||||||
};
|
};
|
||||||
const char *path_fmt = getpath(paths, sizeof(paths) / sizeof(paths[0]));
|
char *path_fmt = getpath(paths, sizeof(paths) / sizeof(paths[0]));
|
||||||
snprintf(tofu->known_hosts_path, sizeof(tofu->known_hosts_path),
|
snprintf(tofu->known_hosts_path, sizeof(tofu->known_hosts_path),
|
||||||
path_fmt, "known_hosts");
|
path_fmt, "known_hosts");
|
||||||
|
|
||||||
@ -164,6 +164,7 @@ gemini_tofu_init(struct gemini_tofu *tofu,
|
|||||||
|
|
||||||
snprintf(tofu->known_hosts_path, sizeof(tofu->known_hosts_path),
|
snprintf(tofu->known_hosts_path, sizeof(tofu->known_hosts_path),
|
||||||
path_fmt, "known_hosts");
|
path_fmt, "known_hosts");
|
||||||
|
free(path_fmt);
|
||||||
|
|
||||||
tofu->callback = cb;
|
tofu->callback = cb;
|
||||||
tofu->cb_data = cb_data;
|
tofu->cb_data = cb_data;
|
||||||
@ -175,6 +176,7 @@ gemini_tofu_init(struct gemini_tofu *tofu,
|
|||||||
}
|
}
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
|
tofu->known_hosts = NULL;
|
||||||
while (getline(&line, &n, f) != -1) {
|
while (getline(&line, &n, f) != -1) {
|
||||||
struct known_host *host = calloc(1, sizeof(struct known_host));
|
struct known_host *host = calloc(1, sizeof(struct known_host));
|
||||||
char *tok = strtok(line, " ");
|
char *tok = strtok(line, " ");
|
||||||
@ -184,6 +186,7 @@ gemini_tofu_init(struct gemini_tofu *tofu,
|
|||||||
tok = strtok(NULL, " ");
|
tok = strtok(NULL, " ");
|
||||||
assert(tok);
|
assert(tok);
|
||||||
if (strcmp(tok, "SHA-512") != 0) {
|
if (strcmp(tok, "SHA-512") != 0) {
|
||||||
|
free(host->host);
|
||||||
free(host);
|
free(host);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -199,4 +202,19 @@ gemini_tofu_init(struct gemini_tofu *tofu,
|
|||||||
host->next = tofu->known_hosts;
|
host->next = tofu->known_hosts;
|
||||||
tofu->known_hosts = host;
|
tofu->known_hosts = host;
|
||||||
}
|
}
|
||||||
|
free(line);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gemini_tofu_finish(struct gemini_tofu *tofu)
|
||||||
|
{
|
||||||
|
struct known_host *host = tofu->known_hosts;
|
||||||
|
while (host) {
|
||||||
|
struct known_host *tmp = host;
|
||||||
|
host = host->next;
|
||||||
|
free(tmp->host);
|
||||||
|
free(tmp->fingerprint);
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user