bootsnap 1.4.4-java → 1.4.9-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/README.md +1 -1
  4. data/ext/bootsnap/bootsnap.c +113 -65
  5. data/ext/bootsnap/extconf.rb +1 -0
  6. data/lib/bootsnap.rb +2 -0
  7. data/lib/bootsnap/bundler.rb +1 -0
  8. data/lib/bootsnap/compile_cache.rb +4 -3
  9. data/lib/bootsnap/compile_cache/iseq.rb +6 -4
  10. data/lib/bootsnap/compile_cache/yaml.rb +67 -38
  11. data/lib/bootsnap/explicit_require.rb +1 -0
  12. data/lib/bootsnap/load_path_cache.rb +1 -1
  13. data/lib/bootsnap/load_path_cache/cache.rb +8 -8
  14. data/lib/bootsnap/load_path_cache/change_observer.rb +2 -1
  15. data/lib/bootsnap/load_path_cache/core_ext/active_support.rb +1 -0
  16. data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +18 -5
  17. data/lib/bootsnap/load_path_cache/core_ext/loaded_features.rb +1 -0
  18. data/lib/bootsnap/load_path_cache/loaded_features_index.rb +33 -10
  19. data/lib/bootsnap/load_path_cache/path.rb +3 -2
  20. data/lib/bootsnap/load_path_cache/path_scanner.rb +39 -26
  21. data/lib/bootsnap/load_path_cache/realpath_cache.rb +5 -5
  22. data/lib/bootsnap/load_path_cache/store.rb +18 -14
  23. data/lib/bootsnap/setup.rb +1 -0
  24. data/lib/bootsnap/version.rb +2 -1
  25. metadata +9 -26
  26. data/.github/CODEOWNERS +0 -2
  27. data/.github/probots.yml +0 -2
  28. data/.gitignore +0 -17
  29. data/.rubocop.yml +0 -20
  30. data/.travis.yml +0 -21
  31. data/CODE_OF_CONDUCT.md +0 -74
  32. data/CONTRIBUTING.md +0 -21
  33. data/Gemfile +0 -8
  34. data/README.jp.md +0 -231
  35. data/Rakefile +0 -12
  36. data/bin/ci +0 -10
  37. data/bin/console +0 -14
  38. data/bin/setup +0 -8
  39. data/bin/test-minimal-support +0 -7
  40. data/bin/testunit +0 -8
  41. data/bootsnap.gemspec +0 -45
  42. data/dev.yml +0 -10
  43. data/shipit.rubygems.yml +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7fbe5730c11c8b3d6088b4a328a05e5cf3a364e949f3df1a68412d6e4331da9b
4
- data.tar.gz: c45de758cc5b2649b54e57f4e8b56959f2138834f75ec13588fa203c3ed58a18
3
+ metadata.gz: 4725339bc7effc3e8e78f210bb0a06302d2b2d53838def89cd329754efd38948
4
+ data.tar.gz: fe28e483feaaddcec205a692127e2537e34b655a949a287cf80ee46e1c53dddf
5
5
  SHA512:
