Fix race condition surrounding global orgWriter
Since writers are normally only used synchronously (i.e. to write one document at a time), we don't guard modifications to their internal state (e.g. temporarily replacing the string.Builder in WriteNodesAsString) against race conditions. The package global `orgWriter` and corresponding use cases of it (`org.String`, `$node.String`) break that pattern - the writer is potentially used from multiple go routines at the same time. This results in race conditions that manifest as error messages like e.g. could not write output: runtime error: invalid memory address or nil pointer dereference. Using unrendered content. Additionally, since we catch panics in `Document.Write`, the corresponding stack trace is lost and dependents of go-org never know what hit them. As using a writer across simultaneously across go routines is not a standard pattern, we'll sync the use of the global `orgWriter` instead of trying to make the actual writer threadsafe; less code noise for the common use case.
This commit is contained in:
parent
18314a9f41
commit
5464ab37d2
12 changed files with 41 additions and 35 deletions
|
@ -20,6 +20,7 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Configuration struct {
|
||||
|
@ -77,6 +78,7 @@ var lexFns = []lexFn{
|
|||
}
|
||||
|
||||
var nilToken = token{"nil", -1, "", nil}
|
||||
var orgWriterMutex = sync.Mutex{}
|
||||
var orgWriter = NewOrgWriter()
|
||||
|
||||
// New returns a new Configuration with (hopefully) sane defaults.
|
||||
|
@ -95,7 +97,11 @@ func New() *Configuration {
|
|||
}
|
||||
|
||||
// String returns the pretty printed Org mode string for the given nodes (see OrgWriter).
|
||||
func String(nodes []Node) string { return orgWriter.WriteNodesAsString(nodes...) }
|
||||
func String(nodes ...Node) string {
|
||||
orgWriterMutex.Lock()
|
||||
defer orgWriterMutex.Unlock()
|
||||
return orgWriter.WriteNodesAsString(nodes...)
|
||||
}
|
||||
|
||||
// Write is called after with an instance of the Writer interface to export a parsed Document into another format.
|
||||
func (d *Document) Write(w Writer) (out string, err error) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue