Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 26 additions & 24 deletions hotfuzz-module.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ static void match_row(struct Str a, struct Str b, int *bonuses, unsigned i, int
static int calc_cost(struct Str needle, struct Str haystack, bool ignore_case) {
unsigned n = haystack.len, m = needle.len;
if (n > MAX_HAYSTACK_LEN || m > MAX_NEEDLE_LEN) return 100000;
if (!m) return 0; // Everything matches the empty needle, at no cost
int c[MAX_NEEDLE_LEN], d[MAX_NEEDLE_LEN];
for (unsigned j = 0; j < m; ++j) c[j] = d[j] = 100000;

Expand Down Expand Up @@ -131,32 +132,33 @@ static void bump_free(struct Bump *head) {

/** Copies the Emacs string to make its contents accessible. */
static struct Str copy_emacs_string(emacs_env *env, struct Bump **bump, emacs_value value) {
char *buf = NULL;
ptrdiff_t origlen, len;
if (*bump) {
// Opportunistically try to copy into remaining space
buf = (*bump)->cursor;
len = origlen = (*bump)->limit - (*bump)->cursor;
}
// Determine the size of the string (including null-terminator)
if (env->copy_string_contents(env, value, buf, &len)) {
if (buf) goto success;
} else {
if (!buf || len == origlen) return (struct Str) { 0 };
env->non_local_exit_clear(env);
// Ask for the size (including null-terminator) with a NULL buffer. Passing
// a buffer that turns out to be too small is not a usable size query: Emacs
// 31 signals `memory-buffer-too-small' in that case, and older versions
// leave the required size unreported when the shortfall is detected early.
ptrdiff_t len = 0;
if (!env->copy_string_contents(env, value, NULL, &len)) return (struct Str) { 0 };

// `strtolower' rewrites the string in uint64_t-sized chunks and so touches up
// to alignof(uint64_t)-1 bytes past the null-terminator. Reserve the rounded
// up size to keep those writes inside the block.
ptrdiff_t need = (len + alignof(uint64_t) - 1) & ~(ptrdiff_t) (alignof(uint64_t) - 1);

char *buf;
if (*bump && (*bump)->limit - (*bump)->cursor >= need)
buf = (*bump)->cursor; // Fits in the remaining space
else {
size_t capacity = *bump ? 2 * ((*bump)->limit - (*bump)->b) : 2048;
if (capacity < (size_t) need) capacity = need;
struct Bump *new;
if (!(new = malloc(sizeof *new + capacity))) return (struct Str) { 0 };
*new = (struct Bump) { .next = *bump, .cursor = new->b, .limit = new->b + capacity };
*bump = new;
buf = new->cursor;
}

size_t capacity = *bump ? 2 * ((*bump)->limit - (*bump)->b) : 2048;
if (capacity < (size_t) len) capacity = len + alignof(uint64_t) - 1;
struct Bump *new;
if (!(new = malloc(sizeof *new + capacity))) return (struct Str) { 0 };
*new = (struct Bump) { .next = *bump, .cursor = new->b, .limit = new->b + capacity };
*bump = new;

env->copy_string_contents(env, value, buf = new->cursor, &len);
success:
(*bump)->cursor = (char *) (((uintptr_t) (*bump)->cursor + len
+ alignof(uint64_t) - 1) & ~(alignof(uint64_t) - 1));
if (!env->copy_string_contents(env, value, buf, &len)) return (struct Str) { 0 };
(*bump)->cursor = buf + need;
return (struct Str) { buf, len - 1 };
}

Expand Down