6
- metadata.gz: 5df01b2d8caa55aaae85f8d3144d03805b2e964fb0da7178601d8771a3414001fdd914a3973d508d15d733db6fbfe27617a8d0ffe8a18f6dd6c052d872530c55
7
- data.tar.gz: 8b3d127f57624a9bd2faaf61f87573fc938b1bce59b56b65cd5fc817230b399f2d4b42002f0bd2695b04a9be1247d3c8e4d2e2faf6a49500443a246807287cdd
6
+ metadata.gz: 229316c6ce5fc9494f17bc2907b2fae6782452f9379d10a18666cb02479ac387dc818bc40f861c07ae83eb4423a8f02a0e0d841e53af78b7d326f1274e805973
7
+ data.tar.gz: f45154c1ed2efbb613a2945a13d2b5428971c34fc098cad3e6b21291846f27fc09d853f0e3b66decb3782fb4a325e48136aa96a0135fcf98840a977a14503cd8
@@ -1,3 +1,36 @@
1
+ # 1.4.9
2
+
3
+ * [Windows support](https://github.com/Shopify/bootsnap/pull/319)
4
+ * [Fix potential crash](https://github.com/Shopify/bootsnap/pull/322)
5
+
6
+ # 1.4.8
7
+
8
+ * [Prevent FallbackScan from polluting exception cause](https://github.com/Shopify/bootsnap/pull/314)
9
+
10
+ # 1.4.7
11
+
12
+ * Various performance enhancements
13
+ * Fix race condition in heavy concurrent load scenarios that would cause bootsnap to raise
14
+
15
+ # 1.4.6
16
+
17
+ * Fix bug that was erroneously considering that files containing `.` in the names were being
18
+ required if a different file with the same name was already being required
19
+
20
+ Example:
21
+
22
+ require 'foo'
23
+ require 'foo.en'
24
+
25
+ Before bootsnap was considering `foo.en` to be the same file as `foo`
26
+
27
+ * Use glibc as part of the ruby_platform cache key
28
+
29
+ # 1.4.5
30
+
31
+ * MRI 2.7 support
32
+ * Fixed concurrency bugs
33
+
1
34
  # 1.4.4
2
35
 
3
36
  * Disable ISeq cache in `bootsnap/setup` by default in Ruby 2.5
data/README.md CHANGED
@@ -214,7 +214,7 @@ Bootsnap writes a cache file containing a 64 byte header followed by the cache c
214
214
  is a cache key including several fields:
215
215
 
216
216
  * `version`, hardcoded in bootsnap. Essentially a schema version;
217
- * `os_version`, A hash of the current kernel version (on macOS, BSD) or glibc version (on Linux);
217
+ * `ruby_platform`, A hash of `RUBY_PLATFORM` (e.g. x86_64-linux-gnu) variable and glibc version (on Linux) or OS version (`uname -v` on BSD, macOS)
218
218
  * `compile_option`, which changes with `RubyVM::InstructionSequence.compile_option` does;
219
219
  * `ruby_revision`, the version of Ruby this was compiled with;
220
220
  * `size`, the size of the source file;
@@ -21,6 +21,9 @@
21
21
  #ifndef _WIN32
22
22
  #include <sys/utsname.h>
23
23
  #endif
24
+ #ifdef __GLIBC__
25
+ #include <gnu/libc-version.h>
26
+ #endif
24
27
 
25
28
  /* 1000 is an arbitrary limit; FNV64 plus some slashes brings the cap down to
26
29
  * 981 for the cache dir */
@@ -29,6 +32,8 @@
29
32
 
30
33
  #define KEY_SIZE 64
31
34
 
35
+ #define MAX_CREATE_TEMPFILE_ATTEMPT 3
36
+
32
37
  /*
33
38
  * An instance of this key is written as the first 64 bytes of each cache file.
34
39
  * The mtime and size members track whether the file contents have changed, and
@@ -86,28 +91,29 @@ static ID uncompilable;
86
91
 
87
92
  /* Functions exposed as module functions on Bootsnap::CompileCache::Native */
88
93
  static VALUE bs_compile_option_crc32_set(VALUE self, VALUE crc32_v);
89
- static VALUE bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler);
94
+ static VALUE bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler, VALUE args);
90
95
 
91
96
  /* Helpers */
92
97
  static uint64_t fnv1a_64(const char *str);
93
- static void bs_cache_path(const char * cachedir, const char * path, char ** cache_path);
98
+ static void bs_cache_path(const char * cachedir, const char * path, const char * extra, char (* cache_path)[MAX_CACHEPATH_SIZE]);
94
99
  static int bs_read_key(int fd, struct bs_cache_key * key);
95
100
  static int cache_key_equal(struct bs_cache_key * k1, struct bs_cache_key * k2);
96
- static VALUE bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler);
97
- static int open_current_file(char * path, struct bs_cache_key * key, char ** errno_provenance);
98
- static int fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, int * exception_tag, char ** errno_provenance);
101
+ static VALUE bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args);
102
+ static int open_current_file(char * path, struct bs_cache_key * key, const char ** errno_provenance);
103
+ static int fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE * output_data, int * exception_tag, const char ** errno_provenance);
104
+ static uint32_t get_ruby_revision(void);
99
105
  static uint32_t get_ruby_platform(void);
100
106
 
101
107
  /*
102
108
  * Helper functions to call ruby methods on handler object without crashing on
103
109
  * exception.
104
110
  */
105
- static int bs_storage_to_output(VALUE handler, VALUE storage_data, VALUE * output_data);
111
+ static int bs_storage_to_output(VALUE handler, VALUE args, VALUE storage_data, VALUE * output_data);
106
112
  static VALUE prot_storage_to_output(VALUE arg);
