1
0
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:
Eyal Sawady 2020-09-23 12:50:25 -04:00 committed by Drew DeVault
parent 0976b0e446
commit 174fbd5d09
6 changed files with 84 additions and 16 deletions

@ -44,5 +44,6 @@ struct gemini_tofu {
void gemini_tofu_init(struct gemini_tofu *tofu,
SSL_CTX *ssl_ctx, tofu_callback_t *cb, void *data);
void gemini_tofu_finish(struct gemini_tofu *tofu);
#endif

@ -118,11 +118,14 @@ gemini_request(const char *url, struct gemini_options *options,
} else {
if (strcmp(scheme, "gemini") != 0) {
res = GEMINI_ERR_NOT_GEMINI;
free(scheme);
goto cleanup;
}
free(scheme);
}
if (curl_url_get(uri, CURLUPART_HOST, &host, 0) != CURLUE_OK) {
res = GEMINI_ERR_INVALID_URL;
free(host);
goto cleanup;
}
@ -139,6 +142,7 @@ gemini_request(const char *url, struct gemini_options *options,
BIO *sbio = BIO_new(BIO_f_ssl());
res = gemini_connect(uri, options, resp, &resp->fd);
if (res != GEMINI_OK) {
free(host);
goto cleanup;
}
@ -146,11 +150,14 @@ gemini_request(const char *url, struct gemini_options *options,
assert(resp->ssl);
SSL_set_connect_state(resp->ssl);
if ((r = SSL_set1_host(resp->ssl, host)) != 1) {
free(host);
goto ssl_error;
}
if ((r = SSL_set_tlsext_host_name(resp->ssl, host)) != 1) {
free(host);
goto ssl_error;
}
free(host);
if ((r = SSL_set_fd(resp->ssl, resp->fd)) != 1) {
goto ssl_error;
}
@ -235,15 +242,16 @@ gemini_response_finish(struct gemini_response *resp)
}
if (resp->bio) {
BIO_free(BIO_pop(resp->bio)); // ssl bio
BIO_free(resp->bio); // buffered bio
BIO_free_all(resp->bio);
resp->bio = NULL;
}
if (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);
resp->ssl = NULL;

@ -336,6 +336,8 @@ next:
gemini_response_finish(&resp);
}
SSL_CTX_free(opts.ssl_ctx);
free(url);
gemini_tofu_finish(&cfg.tofu);
return ret;
}

