29
29
#include "ruby/util.h"
30
30
#include "ruby_assert.h"
31
31
#include "vm_sync.h"
32
+ #include "ruby_atomic.h"
32
33
33
34
#ifndef ENC_DEBUG
34
35
#define ENC_DEBUG 0
@@ -144,10 +145,14 @@ enc_list_update(int index, rb_raw_encoding *encoding)
144
145
{
145
146
RUBY_ASSERT (index < ENCODING_LIST_CAPA );
146
147
147
- VALUE list = rb_encoding_list ;
148
+ VALUE list = RUBY_ATOMIC_VALUE_LOAD (rb_encoding_list );
149
+
148
150
if (list && NIL_P (rb_ary_entry (list , index ))) {
151
+ VALUE new_list = rb_ary_dup (list );
152
+ RBASIC_CLEAR_CLASS (new_list );
149
153
/* initialize encoding data */
150
- rb_ary_store (list , index , enc_new (encoding ));
154
+ rb_ary_store (new_list , index , enc_new (encoding ));
155
+ RUBY_ATOMIC_VALUE_SET (rb_encoding_list , new_list );
151
156
}
152
157
}
153
158
@@ -157,7 +162,7 @@ enc_list_lookup(int idx)
157
162
VALUE list , enc = Qnil ;
158
163
159
164
if (idx < ENCODING_LIST_CAPA ) {
160
- list = rb_encoding_list ;
165
+ list = RUBY_ATOMIC_VALUE_LOAD ( rb_encoding_list ) ;
161
166
RUBY_ASSERT (list );
162
167
enc = rb_ary_entry (list , idx );
163
168
}
@@ -258,6 +263,7 @@ must_encindex(int index)
258
263
int
259
264
rb_to_encoding_index (VALUE enc )
260
265
{
266
+ ASSERT_vm_unlocking (); // can load encoding, so must not hold VM lock
261
267
int idx ;
262
268
const char * name ;
263
269
@@ -667,15 +673,15 @@ int
667
673
rb_enc_alias (const char * alias , const char * orig )
668
674
{
669
675
int idx , r ;
676
+ GLOBAL_ENC_TABLE_LOCKING (enc_table ) {
677
+ enc_check_addable (enc_table , alias ); // can raise
678
+ }
679
+
680
+ idx = rb_enc_find_index (orig );
681
+ if (idx < 0 ) return -1 ;
670
682
671
683
GLOBAL_ENC_TABLE_LOCKING (enc_table ) {
672
- enc_check_addable (enc_table , alias );
673
- if ((idx = rb_enc_find_index (orig )) < 0 ) {
674
- r = -1 ;
675
- }
676
- else {
677
- r = enc_alias (enc_table , alias , idx );
678
- }
684
+ r = enc_alias (enc_table , alias , idx );
679
685
}
680
686
681
687
return r ;
@@ -742,6 +748,7 @@ int rb_require_internal_silent(VALUE fname);
742
748
static int
743
749
load_encoding (const char * name )
744
750
{
751
+ ASSERT_vm_unlocking ();
745
752
VALUE enclib = rb_sprintf ("enc/%s.so" , name );
746
753
VALUE debug = ruby_debug ;
747
754
VALUE errinfo ;
@@ -757,7 +764,7 @@ load_encoding(const char *name)
757
764
enclib = rb_fstring (enclib );
758
765
ruby_debug = Qfalse ;
759
766
errinfo = rb_errinfo ();
760
- loaded = rb_require_internal_silent (enclib );
767
+ loaded = rb_require_internal_silent (enclib ); // must run without VM_LOCK
761
768
ruby_debug = debug ;
762
769
rb_set_errinfo (errinfo );
763
770
@@ -781,6 +788,7 @@ enc_autoload_body(rb_encoding *enc)
781
788
{
782
789
rb_encoding * base ;
783
790
int i = 0 ;
791
+ ASSERT_vm_unlocking ();
784
792
785
793
GLOBAL_ENC_TABLE_LOCKING (enc_table ) {
786
794
base = enc_table -> list [ENC_TO_ENCINDEX (enc )].base ;
@@ -792,30 +800,32 @@ enc_autoload_body(rb_encoding *enc)
792
800
}
793
801
} while (enc_table -> list [i ].enc != base && (++ i , 1 ));
794
802
}
803
+ }
804
+
795
805
796
- if (i != -1 ) {
797
- if (base ) {
798
- bool do_register = true;
799
- if (rb_enc_autoload_p (base )) {
800
- if (rb_enc_autoload (base ) < 0 ) {
801
- do_register = false;
802
- i = -1 ;
803
- }
806
+ if (i != -1 ) {
807
+ if (base ) {
808
+ bool do_register = true;
809
+ if (rb_enc_autoload_p (base )) {
810
+ if (rb_enc_autoload (base ) < 0 ) {
811
+ do_register = false;
812
+ i = -1 ;
804
813
}
814
+ }
805
815
806
- i = enc -> ruby_encoding_index ;
807
- if (do_register ) {
816
+ if (do_register ) {
817
+ GLOBAL_ENC_TABLE_LOCKING (enc_table ) {
818
+ i = enc -> ruby_encoding_index ;
808
819
enc_register_at (enc_table , i & ENC_INDEX_MASK , rb_enc_name (enc ), base );
809
820
((rb_raw_encoding * )enc )-> ruby_encoding_index = i ;
810
821
}
811
-
812
- i &= ENC_INDEX_MASK ;
813
- }
814
- else {
815
- i = -2 ;
816
822
}
817
- }
818
823
824
+ i &= ENC_INDEX_MASK ;
825
+ }
826
+ else {
827
+ i = -2 ;
828
+ }
819
829
}
820
830
821
831
return i ;
@@ -824,6 +834,7 @@ enc_autoload_body(rb_encoding *enc)
824
834
int
825
835
rb_enc_autoload (rb_encoding * enc )
826
836
{
837
+ ASSERT_vm_unlocking ();
827
838
int i = enc_autoload_body (enc );
828
839
if (i == -2 ) {
829
840
i = load_encoding (rb_enc_name (enc ));
844
855
rb_enc_find_index (const char * name )
845
856
{
846
857
int i ;
858
+ ASSERT_vm_unlocking (); // it needs to be unlocked so it can call `load_encoding` if necessary
847
859
GLOBAL_ENC_TABLE_LOCKING (enc_table ) {
848
860
i = enc_registered (enc_table , name );
849
861
}
@@ -1019,7 +1031,6 @@ rb_enc_associate_index(VALUE obj, int idx)
1019
1031
rb_encoding * enc ;
1020
1032
int oldidx , oldtermlen , termlen ;
1021
1033
1022
- /* enc_check_capable(obj);*/
1023
1034
rb_check_frozen (obj );
1024
1035
oldidx = rb_enc_get_index (obj );
1025
1036
if (oldidx == idx )
@@ -1355,7 +1366,10 @@ enc_names(VALUE self)
1355
1366
1356
1367
args [0 ] = (VALUE )rb_to_encoding_index (self );
1357
1368
args [1 ] = rb_ary_new2 (0 );
1358
- st_foreach (global_enc_table .names , enc_names_i , (st_data_t )args );
1369
+
1370
+ GLOBAL_ENC_TABLE_LOCKING (enc_table ) {
1371
+ st_foreach (enc_table -> names , enc_names_i , (st_data_t )args );
1372
+ }
1359
1373
return args [1 ];
1360
1374
}
1361
1375
@@ -1380,8 +1394,9 @@ enc_names(VALUE self)
1380
1394
static VALUE
1381
1395
enc_list (VALUE klass )
1382
1396
{
1383
- VALUE ary = rb_ary_new2 (0 );
1384
- rb_ary_replace (ary , rb_encoding_list );
1397
+ VALUE ary = rb_ary_new2 (ENCODING_LIST_CAPA );
1398
+ VALUE list = RUBY_ATOMIC_VALUE_LOAD (rb_encoding_list );
1399
+ rb_ary_replace (ary , list );
1385
1400
return ary ;
1386
1401
}
1387
1402
@@ -1526,6 +1541,9 @@ int rb_locale_charmap_index(void);
1526
1541
int
1527
1542
rb_locale_encindex (void )
1528
1543
{
1544
+ // `rb_locale_charmap_index` can call `enc_find_index`, which can
1545
+ // load an encoding. This needs to be done without VM lock held.
1546
+ ASSERT_vm_unlocking ();
1529
1547
int idx = rb_locale_charmap_index ();
1530
1548
1531
1549
if (idx < 0 ) idx = ENCINDEX_UTF_8 ;
@@ -1584,6 +1602,10 @@ enc_set_default_encoding(struct default_encoding *def, VALUE encoding, const cha
1584
1602
/* Already set */
1585
1603
overridden = TRUE;
1586
1604
1605
+ if (!NIL_P (encoding )) {
1606
+ enc_check_encoding (encoding ); // loads it if necessary. Needs to be done outside of VM lock.
1607
+ }
1608
+
1587
1609
GLOBAL_ENC_TABLE_LOCKING (enc_table ) {
1588
1610
if (NIL_P (encoding )) {
1589
1611
def -> index = -1 ;
@@ -1854,8 +1876,11 @@ rb_enc_name_list_i(st_data_t name, st_data_t idx, st_data_t arg)
1854
1876
static VALUE
1855
1877
rb_enc_name_list (VALUE klass )
1856
1878
{
1857
- VALUE ary = rb_ary_new2 (global_enc_table .names -> num_entries );
1858
- st_foreach (global_enc_table .names , rb_enc_name_list_i , (st_data_t )ary );
1879
+ VALUE ary ;
1880
+ GLOBAL_ENC_TABLE_LOCKING (enc_table ) {
1881
+ ary = rb_ary_new2 (enc_table -> names -> num_entries );
1882
+ st_foreach (enc_table -> names , rb_enc_name_list_i , (st_data_t )ary );
1883
+ }
1859
1884
return ary ;
1860
1885
}
1861
1886
@@ -1901,7 +1926,9 @@ rb_enc_aliases(VALUE klass)
1901
1926
aliases [0 ] = rb_hash_new ();
1902
1927
aliases [1 ] = rb_ary_new ();
1903
1928
1904
- st_foreach (global_enc_table .names , rb_enc_aliases_enc_i , (st_data_t )aliases );
1929
+ GLOBAL_ENC_TABLE_LOCKING (enc_table ) {
1930
+ st_foreach (enc_table -> names , rb_enc_aliases_enc_i , (st_data_t )aliases );
1931
+ }
1905
1932
1906
1933
return aliases [0 ];
1907
1934
}
@@ -1969,9 +1996,9 @@ Init_Encoding(void)
1969
1996
1970
1997
struct enc_table * enc_table = & global_enc_table ;
1971
1998
1999
+ rb_gc_register_address (& rb_encoding_list );
1972
2000
list = rb_encoding_list = rb_ary_new2 (ENCODING_LIST_CAPA );
1973
2001
RBASIC_CLEAR_CLASS (list );
1974
- rb_vm_register_global_object (list );
1975
2002
1976
2003
for (i = 0 ; i < enc_table -> count ; ++ i ) {
1977
2004
rb_ary_push (list , enc_new (enc_table -> list [i ].enc ));
@@ -2003,5 +2030,7 @@ Init_encodings(void)
2003
2030
void
2004
2031
rb_enc_foreach_name (int (* func )(st_data_t name , st_data_t idx , st_data_t arg ), st_data_t arg )
2005
2032
{
2006
- st_foreach (global_enc_table .names , func , arg );
2033
+ GLOBAL_ENC_TABLE_LOCKING (enc_table ) {
2034
+ st_foreach (enc_table -> names , func , arg );
2035
+ }
2007
2036
}
0 commit comments