107
113
  static VALUE prot_input_to_output(VALUE arg);
108
- static void bs_input_to_output(VALUE handler, VALUE input_data, VALUE * output_data, int * exception_tag);
114
+ static void bs_input_to_output(VALUE handler, VALUE args, VALUE input_data, VALUE * output_data, int * exception_tag);
109
115
  static VALUE prot_input_to_storage(VALUE arg);
110
- static int bs_input_to_storage(VALUE handler, VALUE input_data, VALUE pathval, VALUE * storage_data);
116
+ static int bs_input_to_storage(VALUE handler, VALUE args, VALUE input_data, VALUE pathval, VALUE * storage_data);
111
117
  struct s2o_data;
112
118
  struct i2o_data;
113
119
  struct i2s_data;
@@ -136,13 +142,13 @@ Init_bootsnap(void)
136
142
  rb_mBootsnap_CompileCache_Native = rb_define_module_under(rb_mBootsnap_CompileCache, "Native");
137
143
  rb_eBootsnap_CompileCache_Uncompilable = rb_define_class_under(rb_mBootsnap_CompileCache, "Uncompilable", rb_eStandardError);
138
144
 
139
- current_ruby_revision = FIX2INT(rb_const_get(rb_cObject, rb_intern("RUBY_REVISION")));
145
+ current_ruby_revision = get_ruby_revision();
140
146
  current_ruby_platform = get_ruby_platform();
141
147
 
142
148
  uncompilable = rb_intern("__bootsnap_uncompilable__");
143
149
 
144
150
  rb_define_module_function(rb_mBootsnap_CompileCache_Native, "coverage_running?", bs_rb_coverage_running, 0);
145
- rb_define_module_function(rb_mBootsnap_CompileCache_Native, "fetch", bs_rb_fetch, 3);
151
+ rb_define_module_function(rb_mBootsnap_CompileCache_Native, "fetch", bs_rb_fetch, 4);
146
152
  rb_define_module_function(rb_mBootsnap_CompileCache_Native, "compile_option_crc32=", bs_compile_option_crc32_set, 1);
147
153
 
148
154
  current_umask = umask(0777);
@@ -196,6 +202,26 @@ fnv1a_64(const char *str)
196
202
  return fnv1a_64_iter(h, str);
197
203
  }
198
204
 
205
+ /*
206
+ * Ruby's revision may be Integer or String. CRuby 2.7 or later uses
207
+ * Git commit ID as revision. It's String.
208
+ */
209
+ static uint32_t
210
+ get_ruby_revision(void)
211
+ {
212
+ VALUE ruby_revision;
213
+
214
+ ruby_revision = rb_const_get(rb_cObject, rb_intern("RUBY_REVISION"));
215
+ if (RB_TYPE_P(ruby_revision, RUBY_T_FIXNUM)) {
216
+ return FIX2INT(ruby_revision);
217
+ } else {
218
+ uint64_t hash;
219
+
220
+ hash = fnv1a_64(StringValueCStr(ruby_revision));
221
+ return (uint32_t)(hash >> 32);
222
+ }
223
+ }
224
+
199
225
  /*
200
226
  * When ruby's version doesn't change, but it's recompiled on a different OS
201
227
  * (or OS version), we need to invalidate the cache.
@@ -215,6 +241,9 @@ get_ruby_platform(void)
215
241
 
216
242
  #ifdef _WIN32
217
243
  return (uint32_t)(hash >> 32) ^ (uint32_t)GetVersion();
244
+ #elif defined(__GLIBC__)
245
+ hash = fnv1a_64_iter(hash, gnu_get_libc_version());
246
+ return (uint32_t)(hash >> 32);
218
247
  #else
219
248
  struct utsname utsname;
220
249
 
@@ -235,9 +264,12 @@ get_ruby_platform(void)
235
264
  * The path will look something like: <cachedir>/12/34567890abcdef
236
265
  */
237
266
  static void
