Skip to content

Commit

Permalink
Don't crash when freezing a struct with a circular reference
Browse files Browse the repository at this point in the history
The Freeze method needs to check for a `frozen` condition just like all the other types of values, otherwise there can be infinite recursion.

The test that I'm adding here would crash without the fix.
  • Loading branch information
oprypin committed Nov 25, 2024
1 parent d4d7611 commit 85ea1c8
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 2 deletions.
8 changes: 6 additions & 2 deletions starlarkstruct/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ func FromStringDict(constructor starlark.Value, d starlark.StringDict) *Struct {
type Struct struct {
constructor starlark.Value
entries entries // sorted by name
frozen bool
}

// Default is the default constructor for structs.
Expand Down Expand Up @@ -172,8 +173,11 @@ func (s *Struct) Hash() (uint32, error) {
return x, nil
}
func (s *Struct) Freeze() {
for _, e := range s.entries {
e.value.Freeze()
if !s.frozen {
s.frozen = true
for _, e := range s.entries {
e.value.Freeze()
}
}
}

Expand Down
9 changes: 9 additions & 0 deletions starlarkstruct/testdata/struct.star
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,12 @@ assert.eq(alice + bob, person(age = 50, city = "NYC", name = "bob")) # not comm
assert.fails(lambda : alice + 1, "struct \\+ int")
assert.eq(http + http, http)
assert.fails(lambda : http + bob, "different constructors: hostport \\+ person")

# Check that a struct with a circular reference doesn't crash when it gets frozen.
def struct_with_a_circular_reference():
foo = lambda: print(self)
self = struct(foo = foo)
return self

# A top-level assigment is what causes this value to be frozen at the end of the load.
toplevel_struct_with_a_circular_reference = struct_with_a_circular_reference()

0 comments on commit 85ea1c8

Please sign in to comment.