mirror of https://github.com/google/oss-fuzz.git
125 lines
2.5 KiB
Go
125 lines
2.5 KiB
Go
// Copyright 2015 go-fuzz project authors. All rights reserved.
|
|
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
|
|
|
package multipart
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"mime/multipart"
|
|
"net/textproto"
|
|
"runtime"
|
|
|
|
"github.com/dvyukov/go-fuzz-corpus/fuzz"
|
|
)
|
|
|
|
type Part struct {
|
|
hdr textproto.MIMEHeader
|
|
data []byte
|
|
}
|
|
|
|
func Fuzz(data []byte) int {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
}
|
|
runtime.GC()
|
|
}()
|
|
const boundary = "dfhjksd23f43242f43fv4b4g2g2g23vf2"
|
|
{
|
|
r := multipart.NewReader(bytes.NewReader(data), boundary)
|
|
f, err := r.ReadForm(1 << 20)
|
|
if err == nil {
|
|
f.RemoveAll()
|
|
}
|
|
}
|
|
fmt.Println("Creating multipart reader")
|
|
r := multipart.NewReader(bytes.NewReader(data), boundary)
|
|
fmt.Println("Reading")
|
|
var parts []Part
|
|
for {
|
|
p, err := r.NextPart()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
p.FileName()
|
|
p.FormName()
|
|
pdata, err := ioutil.ReadAll(p)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
p.Close()
|
|
// The parser is loose here.
|
|
// If data contains \n followed by boundary (but without \r),
|
|
// it parses it as part body. However, when it serializes it back,
|
|
// it writes \r\n followed by boundary, which becomes new part separator.
|
|
if bytes.Contains(pdata, []byte(boundary)) {
|
|
continue
|
|
}
|
|
parts = append(parts, Part{p.Header, pdata})
|
|
}
|
|
if len(parts) == 0 {
|
|
return 0
|
|
}
|
|
|
|
fmt.Println("Creating new writer")
|
|
buf := new(bytes.Buffer)
|
|
w := multipart.NewWriter(buf)
|
|
w.SetBoundary(boundary)
|
|
fmt.Println("Writing data")
|
|
for _, p := range parts {
|
|
pw, err := w.CreatePart(p.hdr)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
n, err := pw.Write(p.data)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
if n != len(p.data) {
|
|
panic("partial write")
|
|
}
|
|
}
|
|
w.Close()
|
|
|
|
fmt.Println("Time to compare")
|
|
data1 := buf.Bytes()
|
|
r1 := multipart.NewReader(buf, boundary)
|
|
var parts1 []Part
|
|
for {
|
|
p, err := r1.NextPart()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
fmt.Printf("parts0: %+v\n", parts)
|
|
fmt.Printf("data0: %q\n", data)
|
|
fmt.Printf("data1: %q\n", data1)
|
|
panic(err)
|
|
}
|
|
p.FileName()
|
|
p.FormName()
|
|
pdata, err := ioutil.ReadAll(p)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
p.Close()
|
|
parts1 = append(parts1, Part{p.Header, pdata})
|
|
}
|
|
|
|
fmt.Println("Performing deep equal")
|
|
|
|
if !fuzz.DeepEqual(parts, parts1) {
|
|
fmt.Printf("parts0: %+v\n", parts)
|
|
fmt.Printf("parts1: %+v\n", parts1)
|
|
fmt.Printf("data0: %q\n", data)
|
|
fmt.Printf("data1: %q\n", data1)
|
|
panic("data has changed")
|
|
}
|
|
return 1
|
|
}
|