shader: Forbid assigning to special variables

This commit is contained in:
Hajime Hoshi 2020-09-13 04:59:04 +09:00
parent 5e15ebf580
commit a5af597594
2 changed files with 83 additions and 3 deletions

View File

@ -45,7 +45,7 @@ func (cs *compileState) parseStmt(block *block, fname string, stmt ast.Stmt, inP
return nil, false return nil, false
} }
ss, ok := cs.assign(block, stmt.Pos(), stmt.Lhs, stmt.Rhs, true) ss, ok := cs.assign(block, fname, stmt.Pos(), stmt.Lhs, stmt.Rhs, inParams, true)
if !ok { if !ok {
return nil, false return nil, false
} }
@ -55,7 +55,7 @@ func (cs *compileState) parseStmt(block *block, fname string, stmt ast.Stmt, inP
cs.addError(stmt.Pos(), fmt.Sprintf("single-value context and multiple-value context cannot be mixed")) cs.addError(stmt.Pos(), fmt.Sprintf("single-value context and multiple-value context cannot be mixed"))
return nil, false return nil, false
} }
ss, ok := cs.assign(block, stmt.Pos(), stmt.Lhs, stmt.Rhs, false) ss, ok := cs.assign(block, fname, stmt.Pos(), stmt.Lhs, stmt.Rhs, inParams, false)
if !ok { if !ok {
return nil, false return nil, false
} }
@ -486,7 +486,7 @@ func (cs *compileState) parseStmt(block *block, fname string, stmt ast.Stmt, inP
return stmts, true return stmts, true
} }
func (cs *compileState) assign(block *block, pos token.Pos, lhs, rhs []ast.Expr, define bool) ([]shaderir.Stmt, bool) { func (cs *compileState) assign(block *block, fname string, pos token.Pos, lhs, rhs []ast.Expr, inParams []variable, define bool) ([]shaderir.Stmt, bool) {
var stmts []shaderir.Stmt var stmts []shaderir.Stmt
var rhsExprs []shaderir.Expr var rhsExprs []shaderir.Expr
var rhsTypes []shaderir.Type var rhsTypes []shaderir.Type
@ -543,6 +543,28 @@ func (cs *compileState) assign(block *block, pos token.Pos, lhs, rhs []ast.Expr,
if l[0].Type == shaderir.Blank { if l[0].Type == shaderir.Blank {
continue continue
} }
var isAssignmentForbidden func(e *shaderir.Expr) bool
isAssignmentForbidden = func(e *shaderir.Expr) bool {
switch e.Type {
case shaderir.UniformVariable:
return true
case shaderir.LocalVariable:
if fname == cs.vertexEntry || fname == cs.fragmentEntry {
return e.Index < len(inParams)
}
case shaderir.FieldSelector:
return isAssignmentForbidden(&e.Exprs[0])
case shaderir.Index:
return isAssignmentForbidden(&e.Exprs[0])
}
return false
}
if isAssignmentForbidden(&l[0]) {
cs.addError(pos, fmt.Sprintf("a uniform variable cannot be assigned"))
return nil, false
}
allblank = false allblank = false
if r[0].Type == shaderir.NumberExpr { if r[0].Type == shaderir.NumberExpr {

View File

@ -448,3 +448,61 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
} }
} }
} }
func TestShaderForbidAssigningSpecialVariables(t *testing.T) {
if _, err := NewShader([]byte(`package main
var U vec4
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
U = vec4(0)
return vec4(0)
}
`)); err == nil {
t.Errorf("error must be non-nil but was nil")
}
if _, err := NewShader([]byte(`package main
var U vec4
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
U.x = 0
return vec4(0)
}
`)); err == nil {
t.Errorf("error must be non-nil but was nil")
}
if _, err := NewShader([]byte(`package main
var U [2]vec4
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
U[0] = vec4(0)
return vec4(0)
}
`)); err == nil {
t.Errorf("error must be non-nil but was nil")
}
if _, err := NewShader([]byte(`package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
texCoord = vec2(0)
return vec4(0)
}
`)); err == nil {
t.Errorf("error must be non-nil but was nil")
}
if _, err := NewShader([]byte(`package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
texCoord.x = 0
return vec4(0)
}
`)); err == nil {
t.Errorf("error must be non-nil but was nil")
}
}