rmagick 7.1.0 → 7.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c56286daf220fd8db82fce268ce2116705e192b643641cc88b4d7e53b6a46d1a
4
- data.tar.gz: 1a060762de65e6bf6a384a7f10c3036f85d6876ec89c1be54fede6ea4f20e604
3
+ metadata.gz: 5ee430e845ae8794dc88e1af56d944fe511321c91eaabdda600810127f522c5e
4
+ data.tar.gz: b8705aec273d52d277bf4f73caeb00c78befdf803426eb14fedc3ddf0028399a
5
5
  SHA512:
6
- metadata.gz: c7ebbec352d94fdeb8873353c8c13a8d3432b2f89c26c05a8520ee56353c1daedde3717429ad6ec1b9c66a9d9ca71eb51c498833ea0e7419fb572f38642d4fcd
7
- data.tar.gz: c7a7941f288dd513f5ab88d009011c07575fc07e95c772fd3950db9d8828738c7ab49e6fa3484a4ead018ecbe0a002b260f4e0c670c70647aac11419465f09a5
6
+ metadata.gz: 48bc5436488b2b05f990e645ab294674b6d176dc584010686098b03b51cae5d67564b47d3ad5532a9001026027c1fb316f6b9b07fd7284c1825b82c5d084c365
7
+ data.tar.gz: 1a389dc68b01846feb575c5dcc3b42988baf99bfef0c03e7231db3d013973e1a74440dac99980295baa72efe5e1d01733a236854b43b6770aa461d7a6ed7e2e0
data/CHANGELOG.md CHANGED
@@ -3,6 +3,12 @@
3
3
  All notable changes to this project are documented in this file.
4
4
  This project adheres to [Semantic Versioning](http://semver.org/).
5
5
 
6
+ ## RMagick 7.1.1
7
+
8
+ Bug Fixes
9
+
10
+ * Fix Strings being recycled while the C pointers into them are in use (#1847)
11
+
6
12
  ## RMagick 7.1.0
7
13
 
8
14
  > [!IMPORTANT]
@@ -1163,8 +1163,8 @@ extern void rm_check_ary_len(VALUE, long);
1163
1163
  extern VALUE rm_check_ary_type(VALUE ary);
1164
1164
  extern Image *rm_check_destroyed(VALUE);
1165
1165
  extern Image *rm_check_frozen(VALUE);
1166
- extern char *rm_str2cstr(VALUE, size_t *);
1167
- extern char *rm_path2cstr(VALUE, size_t *);
1166
+ extern char *rm_str2cstr(VALUE *, size_t *);
1167
+ extern char *rm_path2cstr(VALUE *, size_t *);
1168
1168
  extern int rm_check_num2dbl(VALUE);
1169
1169
  extern double rm_fuzz_to_dbl(VALUE);
1170
1170
  extern Quantum rm_app2quantum(VALUE);
@@ -511,6 +511,8 @@ Image *str_to_image(VALUE str)
511
511
  DestroyExceptionInfo(exception);
512
512
  }
513
513
 
514
+ RB_GC_GUARD(str);
515
+
514
516
  return image;
515
517
  }
516
518
 
@@ -1617,6 +1619,7 @@ get_type_metrics(int argc, VALUE *argv, VALUE self, gvl_function_t fp)
1617
1619
  Image *image;
1618
1620
  Draw *draw;
1619
1621
  VALUE t;
1622
+ VALUE text_arg = Qnil;
1620
1623
  TypeMetric metrics;
1621
1624
  char *text = NULL;
1622
1625
  size_t text_l;
@@ -1628,13 +1631,15 @@ get_type_metrics(int argc, VALUE *argv, VALUE self, gvl_function_t fp)
1628
1631
  switch (argc)
1629
1632
  {
1630
1633
  case 1: // use default image
1631
- text = rm_str2cstr(argv[0], &text_l);
1634
+ text_arg = argv[0];
1635
+ text = rm_str2cstr(&text_arg, &text_l);
1632
1636
  TypedData_Get_Struct(get_dummy_tm_img(CLASS_OF(self)), Image, &rm_image_data_type, image);
1633
1637
  break;
1634
1638
  case 2:
1635
1639
  t = rm_cur_image(argv[0]);
1636
1640
  image = rm_check_destroyed(t);
1637
- text = rm_str2cstr(argv[1], &text_l);
1641
+ text_arg = argv[1];
1642
+ text = rm_str2cstr(&text_arg, &text_l);
1638
1643
  break; // okay
1639
1644
  default:
1640
1645
  rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)", argc);
