Skip to content

Commit

Permalink
Show where mutated chilled strings were allocated
Browse files Browse the repository at this point in the history
[Feature #20205]

The warning now suggests running with --debug-frozen-string-literal:

```
test.rb:3: warning: literal string will be frozen in the future (run with --debug-frozen-string-literal for more information)
```

When using --debug-frozen-string-literal, the location where the string
was created is shown:

```
test.rb:3: warning: literal string will be frozen in the future
test.rb:1: the string was created here
```

When resurrecting strings and debug mode is not enabled, the overhead is a simple FL_TEST_RAW.
When mutating chilled strings and deprecation warnings are not enabled,
the overhead is a simple warning category enabled check.

Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
  • Loading branch information
etiennebarrie and byroot committed Oct 14, 2024
1 parent 1001ea9 commit a3071bd
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 6 deletions.
4 changes: 2 additions & 2 deletions bootstraptest/test_yjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4726,7 +4726,7 @@ def test(klass, args)
}

# Chilled string setivar trigger warning
assert_equal 'literal string will be frozen in the future', %q{
assert_match(/literal string will be frozen in the future/, %q{
Warning[:deprecated] = true
$VERBOSE = true
$warning = "no-warning"
Expand Down Expand Up @@ -4754,7 +4754,7 @@ def setivar!(str)
setivar!("chilled") # Emit warning
$warning
}
})

# arity=-2 cfuncs
assert_equal '["", "1/2", [0, [:ok, 1]]]', %q{
Expand Down
23 changes: 22 additions & 1 deletion internal/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "ruby/internal/stdbool.h" /* for bool */
#include "ruby/encoding.h" /* for rb_encoding */
#include "ruby/ruby.h" /* for VALUE */
#include "id.h" /* for id_debug_created_info */

#define STR_NOEMBED FL_USER1
#define STR_SHARED FL_USER2 /* = ELTS_SHARED */
Expand Down Expand Up @@ -123,8 +124,28 @@ CHILLED_STRING_P(VALUE obj)
static inline void
CHILLED_STRING_MUTATED(VALUE str)
{
bool rb_warning_category_enabled_p(rb_warning_category_t category);

FL_UNSET_RAW(str, STR_CHILLED);
rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "literal string will be frozen in the future");

if (RB_UNLIKELY(rb_warning_category_enabled_p(RB_WARN_CATEGORY_DEPRECATED))) {
VALUE debug_info = rb_attr_get(str, id_debug_created_info);
if (NIL_P(debug_info)) {
rb_category_warn(
RB_WARN_CATEGORY_DEPRECATED,
"literal string will be frozen in the future "
"(run with --debug-frozen-string-literal for more information)");
} else {
VALUE path = rb_ary_entry(debug_info, 0);
VALUE line = rb_ary_entry(debug_info, 1);

rb_category_warn(
RB_WARN_CATEGORY_DEPRECATED,
"literal string will be frozen in the future\n%"PRIsVALUE":%"PRIsVALUE": the string was created here",
path,
line);
}
}
}

static inline void
Expand Down
1 change: 0 additions & 1 deletion spec/ruby/command_line/fixtures/debug_info.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# frozen_string_literal: true
a = 'string'
b = a
c = b
Expand Down
11 changes: 9 additions & 2 deletions spec/ruby/command_line/frozen_strings_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,16 @@

describe "The --debug flag produces" do
it "debugging info on attempted frozen string modification" do
error_str = ruby_exe(fixture(__FILE__, 'debug_info.rb'), options: '--debug', args: "2>&1")
error_str = ruby_exe(fixture(__FILE__, 'debug_info.rb'), options: '--enable-frozen-string-literal --debug', args: "2>&1")
error_str.should include("can't modify frozen String")
error_str.should include("created at")
error_str.should include("command_line/fixtures/debug_info.rb:2")
error_str.should include("command_line/fixtures/debug_info.rb:1")
end

it "debugging info on mutating chilled string" do
error_str = ruby_exe(fixture(__FILE__, 'debug_info.rb'), options: '-w --debug', args: "2>&1")
error_str.should include("literal string will be frozen in the future")
error_str.should include("the string was created here")
error_str.should include("command_line/fixtures/debug_info.rb:1")
end
end
6 changes: 6 additions & 0 deletions string.c
Original file line number Diff line number Diff line change
Expand Up @@ -1914,6 +1914,12 @@ rb_ec_str_resurrect(struct rb_execution_context_struct *ec, VALUE str, bool chil
RUBY_DTRACE_CREATE_HOOK(STRING, RSTRING_LEN(str));
VALUE new_str = ec_str_duplicate(ec, rb_cString, str);
if (chilled) {
if (RB_UNLIKELY(FL_TEST_RAW(str, FL_EXIVAR))) {
VALUE debug_info = rb_ivar_get(str, id_debug_created_info);
if (!NIL_P(debug_info)) {
rb_ivar_set(new_str, id_debug_created_info, debug_info);
}
}
STR_CHILL_RAW(new_str);
}
return new_str;
Expand Down

0 comments on commit a3071bd

Please sign in to comment.