Skip to content

Commit

Permalink
Handle YAML.load_file on Psych 4
Browse files Browse the repository at this point in the history
  • Loading branch information
byroot committed Jan 13, 2022
1 parent d19eef1 commit 89158d4
Show file tree
Hide file tree
Showing 4 changed files with 296 additions and 103 deletions.
55 changes: 40 additions & 15 deletions ext/bootsnap/bootsnap.c
Expand Up @@ -75,7 +75,7 @@ struct bs_cache_key {
STATIC_ASSERT(sizeof(struct bs_cache_key) == KEY_SIZE);

/* Effectively a schema version. Bumping invalidates all previous caches */
static const uint32_t current_version = 3;
static const uint32_t current_version = 4;

/* hash of e.g. "x86_64-darwin17", invalidating when ruby is recompiled on a
* new OS ABI, etc. */
Expand Down Expand Up @@ -426,6 +426,7 @@ open_current_file(char * path, struct bs_cache_key * key, const char ** errno_pr
#define ERROR_WITH_ERRNO -1
#define CACHE_MISS -2
#define CACHE_STALE -3
#define CACHE_UNCOMPILABLE -4

/*
* Read the cache key from the given fd, which must have position 0 (e.g.
Expand Down Expand Up @@ -507,14 +508,14 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE *
if (data_size > 100000000000) {
*errno_provenance = "bs_fetch:fetch_cached_data:datasize";
errno = EINVAL; /* because wtf? */
ret = -1;
ret = ERROR_WITH_ERRNO;
goto done;
}
data = ALLOC_N(char, data_size);
nread = read(fd, data, data_size);
if (nread < 0) {
*errno_provenance = "bs_fetch:fetch_cached_data:read";
ret = -1;
ret = ERROR_WITH_ERRNO;
goto done;
}
if (nread != data_size) {
Expand All @@ -525,6 +526,10 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE *
storage_data = rb_str_new(data, data_size);

*exception_tag = bs_storage_to_output(handler, args, storage_data, output_data);
if (*output_data == uncompilable) {
ret = CACHE_UNCOMPILABLE;
goto done;
}
ret = 0;
done:
if (data != NULL) xfree(data);
Expand Down Expand Up @@ -737,7 +742,14 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
&output_data, &exception_tag, &errno_provenance
);
if (exception_tag != 0) goto raise;
else if (res == CACHE_MISS || res == CACHE_STALE) valid_cache = 0;
else if (res == CACHE_UNCOMPILABLE) {
/* If fetch_cached_data returned `Uncompilable` we fallback to `input_to_output`
This happens if we have say, an unsafe YAML cache, but try to load it in safe mode */
if (bs_read_contents(current_fd, current_key.size, &contents, &errno_provenance) < 0) goto fail_errno;
input_data = rb_str_new(contents, current_key.size);
bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
if (exception_tag != 0) goto raise;
} else if (res == CACHE_MISS || res == CACHE_STALE) valid_cache = 0;
else if (res == ERROR_WITH_ERRNO) goto fail_errno;
else if (!NIL_P(output_data)) goto succeed; /* fast-path, goal */
}
Expand Down Expand Up @@ -772,9 +784,13 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
exception_tag = bs_storage_to_output(handler, args, storage_data, &output_data);
if (exception_tag != 0) goto raise;

/* If output_data is nil, delete the cache entry and generate the output
* using input_to_output */
if (NIL_P(output_data)) {
if (output_data == uncompilable) {
/* If storage_to_output returned `Uncompilable` we fallback to `input_to_output` */
bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
if (exception_tag != 0) goto raise;
} else if (NIL_P(output_data)) {
/* If output_data is nil, delete the cache entry and generate the output
* using input_to_output */
if (unlink(cache_path) < 0) {
errno_provenance = "bs_fetch:unlink";
goto fail_errno;
Expand Down Expand Up @@ -919,12 +935,27 @@ struct i2s_data {
};

static VALUE
prot_storage_to_output(VALUE arg)
rescue_uncompilable(VALUE arg, VALUE e)
{
return uncompilable;
}

static VALUE
try_storage_to_output(VALUE arg)
{
struct s2o_data * data = (struct s2o_data *)arg;
return rb_funcall(data->handler, rb_intern("storage_to_output"), 2, data->storage_data, data->args);
}

static VALUE
prot_storage_to_output(VALUE arg)
{
return rb_rescue2(
try_storage_to_output, arg,
rescue_uncompilable, Qnil,
rb_eBootsnap_CompileCache_Uncompilable, 0);
}

static int
bs_storage_to_output(VALUE handler, VALUE args, VALUE storage_data, VALUE * output_data)
{
Expand Down Expand Up @@ -963,19 +994,13 @@ try_input_to_storage(VALUE arg)
return rb_funcall(data->handler, rb_intern("input_to_storage"), 2, data->input_data, data->pathval);
}

static VALUE
rescue_input_to_storage(VALUE arg, VALUE e)
{
return uncompilable;
}

static VALUE
prot_input_to_storage(VALUE arg)
{
struct i2s_data * data = (struct i2s_data *)arg;
return rb_rescue2(
try_input_to_storage, (VALUE)data,
rescue_input_to_storage, Qnil,
rescue_uncompilable, Qnil,
rb_eBootsnap_CompileCache_Uncompilable, 0);
}

Expand Down

0 comments on commit 89158d4

Please sign in to comment.