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,
|
||||
SSL_CTX *ssl_ctx, tofu_callback_t *cb, void *data);
|
||||
void gemini_tofu_finish(struct gemini_tofu *tofu);
|
||||
|
||||
#endif
|
||||
|
14
src/client.c
14
src/client.c
@ -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;
|
||||
}
|
||||
|
50
src/gmnlm.c
50
src/gmnlm.c
@ -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;
|
||||
}
|
||||
|
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));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
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 = "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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user