commit 4100698bbc792f50bb38eca67839a37b0932f7be
parent e2641771bea38c1ff5bf9429eecd693932d179fe
Author: Chris Bracken <chris@bracken.jp>
Date: Wed, 23 Jul 2025 16:28:59 -0700
Do not open files over 16MB in size
In order to prevent resource exhaustion -- either out-of-memory issues
while reading or filesystem free space exhaustion by emitting
exceedingly large files, set a 16MB maximum filesize limit. Anything
over 16MB will not be read, and instead "File too large to display" will
be emitted to the output instead.
Diffstat:
4 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/git/file.h b/git/file.h
@@ -17,6 +17,8 @@ const char* gitfile_repo_path(const GitFile* file);
// Submodule commit OID. Empty string for files.
const char* gitfile_commit_oid(const GitFile* file);
ssize_t gitfile_size_bytes(const GitFile* file);
+
+// Returns file size in lines, or -1 if binary file, -2 if file too large.
ssize_t gitfile_size_lines(const GitFile* file);
const char* gitfile_content(const GitFile* file);
diff --git a/git/repo.c b/git/repo.c
@@ -46,6 +46,9 @@ static const size_t kLicensesLen = sizeof(kLicenses) / sizeof(char*);
static const char* kReadmes[] = {"HEAD:README", "HEAD:README.md"};
static const size_t kReadmesLen = sizeof(kReadmes) / sizeof(char*);
+/* Maximum file size to load into memory, in bytes. */
+static const ssize_t kMaxFileSizeBytes = 16 * 1024 * 1024;
+
/* Utilities */
static size_t string_count_lines(const char* str, ssize_t size_bytes);
static bool string_ends_with(const char* str, const char* suffix);
@@ -453,10 +456,14 @@ bool gitrepo_walk_tree_files(git_repository* repo,
ssize_t size_bytes = git_blob_rawsize(blob);
ssize_t size_lines = -1;
const char* content = "";
- if (!git_blob_is_binary(blob)) {
+
+ if (size_bytes > kMaxFileSizeBytes) {
+ size_lines = -2; /* oversized file */
+ } else if (!git_blob_is_binary(blob)) {
content = (const char*)git_blob_rawcontent(blob);
size_lines = string_count_lines(content, size_bytes);
}
+
char* filemode = format_filemode(git_tree_entry_filemode(entry));
GitFile* fileinfo =
gitfile_create(kFileTypeFile, filemode, entrypath, entrypath, "",
diff --git a/writer/gopher/fileblob.c b/writer/gopher/fileblob.c
@@ -86,10 +86,15 @@ void gopher_fileblob_add_file(GopherFileBlob* blob, const GitFile* file) {
fprintf(out, " (%zdB)\n", gitfile_size_bytes(file));
fprintf(out, "---\n");
- if (gitfile_size_lines(file) < 0) {
+ ssize_t size_lines = gitfile_size_lines(file);
+ if (size_lines == -1) {
fprintf(out, "Binary file.\n");
return;
}
+ if (size_lines == -2) {
+ fprintf(out, "File too large to display.\n");
+ return;
+ }
size_t i = 0;
const char* content = gitfile_content(file);
diff --git a/writer/html/fileblob.c b/writer/html/fileblob.c
@@ -87,10 +87,15 @@ void html_fileblob_add_file(HtmlFileBlob* blob, const GitFile* file) {
fprintf(out, " (%zdB)", gitfile_size_bytes(file));
fprintf(out, "</p><hr/>");
- if (gitfile_size_lines(file) < 0) {
+ ssize_t size_lines = gitfile_size_lines(file);
+ if (size_lines == -1) {
fprintf(out, "<p>Binary file.</p>\n");
return;
}
+ if (size_lines == -2) {
+ fprintf(out, "<p>File too large to display.</p>\n");
+ return;
+ }
fprintf(out, "<pre id=\"blob\">\n");