gogf / gf

GoFrame is a modular, powerful, high-performance and enterprise-class application development framework of Golang.
https://goframe.org
MIT License
11.8k stars 1.61k forks source link

net/ghttp: The new version of nested field parsing is invalid #3789

Closed shuqingzai closed 2 months ago

shuqingzai commented 2 months ago

Go version

go version go1.21.13 darwin/amd64

GoFrame version

2.7.3

Can this bug be reproduced with the latest release?

Option Yes

What did you do?

2.7.2 以下代码运行正常,但是 2.7.3 解析请求参数错误

config.yaml

server:
  address:     ":8199"
  openapiPath: "/api.json"
  swaggerPath: "/swagger"

main.go

package main

import (
    "context"

    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/net/ghttp"
)

type ItemInput struct {
    ItemFirst
}

type ItemSecondThird struct {
    // SecondID ...
    SecondID uint64 `json:"secondId,string" dc:"SecondID" v:"required"`
    // ThirdID ...
    ThirdID uint64 `json:"thirdId,string" dc:"ThirdID" v:"required"`
}

type ItemFirst struct {
    // ID ID
    ID uint64 `json:"id,string" dc:"ID"`

    ItemSecondThird
}

type HelloReq struct {
    g.Meta `path:"/hello" method:"GET"`

    ItemInput
}
type HelloRes struct {
    ItemInput
}

type Hello struct{}

func (Hello) Say(ctx context.Context, req *HelloReq) (res *HelloRes, err error) {
    g.Log().Debugf(ctx, `receive say: %+v`, req)
    res = &HelloRes{
        ItemInput: req.ItemInput,
    }
    return
}

func main() {
    s := g.Server()
    s.Use(ghttp.MiddlewareHandlerResponse)
    s.Group("/", func(group *ghttp.RouterGroup) {
        group.Bind(
            new(Hello),
        )
    })
    s.Run()
}

What did you see happen?

分别使用不同版本启动服务,得到不同的响应结果

使用请求

curl -X GET 'http://127.0.0.1:8199/hello?id=&secondId=157889372459384832&thirdId=157889372459384833' \
-H 'Host: 127.0.0.1:8199'
  1. 2.7.2

正确解析请求参数 secondId

{"code":0,"message":"","data":{"id":"0","secondId":"157889372459384832","thirdId":"157889372459384833"}}
  1. 2.7.3

没有正确解析请求参数 secondId ,甚至说试多几次,有时候 thirdId 的值会被赋值到 secondId ,值被缓存??

{"code":0,"message":"","data":{"id":"0","secondId":"0","thirdId":"157889372459384833"}}

What did you expect to see?

参数被正确解析

wln32 commented 2 months ago

@shuqingzai @gqcn 目前已经找到原因了,竟是slice扩容机制导致的,这个bug非常有意思 image

下面是我打印不同字段的切片的详细信息 可以看到最后两个字段,切片的地址是相同的,在before的时候,也就是调用structInfo.AddField之前,由于len<cap, SecondID扩容之后变成[1 0 1 0],由于ThirdID和SecondID的引用的相同的地址,ThirdID扩容切片会变成[1 0 1 1], 覆盖了SecondID的索引信息,导致参数解析失败 image

@shuqingzai 如果对2.7.3没有特别需求,暂时退到2.7.2版本

Issues-translate-bot commented 2 months ago

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


@shuqingzai @gqcn The real reason has been found so far. It is actually caused by the slice expansion mechanism. This bug is very interesting! [image](https://private-user-images.githubusercontent.com/49137144/369721902-3d6cb923-473d -4955-8a86-7c1276e64547.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..B7wWhBcWgWKUIlPoO0_AsBflR8q8hSqo83Fis5mP1ec)

Below is the detailed information of the slices I printed with different fields. You can see the last two fields. The addresses of the slices are the same. Before, that is, before calling structInfo.AddField, because len<cap, SecondID becomes [1 0 1 0], since ThirdID and SecondID refer to the same address, the expansion of ThirdID will slice it into [1 0 1 1], covering the index information of SecondID, causing parameter parsing to fail! [image](https: //private-user-images.githubusercontent.com/49137144/369721747-6325acd7-f880-48e6-ae6a-be834d983041.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..1iayo14olicpDtuLhPQ8 162UqscD2aXvQaGLPnbXEOc)

@shuqingzai If there is no special need for 2.7.3, we will temporarily fall back to version 2.7.2