Skip to content

fix(util/gconv): gconv unsafe str to bytes - #4600

Merged
hailaz merged 1 commit into
gogf:masterfrom
liov:master
Jan 15, 2026
Merged

fix(util/gconv): gconv unsafe str to bytes#4600
hailaz merged 1 commit into
gogf:masterfrom
liov:master

Conversation

@liov

@liov liov commented Jan 9, 2026

Copy link
Copy Markdown
Contributor

The gconv.UnsafeStrToBytes function has been updated to use the Go 1.20+ safe approach, as the previous implementation could cause a panic in certain scenarios.

For example, when an HTTP request header specifies Content-Type: application/x-www-form-urlencoded, but the actual request body contains JSON data, the following code attempts to detect and handle this case:

if !gregex.IsMatchString(`^[\w\-\[\]]+$`, name) && len(r.PostForm) == 1 {
    // It might be JSON/XML content.
    if s := gstr.Trim(name + strings.Join(values, " ")); len(s) > 0 {
        if s[0] == '{' && s[len(s)-1] == '}' || s[0] == '<' && s[len(s)-1] == '>' {
            r.bodyContent = gconv.UnsafeStrToBytes(s)
            params = ""
            break
        }
    }
}

However, after this assignment, bodyContent ends up with a capacity (cap) of 0. slice operations like [:] perform stricter validation and will panic if the capacity is 0. This causes a panic in functions such as:

body = bytes.TrimSpace(body)

func TrimSpace(s []byte) []byte {
    ...
    return s[start:stop] // panic here due to cap == 0
}

The capacity (cap) of the slice returned by directly calling this function is unpredictable, as it depends on the adjacent memory layout. However, within the framework, this causes issues—likely because, starting from Go 1.22, the standard library's parseForm implementation consistently appends a trailing zero byte after the string data in memory.
This PR fix the problem.


gconv unsafe str to bytes 改用 go1.20 后的写法,之前的写法在某些场景下会 panic
例如 http 请求头为application/x-www-form-urlencoded,实际的 body 为 json,
经过解析后

	if !gregex.IsMatchString(`^[\w\-\[\]]+$`, name) && len(r.PostForm) == 1 {
					// It might be JSON/XML content.
					if s := gstr.Trim(name + strings.Join(values, " ")); len(s) > 0 {
						if s[0] == '{' && s[len(s)-1] == '}' || s[0] == '<' && s[len(s)-1] == '>' {
							r.bodyContent = gconv.UnsafeStrToBytes(s)
							params = ""
							break
						}
					}
				}

bodyContent的 cap 为 0,由于切片操作[:]会校验 cap 为 0,会直接 panic

body = bytes.TrimSpace(body)

---
func TrimSpace(s []byte) []byte {
...
return s[start:stop] // panic
}

直接使用这个函数得到的 cap 会是随机的, 因为跟的内存不确定,但是在框架中有问题,估计是1.22 后标准库parseForm 的时候后面内存固定跟了个 0
该 PR 修复这个问题

@gqcn gqcn added the awesome It's awesome! We keep watching. label Jan 13, 2026

@gqcn gqcn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm

@hailaz
hailaz merged commit 1ed4e02 into gogf:master Jan 15, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awesome It's awesome! We keep watching.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants