Skip to content

Commit e97b2b0

Browse files
committed
interp: avoid the last panics which can be triggered by users
That is, panics due to unsupported features, rather than bugs in our Go code. Add tests as well. Fixes #1305.
1 parent f299f47 commit e97b2b0

6 files changed

Lines changed: 33 additions & 10 deletions

File tree

interp/builtin.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,7 @@ func (r *Runner) builtin(ctx context.Context, pos syntax.Pos, name string, args
791791
case "-o":
792792
posixOpts = true
793793
case "-p", "-q":
794-
panic(fmt.Sprintf("unhandled shopt flag: %s", flag))
794+
return failf(2, "shopt: unsupported option %q\n", flag)
795795
default:
796796
return failf(2, "shopt: invalid option %q\n", flag)
797797
}
@@ -988,7 +988,7 @@ func (r *Runner) builtin(ctx context.Context, pos syntax.Pos, name string, args
988988
r.setVar(arrayName, vr)
989989

990990
default:
991-
return failf(2, "%s: unimplemented builtin\n", name)
991+
return failf(2, "%s: unsupported builtin\n", name)
992992
}
993993
return exit
994994
}

interp/interp_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1960,6 +1960,15 @@ var runTests = []runTest{
19601960
"mkdir d; [ -r d ] && echo r; [ -w d ] && echo w; [ -x d ] && echo x",
19611961
"r\nw\nx\n",
19621962
},
1963+
{
1964+
"test -N a",
1965+
"unsupported unary test op: -N\nexit status 1 #IGNORE",
1966+
},
1967+
{
1968+
"test -? a",
1969+
// TODO: this error message should refer to `-?`
1970+
"1:1: not a valid test operator: `a`\n1:1: a must be followed by a word\nexit status 2 #JUSTERR",
1971+
},
19631972
{
19641973
"[ -s a ] && echo x; echo body >a; [ -s a ] && echo y",
19651974
"y\n",
@@ -2499,6 +2508,14 @@ done <<< 2`,
24992508
"touch a ab abB Ac Ad; shopt -s nocaseglob; echo *b",
25002509
"ab abB\n",
25012510
},
2511+
{
2512+
"shopt -p",
2513+
"shopt: unsupported option \"-p\"\nexit status 2 #IGNORE",
2514+
},
2515+
{
2516+
"shopt -q",
2517+
"shopt: unsupported option \"-q\"\nexit status 2 #IGNORE",
2518+
},
25022519

25032520
// IFS
25042521
{`echo -n "$IFS"`, " \t\n"},

interp/os_notunix.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ func (r *Runner) access(ctx context.Context, path string, mode uint32) error {
4747
// doesn't have the concept of a file owner, just ACLs, and it's unclear how
4848
// to map the one to the other.
4949
func (r *Runner) unTestOwnOrGrp(ctx context.Context, op syntax.UnTestOperator, x string) bool {
50-
panic(fmt.Sprintf("unhandled unary test op: %v", op))
50+
r.errf("unsupported unary test op: %v\n", op)
51+
return false
5152
}
5253

5354
// waitStatus is a no-op on plan9 and windows.

interp/runner.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ func (r *Runner) fillExpandConfig(ctx context.Context) {
143143
os.Remove(path)
144144
}()
145145
default:
146-
panic(fmt.Sprintf("unsupported process substitution operator: %q", ps.Op))
146+
// Should only happen if we forgot a case above.
147+
panic(fmt.Sprintf("unexpected process substitution operator: %q", ps.Op))
147148
}
148149
r2.stmts(ctx, ps.Stmts)
149150
r2.exit.exiting = false // subshells don't exit the parent shell
@@ -811,6 +812,7 @@ func (r *Runner) cmd(ctx context.Context, cm syntax.Command) {
811812
r.outf(format, "user", elapsedString(0, cm.PosixFormat))
812813
r.outf(format, "sys", elapsedString(0, cm.PosixFormat))
813814
default:
815+
// Should only happen if we forgot a case above.
814816
r.errf("unhandled command node: %T\n", cm)
815817
r.exit.code = 1
816818
}

interp/test.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ func (r *Runner) binTest(ctx context.Context, op syntax.BinTestOperator, x, y st
119119
case syntax.TsAfter:
120120
return x > y
121121
default:
122-
panic(fmt.Sprintf("unsupported binary test operator: %q", op))
122+
// Should only happen if we forgot a case above.
123+
panic(fmt.Sprintf("unexpected binary test operator: %q", op))
123124
}
124125
}
125126

@@ -164,9 +165,9 @@ func (r *Runner) unTest(ctx context.Context, op syntax.UnTestOperator, x string)
164165
return r.statMode(ctx, x, os.ModeSetuid)
165166
case syntax.TsGIDSet:
166167
return r.statMode(ctx, x, os.ModeSetgid)
167-
// case syntax.TsGrpOwn:
168-
// case syntax.TsUsrOwn:
169-
// case syntax.TsModif:
168+
case syntax.TsModif:
169+
r.errf("unsupported unary test op: %v\n", op)
170+
return false
170171
case syntax.TsRead:
171172
return r.access(ctx, r.absPath(x), access_R_OK) == nil
172173
case syntax.TsWrite:
@@ -212,6 +213,7 @@ func (r *Runner) unTest(ctx context.Context, op syntax.UnTestOperator, x string)
212213
case syntax.TsUsrOwn, syntax.TsGrpOwn:
213214
return r.unTestOwnOrGrp(ctx, op, x)
214215
default:
215-
panic(fmt.Sprintf("unhandled unary test op: %v", op))
216+
// Should only happen if we forgot a case above.
217+
panic(fmt.Sprintf("unexpected unary test op: %v", op))
216218
}
217219
}

interp/vars.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,8 @@ func (r *Runner) assignVal(name string, prev expand.Variable, as *syntax.Assign,
417417
case expand.Associative:
418418
// TODO
419419
default:
420-
panic(fmt.Sprintf("unhandled conversion of kind %d", prev.Kind))
420+
// Should only happen if we forgot a case above.
421+
panic(fmt.Sprintf("unexpected conversion of kind %d", prev.Kind))
421422
}
422423
return name, prev
423424
}

0 commit comments

Comments
 (0)