summaryrefslogtreecommitdiff
path: root/ext/-test-/string
diff options
context:
space:
mode:
Diffstat (limited to 'ext/-test-/string')
-rw-r--r--ext/-test-/string/capacity.c17
-rw-r--r--ext/-test-/string/coderange.c47
-rw-r--r--ext/-test-/string/cstr.c146
-rw-r--r--ext/-test-/string/depend198
-rw-r--r--ext/-test-/string/ellipsize.c13
-rw-r--r--ext/-test-/string/enc_associate.c22
-rw-r--r--ext/-test-/string/enc_str_buf_cat.c14
-rw-r--r--ext/-test-/string/extconf.rb3
-rw-r--r--ext/-test-/string/fstring.c15
-rw-r--r--ext/-test-/string/init.c11
-rw-r--r--ext/-test-/string/modify.c22
-rw-r--r--ext/-test-/string/new.c21
-rw-r--r--ext/-test-/string/nofree.c13
-rw-r--r--ext/-test-/string/normalize.c17
-rw-r--r--ext/-test-/string/qsort.c61
-rw-r--r--ext/-test-/string/rb_str_dup.c35
-rw-r--r--ext/-test-/string/set_len.c14
17 files changed, 669 insertions, 0 deletions
diff --git a/ext/-test-/string/capacity.c b/ext/-test-/string/capacity.c
new file mode 100644
index 0000000000..f5277bf4e6
--- /dev/null
+++ b/ext/-test-/string/capacity.c
@@ -0,0 +1,17 @@
+#include "ruby.h"
+#include "internal.h"
+
+static VALUE
+bug_str_capacity(VALUE klass, VALUE str)
+{
+ return
+ STR_EMBED_P(str) ? INT2FIX(RSTRING_EMBED_LEN_MAX) : \
+ STR_SHARED_P(str) ? INT2FIX(0) : \
+ LONG2FIX(RSTRING(str)->as.heap.aux.capa);
+}
+
+void
+Init_string_capacity(VALUE klass)
+{
+ rb_define_singleton_method(klass, "capacity", bug_str_capacity, 1);
+}
diff --git a/ext/-test-/string/coderange.c b/ext/-test-/string/coderange.c
new file mode 100644
index 0000000000..df83fb5d44
--- /dev/null
+++ b/ext/-test-/string/coderange.c
@@ -0,0 +1,47 @@
+#include "ruby/ruby.h"
+#include "ruby/encoding.h"
+
+static VALUE sym_7bit, sym_valid, sym_unknown, sym_broken;
+
+static VALUE
+coderange_int2sym(int coderange)
+{
+ switch (coderange) {
+ case ENC_CODERANGE_7BIT:
+ return sym_7bit;
+ case ENC_CODERANGE_VALID:
+ return sym_valid;
+ case ENC_CODERANGE_UNKNOWN:
+ return sym_unknown;
+ case ENC_CODERANGE_BROKEN:
+ return sym_broken;
+ }
+ rb_bug("wrong condition of coderange");
+ UNREACHABLE;
+}
+
+/* return coderange without scan */
+static VALUE
+str_coderange(VALUE str)
+{
+ return coderange_int2sym(ENC_CODERANGE(str));
+}
+
+/* scan coderange and return the result */
+static VALUE
+str_coderange_scan(VALUE str)
+{
+ ENC_CODERANGE_SET(str, ENC_CODERANGE_UNKNOWN);
+ return coderange_int2sym(rb_enc_str_coderange(str));
+}
+
+void
+Init_string_coderange(VALUE klass)
+{
+ sym_7bit = ID2SYM(rb_intern("7bit"));
+ sym_valid = ID2SYM(rb_intern("valid"));
+ sym_unknown = ID2SYM(rb_intern("unknown"));
+ sym_broken = ID2SYM(rb_intern("broken"));
+ rb_define_method(klass, "coderange", str_coderange, 0);
+ rb_define_method(klass, "coderange_scan", str_coderange_scan, 0);
+}
diff --git a/ext/-test-/string/cstr.c b/ext/-test-/string/cstr.c
new file mode 100644
index 0000000000..2a41b932db
--- /dev/null
+++ b/ext/-test-/string/cstr.c
@@ -0,0 +1,146 @@
+#include "internal.h"
+
+static VALUE
+bug_str_cstr_term(VALUE str)
+{
+ long len;
+ char *s;
+ int c;
+ rb_encoding *enc;
+
+ len = RSTRING_LEN(str);
+ s = StringValueCStr(str);
+ rb_gc();
+ enc = rb_enc_get(str);
+ c = rb_enc_codepoint(&s[len], &s[len+rb_enc_mbminlen(enc)], enc);
+ return INT2NUM(c);
+}
+
+static VALUE
+bug_str_cstr_unterm(VALUE str, VALUE c)
+{
+ long len;
+
+ rb_str_modify(str);
+ len = RSTRING_LEN(str);
+ RSTRING_PTR(str)[len] = NUM2CHR(c);
+ return str;
+}
+
+static VALUE
+bug_str_cstr_term_char(VALUE str)
+{
+ long len;
+ char *s;
+ int c;
+ rb_encoding *enc = rb_enc_get(str);
+
+ RSTRING_GETMEM(str, s, len);
+ s += len;
+ len = rb_enc_mbminlen(enc);
+ c = rb_enc_precise_mbclen(s, s + len, enc);
+ if (!MBCLEN_CHARFOUND_P(c)) {
+ c = (unsigned char)*s;
+ }
+ else {
+ c = rb_enc_mbc_to_codepoint(s, s + len, enc);
+ if (!c) return Qnil;
+ }
+ return rb_enc_uint_chr((unsigned int)c, enc);
+}
+
+static VALUE
+bug_str_unterminated_substring(VALUE str, VALUE vbeg, VALUE vlen)
+{
+ long beg = NUM2LONG(vbeg);
+ long len = NUM2LONG(vlen);
+ rb_str_modify(str);
+ if (len < 0) rb_raise(rb_eArgError, "negative length: %ld", len);
+ if (RSTRING_LEN(str) < beg) rb_raise(rb_eIndexError, "beg: %ld", beg);
+ if (RSTRING_LEN(str) < beg + len) rb_raise(rb_eIndexError, "end: %ld", beg + len);
+ str = rb_str_new_shared(str);
+ if (STR_EMBED_P(str)) {
+ RSTRING(str)->basic.flags &= ~RSTRING_EMBED_LEN_MASK;
+ RSTRING(str)->basic.flags |= len << RSTRING_EMBED_LEN_SHIFT;
+ memmove(RSTRING(str)->as.ary, RSTRING(str)->as.ary + beg, len);
+ }
+ else {
+ RSTRING(str)->as.heap.ptr += beg;
+ RSTRING(str)->as.heap.len = len;
+ }
+ return str;
+}
+
+static VALUE
+bug_str_s_cstr_term(VALUE self, VALUE str)
+{
+ Check_Type(str, T_STRING);
+ return bug_str_cstr_term(str);
+}
+
+static VALUE
+bug_str_s_cstr_unterm(VALUE self, VALUE str, VALUE c)
+{
+ Check_Type(str, T_STRING);
+ return bug_str_cstr_unterm(str, c);
+}
+
+static VALUE
+bug_str_s_cstr_term_char(VALUE self, VALUE str)
+{
+ Check_Type(str, T_STRING);
+ return bug_str_cstr_term_char(str);
+}
+
+#define TERM_LEN(str) rb_enc_mbminlen(rb_enc_get(str))
+#define TERM_FILL(ptr, termlen) do {\
+ char *const term_fill_ptr = (ptr);\
+ const int term_fill_len = (termlen);\
+ *term_fill_ptr = '\0';\
+ if (UNLIKELY(term_fill_len > 1))\
+ memset(term_fill_ptr, 0, term_fill_len);\
+} while (0)
+
+static VALUE
+bug_str_s_cstr_noembed(VALUE self, VALUE str)
+{
+ VALUE str2 = rb_str_new(NULL, 0);
+ long capacity = RSTRING_LEN(str) + TERM_LEN(str);
+ char *buf = ALLOC_N(char, capacity);
+ Check_Type(str, T_STRING);
+ FL_SET((str2), STR_NOEMBED);
+ memcpy(buf, RSTRING_PTR(str), capacity);
+ RBASIC(str2)->flags &= ~RSTRING_EMBED_LEN_MASK;
+ RSTRING(str2)->as.heap.aux.capa = capacity;
+ RSTRING(str2)->as.heap.ptr = buf;
+ RSTRING(str2)->as.heap.len = RSTRING_LEN(str);
+ TERM_FILL(RSTRING_END(str2), TERM_LEN(str));
+ return str2;
+}
+
+static VALUE
+bug_str_s_cstr_embedded_p(VALUE self, VALUE str)
+{
+ return STR_EMBED_P(str) ? Qtrue : Qfalse;
+}
+
+static VALUE
+bug_str_s_rb_str_new_frozen(VALUE self, VALUE str)
+{
+ return rb_str_new_frozen(str);
+}
+
+void
+Init_string_cstr(VALUE klass)
+{
+ rb_define_method(klass, "cstr_term", bug_str_cstr_term, 0);
+ rb_define_method(klass, "cstr_unterm", bug_str_cstr_unterm, 1);
+ rb_define_method(klass, "cstr_term_char", bug_str_cstr_term_char, 0);
+ rb_define_method(klass, "unterminated_substring", bug_str_unterminated_substring, 2);
+ rb_define_singleton_method(klass, "cstr_term", bug_str_s_cstr_term, 1);
+ rb_define_singleton_method(klass, "cstr_unterm", bug_str_s_cstr_unterm, 2);
+ rb_define_singleton_method(klass, "cstr_term_char", bug_str_s_cstr_term_char, 1);
+ rb_define_singleton_method(klass, "cstr_noembed", bug_str_s_cstr_noembed, 1);
+ rb_define_singleton_method(klass, "cstr_embedded?", bug_str_s_cstr_embedded_p, 1);
+ rb_define_singleton_method(klass, "rb_str_new_frozen", bug_str_s_rb_str_new_frozen, 1);
+}
diff --git a/ext/-test-/string/depend b/ext/-test-/string/depend
new file mode 100644
index 0000000000..71e995a523
--- /dev/null
+++ b/ext/-test-/string/depend
@@ -0,0 +1,198 @@
+# AUTOGENERATED DEPENDENCIES START
+capacity.o: $(RUBY_EXTCONF_H)
+capacity.o: $(arch_hdrdir)/ruby/config.h
+capacity.o: $(hdrdir)/ruby/backward.h
+capacity.o: $(hdrdir)/ruby/defines.h
+capacity.o: $(hdrdir)/ruby/encoding.h
+capacity.o: $(hdrdir)/ruby/intern.h
+capacity.o: $(hdrdir)/ruby/io.h
+capacity.o: $(hdrdir)/ruby/missing.h
+capacity.o: $(hdrdir)/ruby/onigmo.h
+capacity.o: $(hdrdir)/ruby/oniguruma.h
+capacity.o: $(hdrdir)/ruby/ruby.h
+capacity.o: $(hdrdir)/ruby/st.h
+capacity.o: $(hdrdir)/ruby/subst.h
+capacity.o: $(top_srcdir)/include/ruby.h
+capacity.o: $(top_srcdir)/internal.h
+capacity.o: capacity.c
+coderange.o: $(RUBY_EXTCONF_H)
+coderange.o: $(arch_hdrdir)/ruby/config.h
+coderange.o: $(hdrdir)/ruby/backward.h
+coderange.o: $(hdrdir)/ruby/defines.h
+coderange.o: $(hdrdir)/ruby/encoding.h
+coderange.o: $(hdrdir)/ruby/intern.h
+coderange.o: $(hdrdir)/ruby/missing.h
+coderange.o: $(hdrdir)/ruby/onigmo.h
+coderange.o: $(hdrdir)/ruby/oniguruma.h
+coderange.o: $(hdrdir)/ruby/ruby.h
+coderange.o: $(hdrdir)/ruby/st.h
+coderange.o: $(hdrdir)/ruby/subst.h
+coderange.o: coderange.c
+cstr.o: $(RUBY_EXTCONF_H)
+cstr.o: $(arch_hdrdir)/ruby/config.h
+cstr.o: $(hdrdir)/ruby/backward.h
+cstr.o: $(hdrdir)/ruby/defines.h
+cstr.o: $(hdrdir)/ruby/encoding.h
+cstr.o: $(hdrdir)/ruby/intern.h
+cstr.o: $(hdrdir)/ruby/io.h
+cstr.o: $(hdrdir)/ruby/missing.h
+cstr.o: $(hdrdir)/ruby/onigmo.h
+cstr.o: $(hdrdir)/ruby/oniguruma.h
+cstr.o: $(hdrdir)/ruby/ruby.h
+cstr.o: $(hdrdir)/ruby/st.h
+cstr.o: $(hdrdir)/ruby/subst.h
+cstr.o: $(top_srcdir)/include/ruby.h
+cstr.o: $(top_srcdir)/internal.h
+cstr.o: cstr.c
+ellipsize.o: $(RUBY_EXTCONF_H)
+ellipsize.o: $(arch_hdrdir)/ruby/config.h
+ellipsize.o: $(hdrdir)/ruby/backward.h
+ellipsize.o: $(hdrdir)/ruby/defines.h
+ellipsize.o: $(hdrdir)/ruby/intern.h
+ellipsize.o: $(hdrdir)/ruby/missing.h
+ellipsize.o: $(hdrdir)/ruby/ruby.h
+ellipsize.o: $(hdrdir)/ruby/st.h
+ellipsize.o: $(hdrdir)/ruby/subst.h
+ellipsize.o: $(top_srcdir)/include/ruby.h
+ellipsize.o: ellipsize.c
+enc_associate.o: $(RUBY_EXTCONF_H)
+enc_associate.o: $(arch_hdrdir)/ruby/config.h
+enc_associate.o: $(hdrdir)/ruby/backward.h
+enc_associate.o: $(hdrdir)/ruby/defines.h
+enc_associate.o: $(hdrdir)/ruby/encoding.h
+enc_associate.o: $(hdrdir)/ruby/intern.h
+enc_associate.o: $(hdrdir)/ruby/missing.h
+enc_associate.o: $(hdrdir)/ruby/onigmo.h
+enc_associate.o: $(hdrdir)/ruby/oniguruma.h
+enc_associate.o: $(hdrdir)/ruby/ruby.h
+enc_associate.o: $(hdrdir)/ruby/st.h
+enc_associate.o: $(hdrdir)/ruby/subst.h
+enc_associate.o: $(top_srcdir)/include/ruby.h
+enc_associate.o: enc_associate.c
+enc_str_buf_cat.o: $(RUBY_EXTCONF_H)
+enc_str_buf_cat.o: $(arch_hdrdir)/ruby/config.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/backward.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/defines.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/encoding.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/intern.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/missing.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/onigmo.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/oniguruma.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/ruby.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/st.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/subst.h
+enc_str_buf_cat.o: enc_str_buf_cat.c
+fstring.o: $(RUBY_EXTCONF_H)
+fstring.o: $(arch_hdrdir)/ruby/config.h
+fstring.o: $(hdrdir)/ruby/backward.h
+fstring.o: $(hdrdir)/ruby/defines.h
+fstring.o: $(hdrdir)/ruby/intern.h
+fstring.o: $(hdrdir)/ruby/missing.h
+fstring.o: $(hdrdir)/ruby/ruby.h
+fstring.o: $(hdrdir)/ruby/st.h
+fstring.o: $(hdrdir)/ruby/subst.h
+fstring.o: $(top_srcdir)/include/ruby.h
+fstring.o: fstring.c
+init.o: $(RUBY_EXTCONF_H)
+init.o: $(arch_hdrdir)/ruby/config.h
+init.o: $(hdrdir)/ruby/backward.h
+init.o: $(hdrdir)/ruby/defines.h
+init.o: $(hdrdir)/ruby/intern.h
+init.o: $(hdrdir)/ruby/missing.h
+init.o: $(hdrdir)/ruby/ruby.h
+init.o: $(hdrdir)/ruby/st.h
+init.o: $(hdrdir)/ruby/subst.h
+init.o: $(top_srcdir)/include/ruby.h
+init.o: init.c
+modify.o: $(RUBY_EXTCONF_H)
+modify.o: $(arch_hdrdir)/ruby/config.h
+modify.o: $(hdrdir)/ruby/backward.h
+modify.o: $(hdrdir)/ruby/defines.h
+modify.o: $(hdrdir)/ruby/intern.h
+modify.o: $(hdrdir)/ruby/missing.h
+modify.o: $(hdrdir)/ruby/ruby.h
+modify.o: $(hdrdir)/ruby/st.h
+modify.o: $(hdrdir)/ruby/subst.h
+modify.o: $(top_srcdir)/include/ruby.h
+modify.o: modify.c
+new.o: $(RUBY_EXTCONF_H)
+new.o: $(arch_hdrdir)/ruby/config.h
+new.o: $(hdrdir)/ruby/backward.h
+new.o: $(hdrdir)/ruby/defines.h
+new.o: $(hdrdir)/ruby/encoding.h
+new.o: $(hdrdir)/ruby/intern.h
+new.o: $(hdrdir)/ruby/io.h
+new.o: $(hdrdir)/ruby/missing.h
+new.o: $(hdrdir)/ruby/onigmo.h
+new.o: $(hdrdir)/ruby/oniguruma.h
+new.o: $(hdrdir)/ruby/ruby.h
+new.o: $(hdrdir)/ruby/st.h
+new.o: $(hdrdir)/ruby/subst.h
+new.o: $(top_srcdir)/include/ruby.h
+new.o: $(top_srcdir)/internal.h
+new.o: new.c
+nofree.o: $(RUBY_EXTCONF_H)
+nofree.o: $(arch_hdrdir)/ruby/config.h
+nofree.o: $(hdrdir)/ruby/backward.h
+nofree.o: $(hdrdir)/ruby/defines.h
+nofree.o: $(hdrdir)/ruby/intern.h
+nofree.o: $(hdrdir)/ruby/missing.h
+nofree.o: $(hdrdir)/ruby/ruby.h
+nofree.o: $(hdrdir)/ruby/st.h
+nofree.o: $(hdrdir)/ruby/subst.h
+nofree.o: $(top_srcdir)/include/ruby.h
+nofree.o: nofree.c
+normalize.o: $(RUBY_EXTCONF_H)
+normalize.o: $(arch_hdrdir)/ruby/config.h
+normalize.o: $(hdrdir)/ruby/backward.h
+normalize.o: $(hdrdir)/ruby/defines.h
+normalize.o: $(hdrdir)/ruby/encoding.h
+normalize.o: $(hdrdir)/ruby/intern.h
+normalize.o: $(hdrdir)/ruby/io.h
+normalize.o: $(hdrdir)/ruby/missing.h
+normalize.o: $(hdrdir)/ruby/onigmo.h
+normalize.o: $(hdrdir)/ruby/oniguruma.h
+normalize.o: $(hdrdir)/ruby/ruby.h
+normalize.o: $(hdrdir)/ruby/st.h
+normalize.o: $(hdrdir)/ruby/subst.h
+normalize.o: $(top_srcdir)/include/ruby.h
+normalize.o: $(top_srcdir)/internal.h
+normalize.o: normalize.c
+qsort.o: $(RUBY_EXTCONF_H)
+qsort.o: $(arch_hdrdir)/ruby/config.h
+qsort.o: $(hdrdir)/ruby/backward.h
+qsort.o: $(hdrdir)/ruby/defines.h
+qsort.o: $(hdrdir)/ruby/encoding.h
+qsort.o: $(hdrdir)/ruby/intern.h
+qsort.o: $(hdrdir)/ruby/missing.h
+qsort.o: $(hdrdir)/ruby/onigmo.h
+qsort.o: $(hdrdir)/ruby/oniguruma.h
+qsort.o: $(hdrdir)/ruby/ruby.h
+qsort.o: $(hdrdir)/ruby/st.h
+qsort.o: $(hdrdir)/ruby/subst.h
+qsort.o: $(hdrdir)/ruby/util.h
+qsort.o: $(top_srcdir)/include/ruby.h
+qsort.o: qsort.c
+rb_str_dup.o: $(RUBY_EXTCONF_H)
+rb_str_dup.o: $(arch_hdrdir)/ruby/config.h
+rb_str_dup.o: $(hdrdir)/ruby.h
+rb_str_dup.o: $(hdrdir)/ruby/backward.h
+rb_str_dup.o: $(hdrdir)/ruby/defines.h
+rb_str_dup.o: $(hdrdir)/ruby/intern.h
+rb_str_dup.o: $(hdrdir)/ruby/missing.h
+rb_str_dup.o: $(hdrdir)/ruby/ruby.h
+rb_str_dup.o: $(hdrdir)/ruby/st.h
+rb_str_dup.o: $(hdrdir)/ruby/subst.h
+rb_str_dup.o: rb_str_dup.c
+set_len.o: $(RUBY_EXTCONF_H)
+set_len.o: $(arch_hdrdir)/ruby/config.h
+set_len.o: $(hdrdir)/ruby/backward.h
+set_len.o: $(hdrdir)/ruby/defines.h
+set_len.o: $(hdrdir)/ruby/intern.h
+set_len.o: $(hdrdir)/ruby/missing.h
+set_len.o: $(hdrdir)/ruby/ruby.h
+set_len.o: $(hdrdir)/ruby/st.h
+set_len.o: $(hdrdir)/ruby/subst.h
+set_len.o: $(top_srcdir)/include/ruby.h
+set_len.o: set_len.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/string/ellipsize.c b/ext/-test-/string/ellipsize.c
new file mode 100644
index 0000000000..6034408724
--- /dev/null
+++ b/ext/-test-/string/ellipsize.c
@@ -0,0 +1,13 @@
+#include "ruby.h"
+
+static VALUE
+bug_str_ellipsize(VALUE str, VALUE len)
+{
+ return rb_str_ellipsize(str, NUM2LONG(len));
+}
+
+void
+Init_string_ellipsize(VALUE klass)
+{
+ rb_define_method(klass, "ellipsize", bug_str_ellipsize, 1);
+}
diff --git a/ext/-test-/string/enc_associate.c b/ext/-test-/string/enc_associate.c
new file mode 100644
index 0000000000..594d8a43a4
--- /dev/null
+++ b/ext/-test-/string/enc_associate.c
@@ -0,0 +1,22 @@
+#include "ruby.h"
+#include "ruby/encoding.h"
+
+VALUE
+bug_str_enc_associate(VALUE str, VALUE enc)
+{
+ return rb_enc_associate(str, rb_to_encoding(enc));
+}
+
+VALUE
+bug_str_encoding_index(VALUE self, VALUE str)
+{
+ int idx = rb_enc_get_index(str);
+ return INT2NUM(idx);
+}
+
+void
+Init_string_enc_associate(VALUE klass)
+{
+ rb_define_method(klass, "associate_encoding!", bug_str_enc_associate, 1);
+ rb_define_singleton_method(klass, "encoding_index", bug_str_encoding_index, 1);
+}
diff --git a/ext/-test-/string/enc_str_buf_cat.c b/ext/-test-/string/enc_str_buf_cat.c
new file mode 100644
index 0000000000..9ac4a298be
--- /dev/null
+++ b/ext/-test-/string/enc_str_buf_cat.c
@@ -0,0 +1,14 @@
+#include "ruby/ruby.h"
+#include "ruby/encoding.h"
+
+static VALUE
+enc_str_buf_cat(VALUE str, VALUE str2)
+{
+ return rb_enc_str_buf_cat(str, RSTRING_PTR(str2), RSTRING_LEN(str2), rb_enc_get(str2));
+}
+
+void
+Init_string_enc_str_buf_cat(VALUE klass)
+{
+ rb_define_method(klass, "enc_str_buf_cat", enc_str_buf_cat, 1);
+}
diff --git a/ext/-test-/string/extconf.rb b/ext/-test-/string/extconf.rb
new file mode 100644
index 0000000000..d786b15db9
--- /dev/null
+++ b/ext/-test-/string/extconf.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: false
+require_relative "../auto_ext.rb"
+auto_ext(inc: true)
diff --git a/ext/-test-/string/fstring.c b/ext/-test-/string/fstring.c
new file mode 100644
index 0000000000..30120b42f6
--- /dev/null
+++ b/ext/-test-/string/fstring.c
@@ -0,0 +1,15 @@
+#include "ruby.h"
+
+VALUE rb_fstring(VALUE str);
+
+VALUE
+bug_s_fstring(VALUE self, VALUE str)
+{
+ return rb_fstring(str);
+}
+
+void
+Init_string_fstring(VALUE klass)
+{
+ rb_define_singleton_method(klass, "fstring", bug_s_fstring, 1);
+}
diff --git a/ext/-test-/string/init.c b/ext/-test-/string/init.c
new file mode 100644
index 0000000000..a74245c8d7
--- /dev/null
+++ b/ext/-test-/string/init.c
@@ -0,0 +1,11 @@
+#include "ruby.h"
+
+#define init(n) {void Init_string_##n(VALUE klass); Init_string_##n(klass);}
+
+void
+Init_string(void)
+{
+ VALUE mBug = rb_define_module("Bug");
+ VALUE klass = rb_define_class_under(mBug, "String", rb_cString);
+ TEST_INIT_FUNCS(init);
+}
diff --git a/ext/-test-/string/modify.c b/ext/-test-/string/modify.c
new file mode 100644
index 0000000000..945febc7e3
--- /dev/null
+++ b/ext/-test-/string/modify.c
@@ -0,0 +1,22 @@
+#include "ruby.h"
+
+VALUE
+bug_str_modify(VALUE str)
+{
+ rb_str_modify(str);
+ return str;
+}
+
+VALUE
+bug_str_modify_expand(VALUE str, VALUE expand)
+{
+ rb_str_modify_expand(str, NUM2LONG(expand));
+ return str;
+}
+
+void
+Init_string_modify(VALUE klass)
+{
+ rb_define_method(klass, "modify!", bug_str_modify, 0);
+ rb_define_method(klass, "modify_expand!", bug_str_modify_expand, 1);
+}
diff --git a/ext/-test-/string/new.c b/ext/-test-/string/new.c
new file mode 100644
index 0000000000..60625b8300
--- /dev/null
+++ b/ext/-test-/string/new.c
@@ -0,0 +1,21 @@
+#include "ruby.h"
+#include "ruby/encoding.h"
+
+static VALUE
+bug_str_buf_new(VALUE self, VALUE len)
+{
+ return rb_str_buf_new(NUM2LONG(len));
+}
+
+static VALUE
+bug_external_str_new(VALUE self, VALUE len, VALUE enc)
+{
+ return rb_external_str_new_with_enc(NULL, NUM2LONG(len), rb_to_encoding(enc));
+}
+
+void
+Init_string_new(VALUE klass)
+{
+ rb_define_singleton_method(klass, "buf_new", bug_str_buf_new, 1);
+ rb_define_singleton_method(klass, "external_new", bug_external_str_new, 2);
+}
diff --git a/ext/-test-/string/nofree.c b/ext/-test-/string/nofree.c
new file mode 100644
index 0000000000..fdf810c741
--- /dev/null
+++ b/ext/-test-/string/nofree.c
@@ -0,0 +1,13 @@
+#include "ruby.h"
+
+VALUE
+bug_str_nofree(VALUE self)
+{
+ return rb_str_new_cstr("abcdef");
+}
+
+void
+Init_string_nofree(VALUE klass)
+{
+ rb_define_singleton_method(klass, "nofree", bug_str_nofree, 0);
+}
diff --git a/ext/-test-/string/normalize.c b/ext/-test-/string/normalize.c
new file mode 100644
index 0000000000..0ba1797631
--- /dev/null
+++ b/ext/-test-/string/normalize.c
@@ -0,0 +1,17 @@
+#include "internal.h"
+
+#ifdef __APPLE__
+static VALUE
+normalize_ospath(VALUE str)
+{
+ return rb_str_normalize_ospath(RSTRING_PTR(str), RSTRING_LEN(str));
+}
+#else
+#define normalize_ospath rb_f_notimplement
+#endif
+
+void
+Init_string_normalize(VALUE klass)
+{
+ rb_define_method(klass, "normalize_ospath", normalize_ospath, 0);
+}
diff --git a/ext/-test-/string/qsort.c b/ext/-test-/string/qsort.c
new file mode 100644
index 0000000000..fb7ea3d8cb
--- /dev/null
+++ b/ext/-test-/string/qsort.c
@@ -0,0 +1,61 @@
+#include "ruby.h"
+#include "ruby/util.h"
+#include "ruby/encoding.h"
+
+struct sort_data {
+ rb_encoding *enc;
+ long elsize;
+};
+
+static int
+cmp_1(const void *ap, const void *bp, void *dummy)
+{
+ struct sort_data *d = dummy;
+ VALUE a = rb_enc_str_new(ap, d->elsize, d->enc);
+ VALUE b = rb_enc_str_new(bp, d->elsize, d->enc);
+ VALUE retval = rb_yield_values(2, a, b);
+ return rb_cmpint(retval, a, b);
+}
+
+static int
+cmp_2(const void *ap, const void *bp, void *dummy)
+{
+ int a = *(const unsigned char *)ap;
+ int b = *(const unsigned char *)bp;
+ return a - b;
+}
+
+static VALUE
+bug_str_qsort_bang(int argc, VALUE *argv, VALUE str)
+{
+ VALUE beg, len, size;
+ long l, b = 0, n, s = 1;
+ struct sort_data d;
+
+ rb_scan_args(argc, argv, "03", &beg, &len, &size);
+ l = RSTRING_LEN(str);
+ if (!NIL_P(beg) && (b = NUM2INT(beg)) < 0 && (b += l) < 0) {
+ rb_raise(rb_eArgError, "out of bounds");
+ }
+ if (!NIL_P(size) && (s = NUM2INT(size)) < 0) {
+ rb_raise(rb_eArgError, "negative size");
+ }
+ if (NIL_P(len) ||
+ (((n = NUM2INT(len)) < 0) ?
+ (rb_raise(rb_eArgError, "negative length"), 0) :
+ (b + n * s > l))) {
+ n = (l - b) / s;
+ }
+ rb_str_modify(str);
+ d.enc = rb_enc_get(str);
+ d.elsize = s;
+ ruby_qsort(RSTRING_PTR(str) + b, n, s,
+ rb_block_given_p() ? cmp_1 : cmp_2, &d);
+ return str;
+}
+
+void
+Init_string_qsort(VALUE klass)
+{
+ rb_define_method(klass, "qsort!", bug_str_qsort_bang, -1);
+}
diff --git a/ext/-test-/string/rb_str_dup.c b/ext/-test-/string/rb_str_dup.c
new file mode 100644
index 0000000000..a0bd65820f
--- /dev/null
+++ b/ext/-test-/string/rb_str_dup.c
@@ -0,0 +1,35 @@
+#include "ruby.h"
+
+VALUE rb_str_dup(VALUE str);
+
+static VALUE
+bug_rb_str_dup(VALUE self, VALUE str)
+{
+ rb_check_type(str, T_STRING);
+ return rb_str_dup(str);
+}
+
+static VALUE
+bug_shared_string_p(VALUE self, VALUE str)
+{
+ rb_check_type(str, T_STRING);
+ return RB_FL_TEST(str, RUBY_ELTS_SHARED) && RB_FL_TEST(str, RSTRING_NOEMBED) ? Qtrue : Qfalse;
+}
+
+static VALUE
+bug_sharing_with_shared_p(VALUE self, VALUE str)
+{
+ rb_check_type(str, T_STRING);
+ if (bug_shared_string_p(self, str)) {
+ return bug_shared_string_p(self, RSTRING(str)->as.heap.aux.shared);
+ }
+ return Qfalse;
+}
+
+void
+Init_string_rb_str_dup(VALUE klass)
+{
+ rb_define_singleton_method(klass, "rb_str_dup", bug_rb_str_dup, 1);
+ rb_define_singleton_method(klass, "shared_string?", bug_shared_string_p, 1);
+ rb_define_singleton_method(klass, "sharing_with_shared?", bug_sharing_with_shared_p, 1);
+}
diff --git a/ext/-test-/string/set_len.c b/ext/-test-/string/set_len.c
new file mode 100644
index 0000000000..219cea404c
--- /dev/null
+++ b/ext/-test-/string/set_len.c
@@ -0,0 +1,14 @@
+#include "ruby.h"
+
+static VALUE
+bug_str_set_len(VALUE str, VALUE len)
+{
+ rb_str_set_len(str, NUM2LONG(len));
+ return str;
+}
+
+void
+Init_string_set_len(VALUE klass)
+{
+ rb_define_method(klass, "set_len", bug_str_set_len, 1);
+}