Jens Geyer created THRIFT-6236:
----------------------------------

             Summary: Generated string constants are not escaped correctly in 
several target languages
                 Key: THRIFT-6236
                 URL: https://issues.apache.org/jira/browse/THRIFT-6236
             Project: Thrift
          Issue Type: Bug
          Components: C glib - Compiler, Kotlin - Compiler, Rust - Compiler, 
Lua - Compiler, Common LISP - Compiler, Delphi - Compiler, Ruby - Compiler, 
Dart - Compiler
            Reporter: Jens Geyer


Several code generators write string constants in a form that does not fit the 
string syntax of the target language. A constant that contains a quote, a 
backslash, a line break or a dollar sign then produces generated code that does 
not compile, or a constant with a different value. Since THRIFT-4244 the 
compiler tells users to double a backslash to get a literal one, and in the 
generators below exactly that input breaks.

h3. Cause

Most generators pass the value through {{t_generator::escape_string()}}, which 
fits C-like string syntax.
* rs, c_glib, cl, kotlin and lua write the raw value.
* dart, rb and delphi escape it, but not for their own string syntax: dart puts 
the C-style escapes inside single quotes and escapes neither {{'}} nor {{$}}; 
rb puts them into a {{%q}} string, where only the delimiter and the backslash 
itself can be escaped; delphi only doubles single quotes.

h3. How this was checked

One constant per IDL file, generated with current master (81103bf9c):
{noformat}
namespace * esc
const string X = "say \"hi\""     # value: say "hi"
const string X = 'don\'t'         # value: don't
const string X = "C:\\Temp"       # value: C:\Temp
const string X = "a\nb"           # value: a, line feed, b
const string X = "a\tb"           # value: a, tab, b
const string X = "a$b"            # value: a$b
{noformat}
The generated constant was fed to the real toolchain wherever the 
{{thrift:jammy}} build image has one. As a control, {{const string X = 
"plain"}} compiled (or parsed) and kept its value in every one of them.

h3. Results

{noformat}
gen     value     generated code                                 result
rs      say "hi"  pub const X: &str = "say "hi"";                rustc 1.83: 
expected one of `.`, `;`, `?`, `where`,
                                                                 or an 
operator, found `""`
rs      C:\Temp   pub const X: &str = "C:\Temp";                 rustc: unknown 
character escape: `T`
c_glib  say "hi"  #define ESC_X g_strdup ("say "hi"")            gcc: expected 
')' before 'hi'
c_glib  C:\Temp   #define ESC_X g_strdup ("C:\Temp")             gcc: unknown 
escape sequence: '\T' (a warning)
c_glib  a<LF>b    line break inside the string literal           gcc: missing 
terminating " character
lua     don't     X = 'don't'                                    luac 5.4: 
unfinished string
lua     C:\Temp   X = 'C:\Temp'                                  luac: invalid 
escape sequence
lua     a<LF>b    line break inside the string literal           luac: 
unfinished string
cl      say "hi"  (thrift:def-constant "X" "say "hi"")           SBCL reads 4 
arguments instead of 2
cl      C:\Temp   (thrift:def-constant "X" "C:\Temp")            SBCL reads the 
value as C:Temp
dart    don't     static final String X = 'don't';               dart 2.7: 
String starting with ' must end with '.
dart    a$b       static final String X = 'a$b';                 dart: Getter 
not found: 'b'.
rb      a<LF>b    X = %q"a\nb"                                   ruby: the 
value is a\nb (backslash, n); same for \t
{noformat}

Not compiled, as the image has no Kotlin or Delphi compiler, but the output is 
visibly invalid:
{noformat}
kotlin  say "hi"  const val X: kotlin.String = "say "hi""
kotlin  C:\Temp   const val X: kotlin.String = "C:\Temp"         \T is not a 
Kotlin escape sequence
kotlin  a<LF>b    line break inside the string literal
kotlin  a$b       const val X: kotlin.String = "a$b"             $b is a string 
template
delphi  a<LF>b    line break inside the string literal
{noformat}

Generators not listed here were not checked systematically. perl and php do 
escape {{$}} (perl also {{@}}). The JavaScript generator had the same kind of 
problem before, see THRIFT-2495 and THRIFT-2594.

_Drafted with AI assistance (Claude Opus 5); reviewed and filed by Jens Geyer._




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to