Skip to content

Commit 5067ee7

Browse files
authored
Merge pull request #180 from huandu/bug/cond-misuse
Avoid stack overflow when Cond is misused
2 parents bb320aa + eb375d5 commit 5067ee7

File tree

4 files changed

+35
-6
lines changed

4 files changed

+35
-6
lines changed

args.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type Args struct {
1616
// The default flavor used by `Args#Compile`
1717
Flavor Flavor
1818

19+
indexBase int
1920
argValues []interface{}
2021
namedArgs map[string]int
2122
sqlNamedArgs map[string]int
@@ -47,7 +48,7 @@ func (args *Args) Add(arg interface{}) string {
4748
}
4849

4950
func (args *Args) add(arg interface{}) int {
50-
idx := len(args.argValues)
51+
idx := len(args.argValues) + args.indexBase
5152

5253
switch a := arg.(type) {
5354
case sql.NamedArg:
@@ -164,7 +165,7 @@ func (args *Args) compileNamed(ctx *argsCompileContext, format string) string {
164165
format = format[i+1:]
165166

166167
if p, ok := args.namedArgs[name]; ok {
167-
format, _ = args.compileSuccessive(ctx, format, p)
168+
format, _ = args.compileSuccessive(ctx, format, p-args.indexBase)
168169
}
169170

170171
return format
@@ -181,14 +182,17 @@ func (args *Args) compileDigits(ctx *argsCompileContext, format string, offset i
181182
format = format[i:]
182183

183184
if pointer, err := strconv.Atoi(digits); err == nil {
184-
return args.compileSuccessive(ctx, format, pointer)
185+
return args.compileSuccessive(ctx, format, pointer-args.indexBase)
185186
}
186187

187188
return format, offset
188189
}
189190

190191
func (args *Args) compileSuccessive(ctx *argsCompileContext, format string, offset int) (string, int) {
191-
if offset >= len(args.argValues) {
192+
if offset < 0 || offset >= len(args.argValues) {
193+
ctx.WriteString("/* INVALID ARG $")
194+
ctx.WriteString(strconv.Itoa(offset))
195+
ctx.WriteString(" */")
192196
return format, offset
193197
}
194198

args_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func TestArgs(t *testing.T) {
2323
cases := map[string][]interface{}{
2424
"abc ? def\n[123]": {"abc $? def", 123},
2525
"abc ? def\n[456]": {"abc $0 def", 456},
26-
"abc def\n[]": {"abc $1 def", 123},
26+
"abc /* INVALID ARG $1 */ def\n[]": {"abc $1 def", 123},
2727
"abc def \n[]": {"abc ${unknown} def ", 123},
2828
"abc $ def\n[]": {"abc $$ def", 123},
2929
"abcdef$\n[]": {"abcdef$", 123},

cond.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ const (
1111
opNOT = "NOT "
1212
)
1313

14+
const minIndexBase = 256
15+
1416
// Cond provides several helper methods to build conditions.
1517
type Cond struct {
1618
Args *Args
@@ -19,7 +21,17 @@ type Cond struct {
1921
// NewCond returns a new Cond.
2022
func NewCond() *Cond {
2123
return &Cond{
22-
Args: &Args{},
24+
Args: &Args{
25+
// Based on the discussion in #174, users may call this method to create
26+
// `Cond` for building various conditions, which is a misuse, but we
27+
// cannot completely prevent this error. To facilitate users in
28+
// identifying the issue when they make mistakes and to avoid
29+
// unexpected stackoverflows, the base index for `Args` is
30+
// deliberately set to a larger non-zero value here. This can
31+
// significantly reduce the likelihood of issues and allows for
32+
// timely error notification to users.
33+
indexBase: minIndexBase,
34+
},
2335
}
2436
}
2537

cond_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,16 @@ func TestCondExpr(t *testing.T) {
230230
a.Equal(actual, expected)
231231
}
232232
}
233+
234+
func TestCondMisuse(t *testing.T) {
235+
a := assert.New(t)
236+
237+
cond := NewCond()
238+
sb := Select("*").
239+
From("t1").
240+
Where(cond.Equal("a", 123))
241+
sql, args := sb.Build()
242+
243+
a.Equal(sql, "SELECT * FROM t1 WHERE /* INVALID ARG $256 */")
244+
a.Equal(args, nil)
245+
}

0 commit comments

Comments
 (0)