mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2026-01-31 15:53:10 +08:00
fix(templates): mem leaks in parser cache
Fixes duplicate template storage & removes unnecessary raw bytes caching. Mem usage reduced by ~30%. > 423MB => 299MB heap alloc. * Use `StoreWithoutRaw()` to avoid storing raw bytes. * Remove duplicate storage in both caches. * Remove ineffective raw bytes retrieval logic. Benchmarks show 45% perf improvement with no regressions. Signed-off-by: Dwi Siswanto <git@dw1.io>
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
@@ -103,20 +102,9 @@ func updateRequestOptions(template *Template) {
|
||||
|
||||
// parseFromSource parses a template from source with caching support
|
||||
func parseFromSource(filePath string, preprocessor Preprocessor, options *protocols.ExecutorOptions, parser *Parser) (*Template, error) {
|
||||
var reader io.ReadCloser
|
||||
if !options.DoNotCache {
|
||||
_, raw, err := parser.parsedTemplatesCache.Has(filePath)
|
||||
if err == nil && raw != nil {
|
||||
reader = io.NopCloser(bytes.NewReader(raw))
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
if reader == nil {
|
||||
reader, err = utils.ReaderFromPathOrURL(filePath, options.Catalog)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reader, err := utils.ReaderFromPathOrURL(filePath, options.Catalog)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
@@ -158,7 +146,7 @@ func parseFromSource(filePath string, preprocessor Preprocessor, options *protoc
|
||||
|
||||
template.Path = filePath
|
||||
if !options.DoNotCache {
|
||||
parser.compiledTemplatesCache.Store(filePath, template, nil, err)
|
||||
parser.compiledTemplatesCache.StoreWithoutRaw(filePath, template, err)
|
||||
}
|
||||
|
||||
return template, nil
|
||||
|
||||
@@ -21,11 +21,19 @@ import (
|
||||
type Parser struct {
|
||||
ShouldValidate bool
|
||||
NoStrictSyntax bool
|
||||
// this cache can be copied safely between ephemeral instances
|
||||
|
||||
// parsedTemplatesCache stores lightweight parsed template structures
|
||||
// (without raw bytes).
|
||||
// Used for validation and filtering. This cache can be copied safely
|
||||
// between ephemeral instances.
|
||||
parsedTemplatesCache *Cache
|
||||
// this cache might potentially contain references to heap objects
|
||||
// it's recommended to always empty it at the end of execution
|
||||
|
||||
// compiledTemplatesCache stores fully compiled templates with all protocol
|
||||
// requests.
|
||||
// This cache contains references to heap objects and should be purged when
|
||||
// no longer needed.
|
||||
compiledTemplatesCache *Cache
|
||||
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
@@ -179,7 +187,8 @@ func (p *Parser) ParseTemplate(templatePath string, catalog catalog.Catalog) (an
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.parsedTemplatesCache.Store(templatePath, template, nil, nil) // don't keep raw bytes to save memory
|
||||
p.parsedTemplatesCache.StoreWithoutRaw(templatePath, template, nil)
|
||||
|
||||
return template, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user