238
- bs_cache_path(const char * cachedir, const char * path, char ** cache_path)
267
+ bs_cache_path(const char * cachedir, const char * path, const char * extra, char (* cache_path)[MAX_CACHEPATH_SIZE])
239
268
  {
240
269
  uint64_t hash = fnv1a_64(path);
270
+ if (extra) {
271
+ hash ^= fnv1a_64(extra);
272
+ }
241
273
 
242
274
  uint8_t first_byte = (hash >> (64 - 8));
243
275
  uint64_t remainder = hash & 0x00ffffffffffffff;
@@ -272,7 +304,7 @@ cache_key_equal(struct bs_cache_key * k1, struct bs_cache_key * k2)
272
304
  * conversions on the ruby VALUE arguments before passing them along.
273
305
  */
274
306
  static VALUE
275
- bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler)
307
+ bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler, VALUE args)
276
308
  {
277
309
  FilePathValue(path_v);
278
310
 
@@ -286,13 +318,16 @@ bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler)
286
318
  char * cachedir = RSTRING_PTR(cachedir_v);
287
319
  char * path = RSTRING_PTR(path_v);
288
320
  char cache_path[MAX_CACHEPATH_SIZE];
289
-
290
- { /* generate cache path to cache_path */
291
- char * tmp = (char *)&cache_path;
292
- bs_cache_path(cachedir, path, &tmp);
321
+ char * extra = NULL;
322
+ if (!NIL_P(args)) {
323
+ VALUE args_serial = rb_marshal_dump(args, Qnil);
324
+ extra = RSTRING_PTR(args_serial);
293
325
  }
294
326
 
295
- return bs_fetch(path, path_v, cache_path, handler);
327
+ /* generate cache path to cache_path */
328
+ bs_cache_path(cachedir, path, extra, &cache_path);
329
+
330
+ return bs_fetch(path, path_v, cache_path, handler, args);
296
331
  }
297
332
 
298
333
  /*
@@ -300,14 +335,14 @@ bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler)
300
335
  * was loaded.
301
336
  */
302
337
  static int