@@ -1680,6 +1685,7 @@ get_type_metrics(int argc, VALUE *argv, VALUE self, gvl_function_t fp)
1680
1685
  #endif
1681
1686
 
1682
1687
  RB_GC_GUARD(t);
1688
+ RB_GC_GUARD(text_arg);
1683
1689
 
1684
1690
  return Import_TypeMetric(&metrics);
1685
1691
  }
@@ -2925,7 +2925,7 @@ set_profile(VALUE self, const char *name, VALUE profile)
2925
2925
 
2926
2926
  image = rm_check_frozen(self);
2927
2927
 
2928
- profile_blob = rm_str2cstr(profile, &profile_length);
2928
+ profile_blob = rm_str2cstr(&profile, &profile_length);
2929
2929
 
2930
2930
  exception = AcquireExceptionInfo();
2931
2931
  m = GetMagickInfo(name, exception);
@@ -3002,6 +3002,8 @@ set_profile(VALUE self, const char *name, VALUE profile)
3002
3002
  rm_check_image_exception(image, RetainOnError);
3003
3003
  #endif
3004
3004
 
3005
+ RB_GC_GUARD(profile);
3006
+
3005
3007
  return self;
3006
3008
  }
3007
3009
 
@@ -4372,7 +4374,7 @@ Image_constitute(VALUE klass ATTRIBUTE_UNUSED, VALUE width_arg, VALUE height_arg
4372
4374
 
4373
4375
  width = NUM2LONG(width_arg);
4374
4376
  height = NUM2LONG(height_arg);
4375
- map = rm_str2cstr(map_arg, &map_l);
4377
+ map = rm_str2cstr(&map_arg, &map_l);
4376
4378
 
4377
4379
  npixels = width * height * map_l;
4378
4380
  if (RARRAY_LEN(pixels_arg) != npixels)
@@ -4495,6 +4497,7 @@ Image_constitute(VALUE klass ATTRIBUTE_UNUSED, VALUE width_arg, VALUE height_arg
4495
4497
  RB_GC_GUARD(pixel);
4496
4498
  RB_GC_GUARD(pixel0);
4497
4499
  RB_GC_GUARD(pixel_class);
4500
+ RB_GC_GUARD(map_arg);
4498
4501
 
4499
4502
  return rm_image_new(new_image);
4500
4503
  }
@@ -5252,6 +5255,8 @@ Image_decipher(VALUE self, VALUE passphrase)
5252
5255
 
5253
5256
  DestroyExceptionInfo(exception);
5254
5257
 
5258
+ RB_GC_GUARD(passphrase);
5259
+
5255
5260
  return rm_image_new(new_image);
5256
5261
  }
5257
5262
 
@@ -5753,7 +5758,7 @@ Image_dispatch(int argc, VALUE *argv, VALUE self)
5753
5758
  y = NUM2LONG(argv[1]);
5754
5759
  columns = NUM2ULONG(argv[2]);
5755
5760
  rows = NUM2ULONG(argv[3]);
5756
- map = rm_str2cstr(argv[4], &mapL);
5761
+ map = rm_str2cstr(&argv[4], &mapL);
5757
5762
  if (argc == 6)
5758
5763
  {
5759
5764
  stg_type = RTEST(argv[5]) ? DoublePixel : QuantumPixel;
@@ -5803,6 +5808,7 @@ Image_dispatch(int argc, VALUE *argv, VALUE self)
5803
5808
  xfree((void *)pixels.v);
5804
5809
 
5805
5810
  RB_GC_GUARD(pixels_ary);
5811
+ RB_GC_GUARD(argv[4]);
5806
5812
 
5807
5813
  return pixels_ary;
5808
5814
  }
@@ -6381,6 +6387,8 @@ Image_encipher(VALUE self, VALUE passphrase)
6381
6387
 
6382
6388
  DestroyExceptionInfo(exception);
6383
6389
 
6390
+ RB_GC_GUARD(passphrase);
6391
+
6384
6392
  return rm_image_new(new_image);
6385
6393
  }
6386
6394
 
@@ -7350,7 +7358,7 @@ Image_from_blob(VALUE klass ATTRIBUTE_UNUSED, VALUE blob_arg)
7350
7358
  void *blob;
7351
7359
  size_t length;
7352
7360
 
7353
- blob = (void *) rm_str2cstr(blob_arg, &length);
7361
+ blob = (void *) rm_str2cstr(&blob_arg, &length);
7354
7362
 
7355
7363
  // Get a new Info object - run the parm block if supplied
7356
7364
  info_obj = rm_info_new();
@@ -7368,6 +7376,7 @@ Image_from_blob(VALUE klass ATTRIBUTE_UNUSED, VALUE blob_arg)
7368
7376
  rm_sync_image_options(images, info);
7369
7377
 
7370
7378
  RB_GC_GUARD(info_obj);
7379
+ RB_GC_GUARD(blob_arg);
7371
7380
 
7372
7381
  return array_from_images(images);
7373
7382
  }
@@ -8155,7 +8164,7 @@ Image_import_pixels(int argc, VALUE *argv, VALUE self)
8155
8164
  // binary pixel data.
8156
8165
  if (rb_respond_to(pixel_arg, rb_intern("to_str")))
8157
8166
  {
8158
- buffer = (void *)rm_str2cstr(pixel_arg, &buffer_l);
8167
+ buffer = (void *)rm_str2cstr(&pixel_arg, &buffer_l);
8159
8168
  switch (stg_type)
8160
8169
  {
8161
8170
  case CharPixel:
@@ -8956,7 +8965,7 @@ Image__load(VALUE klass ATTRIBUTE_UNUSED, VALUE str)
8956
8965
  char *blob;
8957
8966
  size_t length;
8958
8967
 
8959
- blob = rm_str2cstr(str, &length);
8968
+ blob = rm_str2cstr(&str, &length);
8960
8969
 
8961
8970
  // Must be at least as big as the 1st 4 fields in DumpedImage
8962
8971
  if (length <= (long)(sizeof(DumpedImage)-MaxTextExtent))
@@ -9006,6 +9015,8 @@ Image__load(VALUE klass ATTRIBUTE_UNUSED, VALUE str)
9006
9015
  rm_check_exception(exception, image, DestroyOnError);
9007
9016
  DestroyExceptionInfo(exception);
9008
9017
 
9018
+ RB_GC_GUARD(str);
9019
+
9009
9020
  return rm_image_new(image);
9010
9021
  }
9011
9022
 
@@ -9169,6 +9180,9 @@ Image_marshal_load(VALUE self, VALUE ary)
9169
9180
  UPDATE_DATA_PTR(self, new_image);
9170
9181
  rm_image_destroy(image);
9171
9182
 
9183
+ RB_GC_GUARD(filename);
9184
+ RB_GC_GUARD(blob);
9185
+
9172
9186
  return self;
9173
9187
  }
9174
9188
 
@@ -11624,7 +11638,7 @@ rd_image(VALUE klass ATTRIBUTE_UNUSED, VALUE file, gvl_function_t fp)
11624
11638
  // Convert arg to string. If an exception occurs raise an error condition.
11625
11639
  file = rb_rescue(RESCUE_FUNC(rb_String), file, RESCUE_EXCEPTION_HANDLER_FUNC(file_arg_rescue), file);
11626
11640
 
11627
- filename = rm_path2cstr(file, &filename_l);
11641
+ filename = rm_path2cstr(&file, &filename_l);
11628
11642
  filename_l = min(filename_l, MaxTextExtent-1);
11629
11643
  if (filename_l == 0)
11630
11644
  {
@@ -11771,7 +11785,7 @@ Image_read_inline(VALUE self ATTRIBUTE_UNUSED, VALUE content)
11771
11785
  size_t blob_l;
11772
11786
  ExceptionInfo *exception;
11773
11787
 
11774
- image_data = rm_str2cstr(content, &image_data_l);
11788
+ image_data = rm_str2cstr(&content, &image_data_l);
11775
11789
 
11776
11790
  // Search for a comma. If found, we'll set the start of the
11777
11791
  // image data just following the comma. Otherwise we'll assume
@@ -11813,6 +11827,7 @@ Image_read_inline(VALUE self ATTRIBUTE_UNUSED, VALUE content)
11813
11827
  rm_sync_image_options(images, info);
11814
11828
 
11815
11829
  RB_GC_GUARD(info_obj);
11830
+ RB_GC_GUARD(content);
11816
11831
 
11817
11832
  return array_from_images(images);
11818
11833
  }
