Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unsubtyping fuzz bug #6565

Closed
kripken opened this issue Apr 30, 2024 · 1 comment
Closed

Unsubtyping fuzz bug #6565

kripken opened this issue Apr 30, 2024 · 1 comment

Comments

@kripken
Copy link
Member

kripken commented Apr 30, 2024

$ wasm-opt x.wat -all --type-ssa -O2 --unsubtyping --roundtrip
[wasm-validator error in module] struct.new operand 0 must have proper type, on 
(struct.new $84
 (global.get $global$4)
)
Fatal: error after opts

After the unsubtyping pass the IR passes validation but is incorrect in some subtle way, which causes errors in roundtripping and other operations (e.g. --precompute instead of --roundtrip will also error, on some internal assertion).

I'd guess this is some subtle bug of Unsubtyping and/or the Type canonicalization logic. @tlively I think you know that code best, can you take a look?

(module
 (rec
  (type $0 (struct (field (ref $3))))
  (type $1 (sub (struct (field (ref null $52)) (field (mut i8)))))
  (type $2 (sub final $1 (struct (field (ref $52)) (field (mut i8)) (field (ref $0)))))
  (type $3 (struct (field (mut i32)) (field i32) (field (ref null $74))))
  (type $4 (sub (struct )))
  (type $5 (sub $4 (struct (field (ref $4)) (field (ref $85)))))
  (type $6 (sub $5 (struct (field (ref $4)) (field (ref $85)) (field (ref $54)) (field (mut i32)) (field (ref $54)))))
  (type $7 (sub final $6 (struct (field (ref $4)) (field (ref $85)) (field (ref $54)) (field (mut i32)) (field (ref $54)) (field (mut i32)))))
  (type $8 (func (param (ref $6)) (result (ref $55))))
  (type $9 (func (param (ref $29)) (result (ref $18))))
  (type $10 (sub $5 (struct (field (ref $4)) (field (ref $85)) (field (mut (ref $83))) (field (mut i32)))))
  (type $11 (sub final $10 (struct (field (ref $4)) (field (ref $85)) (field (mut (ref $83))) (field (mut i32)) (field (mut i32)))))
  (type $12 (func (result (ref $56))))
  (type $13 (func (param (ref $73))))
  (type $14 (func (param (ref $73)) (result (ref null $74))))
  (type $15 (func (param (ref null $82) (ref null $82) i32 i32 i32)))
  (type $16 (func (param (ref $38) (ref null $92)) (result (ref null $92))))
  (type $17 (func (param (ref $70) (ref null $18))))
  (type $18 (sub (struct (field (ref $93)) (field (ref $79)) (field (mut i32)))))
  (type $19 (sub final $18 (struct (field (ref $93)) (field (ref $94)) (field (mut i32)) (field i32))))
  (type $20 (func (param i32) (result (ref null $19))))
  (type $21 (func (param i32) (result (ref $92))))
  (type $22 (func (param (ref $5)) (result (ref $18))))
  (type $23 (func (param (ref $5)) (result i32)))
  (type $24 (func (param (ref $5)) (result (ref null $18))))
  (type $25 (func (param (ref $5) (ref null $18)) (result i32)))
  (type $26 (func (param (ref $5))))
  (type $27 (func (param (ref $38)) (result (ref null $92))))
  (type $28 (struct (field (ref null $92))))
  (type $29 (sub $4 (struct (field (ref $84)))))
  (type $30 (sub final $29 (struct (field (ref $84)) (field (ref $38)))))
  (type $31 (func (param (ref $38))))
  (type $32 (sub final $18 (struct (field (ref $93)) (field (ref $94)) (field (mut i32)) (field f64))))
  (type $33 (sub final $18 (struct (field (ref $93)) (field (ref $94)) (field (mut i32)))))
  (type $34 (func (param (ref null $73) i32) (result (ref $66))))
  (type $35 (func (param (ref $92) (ref $83))))
  (type $36 (func (param externref) (result (ref null $56))))
  (type $37 (func (param (ref $56)) (result (ref $64))))
  (type $38 (sub (struct (field (ref $4)) (field (ref $78)) (field (mut (ref null $30))) (field (mut i32)) (field (mut i32)) (field (mut (ref $83))) (field (mut i32)))))
  (type $39 (sub final $38 (struct (field (ref $4)) (field (ref $78)) (field (mut (ref null $30))) (field (mut i32)) (field (mut i32)) (field (mut (ref $83))) (field (mut i32)) (field (ref $41)))))
  (type $40 (sub $18 (struct (field (ref $93)) (field (ref $94)) (field (mut i32)) (field i32) (field (ref null $92)) (field (mut (ref null $40))) (field (mut (ref null $92))))))
  (type $41 (sub final $40 (struct (field (ref $93)) (field (ref $94)) (field (mut i32)) (field i32) (field (ref null $92)) (field (mut (ref null $40))) (field (mut (ref null $92))) (field (mut (ref null $41))) (field (mut (ref null $41))))))
  (type $42 (sub final $18 (struct (field (ref $93)) (field (ref $80)) (field (mut i32)) (field (ref $39)) (field (mut (ref null $41))) (field (mut (ref null $41))))))
  (type $43 (sub final $18 (struct (field (ref $93)) (field (ref $80)) (field (mut i32)) (field (ref $38)) (field (mut (ref null $40))) (field (mut (ref null $40))) (field (mut i32)))))
  (type $44 (func (param f64) (result (ref null $92))))
  (type $45 (func (param i32) (result (ref null $92))))
  (type $46 (func (param (ref $76)) (result (ref null $92))))
  (type $47 (func (param (ref $92) (ref $92)) (result (ref $92))))
  (type $48 (func (param (ref $70) (ref $92) i32 i32)))
  (type $49 (func (param (ref $70) (ref null $92))))
  (type $50 (func (param (ref $70))))
  (type $51 (func (param (ref $70) i32)))
  (type $52 (sub final $1 (struct (field nullref) (field (mut i8)) (field (ref $3)))))
  (type $53 (func (param (ref $1))))
  (type $54 (struct (field (mut (ref null $54))) (field (mut (ref null $54))) (field (mut (ref null $92)))))
  (type $55 (sub final $18 (struct (field (ref $93)) (field (ref $80)) (field (mut i32)) (field (ref $6)) (field (mut i32)) (field (mut (ref null $54))) (field (mut (ref null $54))))))
  (type $56 (sub $18 (struct (field (ref $93)) (field (ref $94)) (field (mut i32)) (field (mut (ref null $64))) (field (mut (ref null $92))))))
  (type $57 (sub $56 (struct (field (ref $93)) (field (ref $94)) (field (mut i32)) (field (mut (ref null $64))) (field (mut (ref null $92))))))
  (type $58 (sub final $57 (struct (field (ref $93)) (field (ref $94)) (field (mut i32)) (field (mut (ref null $64))) (field (mut (ref null $92))))))
  (type $59 (func (param (ref $18))))
  (type $60 (func (param (ref $18)) (result (ref null $18))))
  (type $61 (sub final $18 (struct (field (ref $93)) (field (ref $80)) (field (mut i32)) (field (ref $10)) (field (mut i32)) (field (mut i32)))))
  (type $62 (func (param (ref $56) (ref $64))))
  (type $63 (func (result i64)))
  (type $64 (sub final $18 (struct (field (ref $93)) (field (ref $79)) (field (mut i32)) (field externref))))
  (type $65 (func (param (ref null $90) i32 (ref null $90) i32 i32)))
  (type $66 (struct (field (mut f64)) (field (ref $67))))
  (type $67 (struct (field (ref $77))))
  (type $68 (sub final $18 (struct (field (ref $93)) (field (ref $79)) (field (mut i32)) (field (mut (ref null $70))) (field (mut (ref null $92))))))
  (type $69 (func (param (ref $18)) (result (ref $76))))
  (type $70 (struct (field (mut i32)) (field (mut (ref null $90)))))
  (type $71 (func (param (ref $18)) (result (ref null $92))))
  (type $72 (func (param (ref $18)) (result i32)))
  (type $73 (struct (field (mut (ref null $74)))))
  (type $74 (struct (field (ref $82))))
  (type $75 (sub final $18 (struct (field (ref $93)) (field (ref $80)) (field (mut i32)))))
  (type $76 (struct (field (mut (ref null $92)))))
  (type $77 (array (mut f64)))
  (type $78 (struct (field (ref $88))))
  (type $79 (sub (struct (field structref))))
  (type $80 (sub final $79 (struct (field (ref $81)))))
  (type $81 (struct (field (ref $72)) (field (ref $60)) (field (ref $59))))
  (type $82 (array (mut i32)))
  (type $83 (struct (field (ref $89))))
  (type $84 (struct (field (ref $4))))
  (type $85 (struct (field (ref $87)) (field (ref $86))))
  (type $86 (struct (field (ref $24)) (field (ref $22)) (field (ref $24))))
  (type $87 (struct (field (ref $25)) (field (ref $23))))
  (type $88 (struct (field (ref $27))))
  (type $89 (array (mut (ref null $18))))
  (type $90 (struct (field (ref $91))))
  (type $91 (array (mut i16)))
  (type $92 (sub final $18 (struct (field (ref $93)) (field (ref $94)) (field (mut i32)) (field (mut i32)) (field (ref string)))))
  (type $93 (struct (field (ref $69)) (field (ref $72)) (field (ref $71))))
  (type $94 (sub final $79 (struct (field (ref $4)))))
 )
 (rec
  (type $38_1 (sub $38 (struct (field (ref $4)) (field (ref $78)) (field (mut (ref null $30))) (field (mut i32)) (field (mut i32)) (field (mut (ref $83))) (field (mut i32)))))
  (type $4_2 (sub $4 (struct )))
  (type $4_3 (sub $4 (struct )))
  (type $4_4 (sub $4 (struct )))
 )
 (type $95 (func))
 (global $global$0 (ref $88) (struct.new $88
  (ref.func $2)
 ))
 (global $global$1 (ref $4_2) (struct.new_default $4_2))
 (global $global$3 (ref $83) (struct.new $83
  (array.new_default $89
   (i32.const 0)
  )
 ))
 (global $global$4 (ref $4_3) (struct.new_default $4_3))
 (global $global$5 (ref $78) (struct.new $78
  (struct.new $88
   (ref.func $2)
  )
 ))
 (global $global$6 (ref $4_4) (struct.new_default $4_4))
 (global $global$7 (ref $78) (struct.new $78
  (struct.new $88
   (ref.func $2)
  )
 ))
 (global $global$8 (ref $29) (struct.new $29
  (struct.new $84
   (global.get $global$4)
  )
 ))
 (export "prepareForRunOnce" (func $0))
 (func $0 (type $95) (; has Stack IR ;)
  (local $0 (ref null $41))
  (call $1
   (struct.new $38_1
    (global.get $global$1)
    (global.get $global$7)
    (ref.null none)
    (i32.const 0)
    (i32.const 0)
    (global.get $global$3)
    (i32.const 0)
   )
  )
  (call $1
   (struct.new $39
    (global.get $global$6)
    (global.get $global$5)
    (ref.null none)
    (i32.const 0)
    (i32.const 0)
    (global.get $global$3)
    (i32.const 0)
    (ref.as_non_null
     (local.get $0)
    )
   )
  )
  (unreachable)
 )
 (func $1 (type $31) (; has Stack IR ;) (param $0 (ref $38))
  (if
   (ref.eq
    (struct.get $84 0
     (struct.get $29 0
      (if (result (ref $29))
       (ref.eq
        (struct.get $78 0
         (struct.get $38 1
          (local.get $0)
         )
        )
        (global.get $global$0)
       )
       (then
        (global.get $global$8)
       )
       (else
        (unreachable)
       )
      )
     )
    )
    (global.get $global$4)
   )
   (then
    (unreachable)
   )
  )
  (unreachable)
 )
 (func $2 (type $27) (; has Stack IR ;) (param $0 (ref $38)) (result (ref null $92))
  (unreachable)
 )
)
tlively added a commit that referenced this issue May 1, 2024
When GlobalRefining refines the type of a global, it updates the type of
corresponding GlobalGet expressions, then runs ReFinalize to propagate the
refined types. However, it only performed these updates in function bodies,
leaving stale types on GlobalGet expressions in constant initializers. This bug
was not easily caught because the validator did not check that `GlobalGet` types
actually match the types of the corresponding globals.

Fix the validator to check the types of `GlobalGet` expressions and fix
GlobalRefining to properly update constant initializers.

Fixes #6565.
@tlively
Copy link
Member

tlively commented May 17, 2024

Fixed by #6603

@tlively tlively closed this as completed May 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants