Skip to content

Commit 6cea2fe

Browse files
committed
v3: detect wrapped fastc NUL escapes
1 parent f44ca9a commit 6cea2fe

3 files changed

Lines changed: 47 additions & 6 deletions

File tree

vlib/v3/gen/fastc/fastc.v

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,20 @@ fn fastc_string_contains_nul(content string, is_raw bool) bool {
740740
i += 2
741741
continue
742742
}
743+
if escape >= `0` && escape <= `7` && i + 3 < content.len && content[i + 2] >= `0`
744+
&& content[i + 2] <= `7` && content[i + 3] >= `0` && content[i + 3] <= `7` {
745+
high := int(escape - `0`)
746+
middle := int(content[i + 2] - `0`)
747+
low := int(content[i + 3] - `0`)
748+
value := high * 64 + middle * 8 + low
749+
// V stores three-digit octal escapes in a byte, including wrapping
750+
// values such as \400 to NUL.
751+
if u8(value) == 0 {
752+
return true
753+
}
754+
i += 4
755+
continue
756+
}
743757
if escape == `0`
744758
|| (escape == `x` && i + 3 < content.len && content[i + 2..i + 4] == '00')
745759
|| (escape == `u` && i + 5 < content.len && content[i + 2..i + 6] == '0000')

vlib/v3/gen/fastc/fastc_test.v

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,17 +128,25 @@ fn test_hex_string_escape_has_fixed_width_in_c() {
128128

129129
fn test_runtime_sensitive_constructs_request_checked_lane() {
130130
prefs := pref.new_preferences()
131-
mut nul_failed := false
132-
_ := generate('module main
131+
for source in ['module main
133132
134133
fn main() {
135134
println("a\\0b")
136135
}
137-
', 'nul_string.v', prefs) or {
138-
nul_failed = true
139-
''
136+
',
137+
"module main\nfn main() { println('\\400tail') }\n"] {
138+
mut nul_failed := false
139+
_ := generate(source, 'nul_string.v', prefs) or {
140+
nul_failed = true
141+
''
142+
}
143+
assert nul_failed
140144
}
141-
assert nul_failed
145+
assert fastc_string_contains_nul(r'\400tail', false)
146+
assert !fastc_string_contains_nul(r'\401tail', false)
147+
non_nul_octal_c := generate("module main\nfn main() { println('\\401tail') }\n",
148+
'non_nul_octal_string.v', prefs) or { panic(err) }
149+
assert non_nul_octal_c.contains(r'println("\401tail");')
142150

143151
mut assert_failed := false
144152
_ := generate('module main

vlib/v3/tests/fastc_backend_test.v

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,25 @@ fn main() {
547547
assert nul_run.exit_code == 0, nul_run.output.bytes().str()
548548
assert nul_run.output == 'a\0b\n', nul_run.output.bytes().str()
549549

550+
wrapped_nul_source := os.join_path(root, 'wrapped_nul_string.v')
551+
os.write_file(wrapped_nul_source, "module main
552+
553+
fn main() {
554+
println('\\400tail')
555+
}
556+
") or {
557+
panic(err)
558+
}
559+
wrapped_nul_binary := os.join_path(root, 'wrapped_nul_string')
560+
wrapped_nul_compile := cmdexec.run(v3_bin, ['-silent', '-b', 'fastc', '-o', wrapped_nul_binary,
561+
wrapped_nul_source])
562+
assert wrapped_nul_compile.exit_code == 0, wrapped_nul_compile.output
563+
wrapped_nul_c := os.read_file(wrapped_nul_binary + '.c') or { panic(err) }
564+
assert !wrapped_nul_c.contains('V_FASTC_PRINT_SELECT')
565+
wrapped_nul_run := cmdexec.run(wrapped_nul_binary, [])
566+
assert wrapped_nul_run.exit_code == 0, wrapped_nul_run.output.bytes().str()
567+
assert wrapped_nul_run.output == '\0tail\n', wrapped_nul_run.output.bytes().str()
568+
550569
assert_source := os.join_path(root, 'assert_failure.v')
551570
os.write_file(assert_source, 'module main
552571

0 commit comments

Comments
 (0)