jsgen: cannot assign unsafe nil values (fix #24407, #24436) (#24458)

This commit is contained in:
Gonzalo Chumillas 2025-05-11 08:57:28 +01:00 committed by GitHub
parent 3f76b69165
commit 27829d56cd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 91 additions and 2 deletions

View File

@ -329,6 +329,20 @@ fn (mut g JsGen) gen_builtin_prototype(c BuiltinPrototypeConfig) {
g.writeln('function ${c.typ_name}__eq(self,other) { return ${c.eq}; } ') g.writeln('function ${c.typ_name}__eq(self,other) { return ${c.eq}; } ')
} }
fn (mut g JsGen) gen_nil_const() {
g.writeln('const nil__ = new \$ref(new nil());')
g.gen_builtin_prototype(
typ_name: 'nil'
val_name: 'str'
default_value: 'new String("&nil")'
constructor: 'this.str = str.toString(); this.len = this.str.length'
value_of: 'null'
to_string: '"&nil"'
eq: 'new bool(self.valueOf() === other.valueOf())'
to_jsval: 'null'
)
}
// generate builtin type definitions, used for casting and methods. // generate builtin type definitions, used for casting and methods.
fn (mut g JsGen) gen_builtin_type_defs() { fn (mut g JsGen) gen_builtin_type_defs() {
g.inc_indent() g.inc_indent()

View File

@ -143,6 +143,7 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) stri
graph.add(g.file.mod.name, imports) graph.add(g.file.mod.name, imports)
// builtin types // builtin types
if g.file.mod.name == 'builtin' && !g.generated_builtin { if g.file.mod.name == 'builtin' && !g.generated_builtin {
g.gen_nil_const()
g.gen_builtin_type_defs() g.gen_builtin_type_defs()
g.writeln('Object.defineProperty(array.prototype,"len", { get: function() {return new int(this.arr.arr.length);}, set: function(l) { this.arr.arr.length = l.valueOf(); } }); ') g.writeln('Object.defineProperty(array.prototype,"len", { get: function() {return new int(this.arr.arr.length);}, set: function(l) { this.arr.arr.length = l.valueOf(); } }); ')
g.writeln('Object.defineProperty(map.prototype,"len", { get: function() {return new int(this.length);}, set: function(l) { } }); ') g.writeln('Object.defineProperty(map.prototype,"len", { get: function() {return new int(this.length);}, set: function(l) { } }); ')
@ -965,7 +966,7 @@ fn (mut g JsGen) expr(node_ ast.Expr) {
g.gen_lock_expr(node) g.gen_lock_expr(node)
} }
ast.Nil { ast.Nil {
g.write('null') g.write('nil__')
} }
ast.NodeError {} ast.NodeError {}
ast.None { ast.None {
@ -1345,7 +1346,7 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
g.expr(left) g.expr(left)
} }
is_ptr := stmt.op == .assign && stmt.left_types[i].is_ptr() && !array_set is_ptr := stmt.op == .assign && stmt.right_types[i].is_ptr() && !array_set
if is_ptr { if is_ptr {
g.write('.val') g.write('.val')
} }

View File

@ -0,0 +1,74 @@
struct Bar {
value int
}
struct Foo1 {
mut:
name &string
}
struct Foo2 {
mut:
name ?&string
}
struct Foo3 {
mut:
bar &Bar
}
fn main() {
// Basic test of assigning nil to a string pointer
mut str := 'hi!'
mut str_ptr := &str
unsafe {
str_ptr = nil
}
println(str_ptr) // should print '&nil'
assert str_ptr == unsafe { nil }
// Test initializing a pointer field with nil
f1 := Foo1{
name: unsafe { nil }
}
assert f1.name == unsafe { nil }
// Test assigning nil to an optional pointer field
mut f2 := Foo2{}
unsafe {
f2.name = nil
}
if f2.name != none {
assert f2.name == unsafe { nil }
} else {
assert false
}
// Test assigning nil to a struct pointer
mut f3 := &Foo2{}
unsafe {
f3 = nil
}
assert f3 == unsafe { nil }
// Test with custom struct fields
mut f4 := Foo3{
bar: &Bar{42}
}
unsafe {
f4.bar = nil
}
assert f4.bar == unsafe { nil }
// Test with nil pointers in arrays
mut ptrs := []&string{len: 3, init: unsafe { nil }}
p0, p1 := 'hello', 'world'
ptrs[0] = &p0
ptrs[1] = &p1
unsafe {
ptrs[2] = nil
}
assert ptrs[0] != unsafe { nil }
assert ptrs[1] != unsafe { nil }
assert ptrs[2] == unsafe { nil }
}