303
- open_current_file(char * path, struct bs_cache_key * key, char ** errno_provenance)
338
+ open_current_file(char * path, struct bs_cache_key * key, const char ** errno_provenance)
304
339
  {
305
340
  struct stat statbuf;
306
341
  int fd;
307
342
 
308
343
  fd = open(path, O_RDONLY);
309
344
  if (fd < 0) {
310
- *errno_provenance = (char *)"bs_fetch:open_current_file:open";
345
+ *errno_provenance = "bs_fetch:open_current_file:open";
311
346
  return fd;
312
347
  }
313
348
  #ifdef _WIN32
@@ -315,7 +350,7 @@ open_current_file(char * path, struct bs_cache_key * key, char ** errno_provenan
315
350
  #endif
316
351
 
317
352
  if (fstat(fd, &statbuf) < 0) {
318
- *errno_provenance = (char *)"bs_fetch:open_current_file:fstat";
353
+ *errno_provenance = "bs_fetch:open_current_file:fstat";
319
354
  close(fd);
320
355
  return -1;
321
356
  }
@@ -361,13 +396,13 @@ bs_read_key(int fd, struct bs_cache_key * key)
361
396
  * - ERROR_WITH_ERRNO (-1, errno is set)
362
397
  */
363
398
  static int
364
- open_cache_file(const char * path, struct bs_cache_key * key, char ** errno_provenance)
399
+ open_cache_file(const char * path, struct bs_cache_key * key, const char ** errno_provenance)
365
400
  {
366
401
  int fd, res;
367
402
 
368
403
  fd = open(path, O_RDONLY);
369
404
  if (fd < 0) {
370
- *errno_provenance = (char *)"bs_fetch:open_cache_file:open";
405
+ *errno_provenance = "bs_fetch:open_cache_file:open";
371
406
  if (errno == ENOENT) return CACHE_MISSING_OR_INVALID;
372
407
  return ERROR_WITH_ERRNO;
373
408
  }
@@ -377,7 +412,7 @@ open_cache_file(const char * path, struct bs_cache_key * key, char ** errno_prov
377
412
 
378
413
  res = bs_read_key(fd, key);
379
414
  if (res < 0) {
380
- *errno_provenance = (char *)"bs_fetch:open_cache_file:read";
415
+ *errno_provenance = "bs_fetch:open_cache_file:read";
381
416
  close(fd);
382
417
  return res;
383
418
  }
@@ -401,7 +436,7 @@ open_cache_file(const char * path, struct bs_cache_key * key, char ** errno_prov
401
436
  * or exception, will be the final data returnable to the user.
402
437
  */
403
438
  static int
404
- fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, int * exception_tag, char ** errno_provenance)
439
+ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE * output_data, int * exception_tag, const char ** errno_provenance)
405
440
  {
406
441
  char * data = NULL;
407
442
  ssize_t nread;
@@ -410,7 +445,7 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data,
410
445
  VALUE storage_data;
411
446
 
412
447
  if (data_size > 100000000000) {
413
- *errno_provenance = (char *)"bs_fetch:fetch_cached_data:datasize";
448
+ *errno_provenance = "bs_fetch:fetch_cached_data:datasize";
414
449
  errno = EINVAL; /* because wtf? */
415
450
  ret = -1;
416
451
  goto done;
@@ -418,7 +453,7 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data,
418
453
  data = ALLOC_N(char, data_size);
419
454
  nread = read(fd, data, data_size);
420
455
  if (nread < 0) {
421
- *errno_provenance = (char *)"bs_fetch:fetch_cached_data:read";
456
+ *errno_provenance = "bs_fetch:fetch_cached_data:read";
422
457
  ret = -1;
423
458
  goto done;
424
459
  }
@@ -427,9 +462,9 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data,
427
462
  goto done;
428
463
  }
429
464
 
430
- storage_data = rb_str_new_static(data, data_size);
465
+ storage_data = rb_str_new(data, data_size);
431
466
 
432
- *exception_tag = bs_storage_to_output(handler, storage_data, output_data);
467
+ *exception_tag = bs_storage_to_output(handler, args, storage_data, output_data);
433
468
  ret = 0;
434
469
  done:
435
470
  if (data != NULL) xfree(data);
@@ -470,29 +505,36 @@ mkpath(char * file_path, mode_t mode)
470
505
  * path.
471
506
  */
472
507
  static int
473
- atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char ** errno_provenance)
508
+ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, const char ** errno_provenance)
474
509
  {
475
510
  char template[MAX_CACHEPATH_SIZE + 20];
476
511
  char * tmp_path;
477
- int fd, ret;
512
+ int fd, ret, attempt;
478
513
  ssize_t nwrite;
479
514
 
480
- tmp_path = strncpy(template, path, MAX_CACHEPATH_SIZE);
481
- strcat(tmp_path, ".tmp.XXXXXX");
515
+ for (attempt = 0; attempt < MAX_CREATE_TEMPFILE_ATTEMPT; ++attempt) {
516
+ tmp_path = strncpy(template, path, MAX_CACHEPATH_SIZE);
517
+ strcat(tmp_path, ".tmp.XXXXXX");
482
518
 
483
- // mkstemp modifies the template to be the actual created path
484
- fd = mkstemp(tmp_path);
485
- if (fd < 0) {
486
- if (mkpath(tmp_path, 0775) < 0) {
487
- *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:mkpath";
488
- return -1;
489
- }
490
- fd = open(tmp_path, O_WRONLY | O_CREAT, 0664);
491
- if (fd < 0) {
492
- *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:open";
519
+ // mkstemp modifies the template to be the actual created path
520
+ fd = mkstemp(tmp_path);
521
+ if (fd > 0) break;
522
+
523
+ if (attempt == 0 && mkpath(tmp_path, 0775) < 0) {
524
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:mkpath";
493
525
  return -1;
494
526
  }
495
527
  }
528
+ if (fd < 0) {
529
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:mkstemp";
530
+ return -1;
531
+ }
532
+
533
+ if (chmod(tmp_path, 0644) < 0) {
534
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:chmod";
535
+ return -1;
536
+ }
537
+
496
538
  #ifdef _WIN32
497
539
  setmode(fd, O_BINARY);
498
540
  #endif
@@ -500,11 +542,11 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char
500
542
  key->data_size = RSTRING_LEN(data);
501
543
  nwrite = write(fd, key, KEY_SIZE);
502
544
  if (nwrite < 0) {
503
- *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:write";
545
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:write";
504
546
  return -1;
505
547
  }
506
548
  if (nwrite != KEY_SIZE) {
507
- *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:keysize";
549
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:keysize";
508
550
  errno = EIO; /* Lies but whatever */
509
551
  return -1;
510
552
  }
@@ -512,7 +554,7 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char
512
554
  nwrite = write(fd, RSTRING_PTR(data), RSTRING_LEN(data));
513
555
  if (nwrite < 0) return -1;
514
556
  if (nwrite != RSTRING_LEN(data)) {
515
- *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:writelength";
557
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:writelength";
516
558
  errno = EIO; /* Lies but whatever */
517
559
  return -1;
518
560
  }
@@ -520,12 +562,12 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char
520
562
  close(fd);
521
563
  ret = rename(tmp_path, path);
522
564
  if (ret < 0) {
523
- *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:rename";
565
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:rename";
524
566
  return -1;
525
567
  }
526
568
  ret = chmod(path, 0664 & ~current_umask);
527
569
  if (ret < 0) {
528
- *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:chmod";
570
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:chmod";
529
571
  }
530
572
  return ret;
531
573
  }
@@ -534,13 +576,13 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char
534
576
  /* Read contents from an fd, whose contents are asserted to be +size+ bytes
535
577
  * long, into a buffer */
536
578
  static ssize_t
537
- bs_read_contents(int fd, size_t size, char ** contents, char ** errno_provenance)
579
+ bs_read_contents(int fd, size_t size, char ** contents, const char ** errno_provenance)
538
580
  {
539
581
  ssize_t nread;
540
582
  *contents = ALLOC_N(char, size);
541
583
  nread = read(fd, *contents, size);
542
584
  if (nread < 0) {
543
- *errno_provenance = (char *)"bs_fetch:bs_read_contents:read";
585
+ *errno_provenance = "bs_fetch:bs_read_contents:read";
544
586
  }
545
587
  return nread;
546
588
  }
@@ -590,13 +632,13 @@ bs_read_contents(int fd, size_t size, char ** contents, char ** errno_provenance
590
632
  * - Return storage_to_output(storage_data)
591
633
  */
592
634
  static VALUE
593
- bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler)
635
+ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args)
594
636
  {
595
637
  struct bs_cache_key cached_key, current_key;
596
638
  char * contents = NULL;
597
639
  int cache_fd = -1, current_fd = -1;
598
640
  int res, valid_cache = 0, exception_tag = 0;
599
- char * errno_provenance = NULL;
641
+ const char * errno_provenance = NULL;
600
642
 
601
643
  VALUE input_data; /* data read from source file, e.g. YAML or ruby source */
602
644
  VALUE storage_data; /* compiled data, e.g. msgpack / binary iseq */
@@ -623,7 +665,7 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler)
623
665
  if (valid_cache) {
624
666
  /* Fetch the cache data and return it if we're able to load it successfully */
625
667
  res = fetch_cached_data(
626
- cache_fd, (ssize_t)cached_key.data_size, handler,
668
+ cache_fd, (ssize_t)cached_key.data_size, handler, args,
627
669
  &output_data, &exception_tag, &errno_provenance
628
670
  );
629
671
  if (exception_tag != 0) goto raise;
@@ -637,15 +679,15 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler)
637
679
 
638
680
  /* Read the contents of the source file into a buffer */
639
681
  if (bs_read_contents(current_fd, current_key.size, &contents, &errno_provenance) < 0) goto fail_errno;
640
- input_data = rb_str_new_static(contents, current_key.size);
682
+ input_data = rb_str_new(contents, current_key.size);
641
683
 
642
684
  /* Try to compile the input_data using input_to_storage(input_data) */
643
- exception_tag = bs_input_to_storage(handler, input_data, path_v, &storage_data);
685
+ exception_tag = bs_input_to_storage(handler, args, input_data, path_v, &storage_data);
644
686
  if (exception_tag != 0) goto raise;
645
687
  /* If input_to_storage raised Bootsnap::CompileCache::Uncompilable, don't try
646
688
  * to cache anything; just return input_to_output(input_data) */
647
689
  if (storage_data == uncompilable) {
648
- bs_input_to_output(handler, input_data, &output_data, &exception_tag);
690
+ bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
649
691
  if (exception_tag != 0) goto raise;
650
692
  goto succeed;
651
693
  }
@@ -657,17 +699,17 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler)
657
699
  if (res < 0) goto fail_errno;
658
700
 
659
701
  /* Having written the cache, now convert storage_data to output_data */
660
- exception_tag = bs_storage_to_output(handler, storage_data, &output_data);
702
+ exception_tag = bs_storage_to_output(handler, args, storage_data, &output_data);
661
703
  if (exception_tag != 0) goto raise;
662
704
 
663
705
  /* If output_data is nil, delete the cache entry and generate the output
664
706
  * using input_to_output */
665
707
  if (NIL_P(output_data)) {
666
708
  if (unlink(cache_path) < 0) {
667
- errno_provenance = (char *)"bs_fetch:unlink";
709
+ errno_provenance = "bs_fetch:unlink";
668
710
  goto fail_errno;
669
711
  }
670
- bs_input_to_output(handler, input_data, &output_data, &exception_tag);
712
+ bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
671
713
  if (exception_tag != 0) goto raise;
672
714
  }
673
715
 
@@ -717,16 +759,19 @@ invalid_type_storage_data:
717
759
 
718
760
  struct s2o_data {
719
761
  VALUE handler;
762
+ VALUE args;
720
763
  VALUE storage_data;
721
764
  };
722
765
 
723
766
  struct i2o_data {
724
767
  VALUE handler;
768
+ VALUE args;
725
769
  VALUE input_data;
726
770
  };
727
771
 
728
772
  struct i2s_data {
729
773
  VALUE handler;
774
+ VALUE args;
730
775
  VALUE input_data;
731
776
  VALUE pathval;
732
777
  };
@@ -735,15 +780,16 @@ static VALUE
735
780
  prot_storage_to_output(VALUE arg)
736
781
  {
737
782
  struct s2o_data * data = (struct s2o_data *)arg;
738
- return rb_funcall(data->handler, rb_intern("storage_to_output"), 1, data->storage_data);
783
+ return rb_funcall(data->handler, rb_intern("storage_to_output"), 2, data->storage_data, data->args);
739
784
  }
740
785
 
741
786
  static int
742
- bs_storage_to_output(VALUE handler, VALUE storage_data, VALUE * output_data)
787
+ bs_storage_to_output(VALUE handler, VALUE args, VALUE storage_data, VALUE * output_data)
743
788
  {
744
789
  int state;
745
790
  struct s2o_data s2o_data = {
746
791
  .handler = handler,
792
+ .args = args,
747
793
  .storage_data = storage_data,
748
794
  };
749
795
  *output_data = rb_protect(prot_storage_to_output, (VALUE)&s2o_data, &state);
@@ -751,10 +797,11 @@ bs_storage_to_output(VALUE handler, VALUE storage_data, VALUE * output_data)
751
797
  }
752
798
 
753
799
  static void
754
- bs_input_to_output(VALUE handler, VALUE input_data, VALUE * output_data, int * exception_tag)
800
+ bs_input_to_output(VALUE handler, VALUE args, VALUE input_data, VALUE * output_data, int * exception_tag)
755
801
  {
756
802
  struct i2o_data i2o_data = {
757
803
  .handler = handler,
804
+ .args = args,
758
805
  .input_data = input_data,
759
806
  };
760
807
  *output_data = rb_protect(prot_input_to_output, (VALUE)&i2o_data, exception_tag);
@@ -764,18 +811,18 @@ static VALUE
764
811
  prot_input_to_output(VALUE arg)
765
812
  {
766
813
  struct i2o_data * data = (struct i2o_data *)arg;
767
- return rb_funcall(data->handler, rb_intern("input_to_output"), 1, data->input_data);
814
+ return rb_funcall(data->handler, rb_intern("input_to_output"), 2, data->input_data, data->args);
768
815
  }
769
816
 
770
817
  static VALUE
771
818
  try_input_to_storage(VALUE arg)
772
819
  {
773
820
  struct i2s_data * data = (struct i2s_data *)arg;
774
- return rb_funcall(data->handler, rb_intern("input_to_storage"), 2, data->input_data, data->pathval);
821
+ return rb_funcall(data->handler, rb_intern("input_to_storage"), 3, data->input_data, data->pathval, data->args);
775
822
  }
776
823
 
777
824
  static VALUE
778
- rescue_input_to_storage(VALUE arg)
825
+ rescue_input_to_storage(VALUE arg, VALUE e)
779
826
  {
780
827
  return uncompilable;
781
828
  }
@@ -791,11 +838,12 @@ prot_input_to_storage(VALUE arg)
791
838
  }
792
839
 
793
840
  static int
794
- bs_input_to_storage(VALUE handler, VALUE input_data, VALUE pathval, VALUE * storage_data)
841
+ bs_input_to_storage(VALUE handler, VALUE args, VALUE input_data, VALUE pathval, VALUE * storage_data)
795
842
  {
796
843
  int state;
797
844
  struct i2s_data i2s_data = {
798
845
  .handler = handler,
846
+ .args = args,
799
847
  .input_data = input_data,
800
848
  .pathval = pathval,
801
849
  };