@@ -12350,7 +12365,7 @@ rotate(int bang, int argc, VALUE *argv, VALUE self)
12350
12365
  switch (argc)
12351
12366
  {
12352
12367
  case 2:
12353
- arrow = rm_str2cstr(argv[1], &arrow_l);
12368
+ arrow = rm_str2cstr(&argv[1], &arrow_l);
12354
12369
  if (arrow_l != 1 || (*arrow != '<' && *arrow != '>'))
12355
12370
  {
12356
12371
  rb_raise(rb_eArgError, "second argument must be '<' or '>', '%s' given", arrow);
@@ -15913,7 +15928,7 @@ void add_format_prefix(Info *info, VALUE file)
15913
15928
  }
15914
15929
  file = rb_rescue(RESCUE_FUNC(rb_String), file, RESCUE_EXCEPTION_HANDLER_FUNC(file_arg_rescue), file);
15915
15930
 
15916
- filename = rm_path2cstr(file, &filename_l);
15931
+ filename = rm_path2cstr(&file, &filename_l);
15917
15932
 
15918
15933
  if (*info->magick == '\0')
15919
15934
  {
@@ -269,8 +269,8 @@ Info_aref(int argc, VALUE *argv, VALUE self)
269
269
  switch (argc)
270
270
  {
271
271
  case 2:
272
- format_p = rm_str2cstr(argv[0], &format_l);
273
- key_p = rm_str2cstr(argv[1], &key_l);
272
+ format_p = rm_str2cstr(&argv[0], &format_l);
273
+ key_p = rm_str2cstr(&argv[1], &key_l);
274
274
  if (format_l > MAX_FORMAT_LEN || format_l + key_l > MaxTextExtent-1)
275
275
  {
276
276
  rb_raise(rb_eArgError, "can't reference %.60s:%.1024s - too long", format_p, key_p);
@@ -333,8 +333,8 @@ Info_aset(int argc, VALUE *argv, VALUE self)
333
333
  switch (argc)
334
334
  {
335
335
  case 3:
336
- format_p = rm_str2cstr(argv[0], &format_l);
337
- key_p = rm_str2cstr(argv[1], &key_l);
336
+ format_p = rm_str2cstr(&argv[0], &format_l);
337
+ key_p = rm_str2cstr(&argv[1], &key_l);
338
338
 
339
339
  if (format_l > MAX_FORMAT_LEN || format_l+key_l > MaxTextExtent-1)
340
340
  {
@@ -707,8 +707,8 @@ Info_define(int argc, VALUE *argv, VALUE self)
707
707
  fmt_arg = rb_String(argv[2]);
708
708
  value = (const char *)StringValueCStr(fmt_arg);
709
709
  case 2:
710
- key = rm_str2cstr(argv[1], &key_l);
711
- format = rm_str2cstr(argv[0], &format_l);
710
+ key = rm_str2cstr(&argv[1], &key_l);
711
+ format = rm_str2cstr(&argv[0], &format_l);
712
712
  break;
713
713
  default:
714
714
  rb_raise(rb_eArgError, "wrong number of arguments (%d for 2 or 3)", argc);
@@ -1850,7 +1850,7 @@ Info_sampling_factor_eq(VALUE self, VALUE sampling_factor)
1850
1850
 
1851
1851
  if (!NIL_P(sampling_factor))
1852
1852
  {
1853
- sampling_factor_p = rm_str2cstr(sampling_factor, &sampling_factor_len);
1853
+ sampling_factor_p = rm_str2cstr(&sampling_factor, &sampling_factor_len);
1854
1854
  }
1855
1855
 
1856
1856
  if (info->sampling_factor)
@@ -2187,8 +2187,8 @@ Info_undefine(VALUE self, VALUE format, VALUE key)
2187
2187
  size_t format_l, key_l;
2188
2188
  char fkey[MaxTextExtent];
2189
2189
 
2190
- format_p = rm_str2cstr(format, &format_l);
2191
- key_p = rm_str2cstr(key, &key_l);
2190
+ format_p = rm_str2cstr(&format, &format_l);
2191
+ key_p = rm_str2cstr(&key, &key_l);
2192
2192
 
2193
2193
  if (format_l > MAX_FORMAT_LEN || format_l + key_l > MaxTextExtent)
2194
2194
  {
@@ -188,8 +188,13 @@ KernelInfo_scale(VALUE self, VALUE scale, VALUE flags)
188
188
  VALUE
189
189
  KernelInfo_scale_geometry(VALUE self, VALUE geometry)
190
190
  {
191
- GVL_STRUCT_TYPE(ScaleGeometryKernelInfo) args = { get_kernel_info(self), StringValueCStr(geometry) };
191
+ char *geom = StringValueCStr(geometry);
192
+
193
+ GVL_STRUCT_TYPE(ScaleGeometryKernelInfo) args = { get_kernel_info(self), geom };
192
194
  CALL_FUNC_WITHOUT_GVL(GVL_FUNC(ScaleGeometryKernelInfo), &args);
195
+
196
+ RB_GC_GUARD(geometry);
197
+
193
198
  return Qnil;
194
199
  }
195
200
 
@@ -320,21 +320,34 @@ rm_no_freeze(VALUE obj)
320
320
  /**
321
321
  * Supply our own version of the "obsolete" rb_str2cstr.
322
322
  *
323
+ * The argument is taken by reference because StringValue may replace it. When
324
+ * the argument is not a String but responds to #to_str, StringValue converts
325
+ * it and the String it produces is referenced by nothing but the variable it
326
+ * is stored in. Writing that String back into the caller's variable is what
327
+ * keeps it - and therefore the buffer the returned pointer addresses - alive
328
+ * for as long as the caller can see it. Taking the argument by value would
329
+ * leave the String unreferenced the moment this function returns, and the GC
330
+ * would be free to recycle it out from under the pointer.
331
+ *
332
+ * Callers must still RB_GC_GUARD the variable after their last use of the
333
+ * pointer whenever the GC can run in between - that is, whenever they release
334
+ * the GVL or call into Ruby.
335
+ *
323
336
  * No Ruby usage (internal function)
324
337
  *
325
- * @param str the Ruby string
338
+ * @param str pointer to the Ruby string, updated in place if it is converted
326
339
  * @param len pointer to a size_t in which to store the number of characters
327
340
  * @return a C string version of str
328
341
  */
329
342
  char *
330
- rm_str2cstr(VALUE str, size_t *len)
343
+ rm_str2cstr(VALUE *str, size_t *len)
331
344
  {
332
- StringValue(str);
345
+ StringValue(*str);
333
346
  if (len)
334
347
  {
335
- *len = (size_t)RSTRING_LEN(str);
348
+ *len = (size_t)RSTRING_LEN(*str);
336
349
  }
337
- return RSTRING_PTR(str);
350
+ return RSTRING_PTR(*str);
338
351
  }
339
352
 
340
353
 
@@ -350,19 +363,20 @@ rm_str2cstr(VALUE str, size_t *len)
350
363
  *
351
364
  * No Ruby usage (internal function)
352
365
  *
353
- * @param str the Ruby string
366
+ * @param str pointer to the Ruby string, updated in place if it is converted
354
367
  * @param len pointer to a size_t in which to store the number of characters
355
368
  * @return a C string version of str
356
369
  * @throw ArgumentError if str contains a NUL byte
370
+ * @see rm_str2cstr for why the argument is taken by reference
357
371
  */
358
372
  char *
359
- rm_path2cstr(VALUE str, size_t *len)
373
+ rm_path2cstr(VALUE *str, size_t *len)
360
374
  {
361
- char *path = StringValueCStr(str);
375
+ char *path = StringValueCStr(*str);
362
376
 
363
377
  if (len)
364
378
  {
365
- *len = (size_t)RSTRING_LEN(str);
379
+ *len = (size_t)RSTRING_LEN(*str);
366
380
  }
367
381
  return path;
368
382
  }
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Magick
4
- VERSION = '7.1.0'
4
+ VERSION = '7.1.1'
5
5
  MIN_RUBY_VERSION = '3.2.0'
6
6
  MIN_IM6_VERSION = '6.9.0'
7
7
  MIN_IM7_VERSION = '7.1.0'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rmagick
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.1.0
4
+ version: 7.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Hunter