@ -83,6 +83,7 @@ history_free(struct history *history)
return;
}
history_free(history->next);
free(history->url);
free(history);
}
@ -93,6 +94,9 @@ set_url(struct browser *browser, char *new_url, struct history **history)
fprintf(stderr, "Error: invalid URL\n");
return false;
}
if (browser->plain_url != NULL) {
free(browser->plain_url);
}
curl_url_get(browser->url, CURLUPART_URL, &browser->plain_url, 0);
if (history) {
struct history *next = calloc(1, sizeof(struct history));
@ -130,17 +134,19 @@ trim_ws(char *in)
static void
save_bookmark(struct browser *browser)
{
const char *path_fmt = get_data_pathfmt();
char *path_fmt = get_data_pathfmt();
static char path[PATH_MAX+1];
snprintf(path, sizeof(path), path_fmt, "bookmarks.gmi");
if (mkdirs(dirname(path), 0755) != 0) {
snprintf(path, sizeof(path), path_fmt, "bookmarks.gmi");
free(path_fmt);
fprintf(stderr, "Error creating directory %s: %s\n",
dirname(path), strerror(errno));
return;
}
snprintf(path, sizeof(path), path_fmt, "bookmarks.gmi");
free(path_fmt);
FILE *f = fopen(path, "a");
if (!f) {
fprintf(stderr, "Error opening %s for writing: %s\n",
@ -150,7 +156,7 @@ save_bookmark(struct browser *browser)
char *title = browser->page_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,
@ -159,6 +165,9 @@ save_bookmark(struct browser *browser)
fprintf(browser->tty, "Bookmark saved: %s\n",
title ? title : browser->plain_url);
if (title != NULL) {
free(title);
}
}
static void
@ -411,12 +420,14 @@ repeat:
}
break;
case GEMINI_PREFORMATTED_BEGIN:
gemini_token_finish(&tok);
/* fallthrough */
case GEMINI_PREFORMATTED_END:
continue; // Not used
case GEMINI_PREFORMATTED_TEXT:
col += fprintf(out, "` ");
if (text == NULL) {
text = tok.text;
text = tok.preformatted;
}
break;
case GEMINI_HEADING:
@ -484,6 +495,9 @@ repeat:
text = NULL;
}
}
if (text == NULL) {
gemini_token_finish(&tok);
}
while (col >= ws.ws_col) {
col -= ws.ws_col;
@ -510,8 +524,16 @@ repeat:
break;
case PROMPT_QUIT:
browser->running = false;
if (text != NULL) {
gemini_token_finish(&tok);
}
gemini_parser_finish(&p);
return true;
case PROMPT_ANSWERED:
if (text != NULL) {
gemini_token_finish(&tok);
}
gemini_parser_finish(&p);
return true;
case PROMPT_NEXT:
searching = true;
@ -523,6 +545,7 @@ repeat:
}
}
gemini_token_finish(&tok);
gemini_parser_finish(&p);
return false;
}
@ -617,6 +640,7 @@ do_requests(struct browser *browser, struct gemini_response *resp)
CURLUPART_SCHEME, &scheme, 0);
assert(uc == CURLUE_OK); // Invariant
if (strcmp(scheme, "file") == 0) {
free(scheme);
requesting = false;
char *path;
@ -630,6 +654,7 @@ do_requests(struct browser *browser, struct gemini_response *resp)
FILE *fp = fopen(path, "r");
if (!fp) {
resp->status = GEMINI_STATUS_NOT_FOUND;
free(path);
break;
}
@ -643,9 +668,14 @@ do_requests(struct browser *browser, struct gemini_response *resp)
} else {
resp->meta = strdup("application/x-octet-stream");
}
free(path);
resp->status = GEMINI_STATUS_SUCCESS;
resp->fd = -1;
resp->ssl = NULL;
resp->ssl_ctx = NULL;
return display_response(browser, resp);
}
free(scheme);
enum gemini_result res = gemini_request(browser->plain_url,
&browser->opts, resp);
@ -672,7 +702,7 @@ do_requests(struct browser *browser, struct gemini_response *resp)
case GEMINI_STATUS_CLASS_REDIRECT:
if (++nredir >= 5) {
requesting = false;
fprintf(stderr, "Error: maximum redirects (5) exceeded");
fprintf(stderr, "Error: maximum redirects (5) exceeded\n");
break;
}
fprintf(stderr, "Following redirect to %s\n", resp->meta);
@ -816,6 +846,7 @@ main(int argc, char *argv[])
break;
default:
fprintf(stderr, "fatal: unknown flag %c\n", c);
curl_url_cleanup(browser.url);
return 1;
}
}
@ -841,6 +872,7 @@ main(int argc, char *argv[])
static char prompt[4096];
if (do_requests(&browser, &resp)) {
// Skip prompts
gemini_response_finish(&resp);
goto next;
}
@ -880,8 +912,16 @@ next:;
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);
curl_url_cleanup(browser.url);
free(browser.page_title);
free(browser.plain_url);
fclose(browser.tty);
return 0;
}

@ -35,15 +35,14 @@ gemini_parser_next(struct gemini_parser *p, struct gemini_token *tok)
memset(tok, 0, sizeof(*tok));
int eof = 0;
while (!strstr(p->buf, "\n")) {
if (p->bufln == p->bufsz) {
while (!strchr(p->buf, '\n')) {
while (p->bufln >= p->bufsz - 1) {
p->bufsz *= 2;
char *buf = realloc(p->buf, p->bufsz);
assert(buf);
p->buf = buf;
p->buf = realloc(p->buf, p->bufsz);
assert(p->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) {
return -1;
} else if (n == 0) {
@ -55,7 +54,7 @@ gemini_parser_next(struct gemini_parser *p, struct gemini_token *tok)
}
char *end;
if ((end = strstr(p->buf, "\n")) != NULL) {
if ((end = strchr(p->buf, '\n')) != NULL) {
*end = 0;
}

@ -150,7 +150,7 @@ gemini_tofu_init(struct gemini_tofu *tofu,
{.var = "XDG_DATA_HOME", .path = "/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),
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),
path_fmt, "known_hosts");
free(path_fmt);
tofu->callback = cb;
tofu->cb_data = cb_data;
@ -175,6 +176,7 @@ gemini_tofu_init(struct gemini_tofu *tofu,
}
size_t n = 0;
char *line = NULL;
tofu->known_hosts = NULL;
while (getline(&line, &n, f) != -1) {
struct known_host *host = calloc(1, sizeof(struct known_host));
char *tok = strtok(line, " ");
@ -184,6 +186,7 @@ gemini_tofu_init(struct gemini_tofu *tofu,
tok = strtok(NULL, " ");
assert(tok);
if (strcmp(tok, "SHA-512") != 0) {
free(host->host);
free(host);
continue;
}
@ -199,4 +202,19 @@ gemini_tofu_init(struct gemini_tofu *tofu,
host->next = tofu->known_hosts;
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);
}
}