bootsnap 1.4.4 → 1.4.9.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -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 +11 -29
  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: db7809e0e5fa0f4a018dd7254cb99619ada5c7c26947db858d9b56f29dc76249
4
- data.tar.gz: 1d9d8eed648ce29ea43307d246089a9ea116c6148681a9c43393d458c77049dd
3
+ metadata.gz: 63428d06eb0e8716ec1536736f8470e040811d59dbb111498961395c748d5290
4
+ data.tar.gz: 757c007d11519164e8b47e35ae9c42f65209191062d0a420f288c130ac52b349
5
5
  SHA512:
6
- metadata.gz: fc0befd695ab9ef47a405fea7e83b856a422f70f8f59bd2737067b4951dc20c85210d562d332e5161a3dd7816258b14295e1a91a7e2ec62a8d8dc0e5bc0fb3bf
7
- data.tar.gz: 7a408b74a5e57dc0feaf2fdfd47930a4f22f048888f0643b316e3a139fc35eaeec358599a8846dde45395db55e8f66d398704de651ba67f4cd0bdfc7d9190469
6
+ metadata.gz: 77ace9ac04ca94e5eca439bf64e0ace07b93349ba5f71c14a3d753ca3b131a6c8f0e1422ad70c9c2872e60698bcfda5343ae895bbdb01538036a185eb5d57752
7
+ data.tar.gz: c18a585ba2fc19dc3f12844efba09ec20198736c00a9c08c7b3c7a9cb8c266445f9c03e3cb38f3785ecdee52e6f2eb1dc4947d46b6b98082d38fe7f0dac3098d
@@ -1,3 +1,31 @@
1
+ # 1.4.8
2
+
3
+ * [Prevent FallbackScan from polluting exception cause](https://github.com/Shopify/bootsnap/pull/314)
4
+
5
+ # 1.4.7
6
+
7
+ * Various performance enhancements
8
+ * Fix race condition in heavy concurrent load scenarios that would cause bootsnap to raise
9
+
10
+ # 1.4.6
11
+
12
+ * Fix bug that was erroneously considering that files containing `.` in the names were being
13
+ required if a different file with the same name was already being required
14
+
15
+ Example:
16
+
17
+ require 'foo'
18
+ require 'foo.en'
19
+
20
+ Before bootsnap was considering `foo.en` to be the same file as `foo`
21
+
22
+ * Use glibc as part of the ruby_platform cache key
23
+
24
+ # 1.4.5
25
+
26
+ * MRI 2.7 support
27
+ * Fixed concurrency bugs
28
+
1
29
  # 1.4.4
2
30
 
3
31
  * 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
  };