Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,10 @@ func (f *ConfigurationFile) parseIniFile(file ufs.File) error {
return err
}

// Force format to be key = value
ini.PrettyFormat = false
ini.PrettyEqual = true
Comment on lines +321 to +323
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the context around lines 321-323 in parser/parser.go
cat -n parser/parser.go | sed -n '310,335p'

Repository: pelican-dev/wings

Length of output: 803


🏁 Script executed:

# Find the parseIniFile function definition to understand its scope
rg -n -A30 'func.*parseIniFile' --type=go

Repository: pelican-dev/wings

Length of output: 1413


🏁 Script executed:

# Search for calls to parseIniFile to check if it's used concurrently
rg -n 'parseIniFile' --type=go

Repository: pelican-dev/wings

Length of output: 195


🏁 Script executed:

# Check for goroutines that might call parseIniFile or use Parse/WriteTo
rg -n 'go\s+.*Parse|go\s+func' --type=go -C3

Repository: pelican-dev/wings

Length of output: 17254


🏁 Script executed:

# Look for synchronization patterns that might indicate concurrent code
rg -n -C2 'sync\.(Mutex|RWMutex|WaitGroup|Cond)|make.*chan' --type=go

Repository: pelican-dev/wings

Length of output: 14300


🏁 Script executed:

# Get context around line 227 where parseIniFile is called
cat -n parser/parser.go | sed -n '200,250p'

Repository: pelican-dev/wings

Length of output: 1750


🏁 Script executed:

# Check if the caller of parseIniFile is in a goroutine or concurrent context
cat -n parser/parser.go | sed -n '150,280p'

Repository: pelican-dev/wings

Length of output: 4759


🏁 Script executed:

# Let's see the entire parseFile function to understand the context
rg -n -A100 'func.*\(f.*\).*parseFile' parser/parser.go

Repository: pelican-dev/wings

Length of output: 43


🌐 Web query:

gopkg.in/ini.v1 PrettyFormat PrettyEqual API instance vs global

💡 Result:

Short answer: PrettyFormat and PrettyEqual are package-level global variables (not per-File instance). Changing them affects all writes done by the gopkg.in/ini.v1 package. See the package variables listing (PrettyFormat, PrettyEqual) in the API/source. [1][2]

Notes / quick options:

  • Set ini.PrettyFormat / ini.PrettyEqual before calling SaveTo/WriteTo to control output globally. [1]
  • If you need per-File behavior you must manage it yourself (e.g. set the globals just before writing a specific File and restore them after, or copy/fork the library to add per-File options). [2]

Sources:

  • Package variables (PrettyFormat, PrettyEqual) in gopkg.in/ini.v1 API/source. [1]
  • ini.go source showing those variables and comments. [2]

References:
[1] pkg.go.dev: gopkg.in/ini.v1 — Variables (PrettyFormat, PrettyEqual).
[2] gopkg.in/ini.v1 source (ini.go) — definition/comments for PrettyFormat/PrettyEqual.


🏁 Script executed:

# Search for calls to Parse() on ConfigurationFile
rg -n '\.Parse\(' --type=go -B5 -A5

Repository: pelican-dev/wings

Length of output: 6778


🏁 Script executed:

# More specifically, search for ConfigurationFile usage and Parse calls
rg -n 'Parse\(' parser/parser.go -B3 -A3

Repository: pelican-dev/wings

Length of output: 423


🏁 Script executed:

# Find which functions/methods call Parse on ConfigurationFile
rg -n 'f\.Parse|cf\.Parse|\.Parse\(\)' --type=go -B5 -A2

Repository: pelican-dev/wings

Length of output: 1595


🏁 Script executed:

# Get more context around server/config_parser.go:64 to see the full function
cat -n server/config_parser.go | sed -n '40,80p'

Repository: pelican-dev/wings

Length of output: 1334


🏁 Script executed:

# Get even more context to understand the full function structure
cat -n server/config_parser.go | sed -n '30,100p'

Repository: pelican-dev/wings

Length of output: 1728


🏁 Script executed:

# Check if there are any imports related to ini and look at how it's used
rg -n 'import.*ini|package ini' parser/parser.go -A5 -B5

Repository: pelican-dev/wings

Length of output: 43


🏁 Script executed:

# Check the exact usage pattern of ini in parseIniFile
cat -n parser/parser.go | sed -n '314,395p'

Repository: pelican-dev/wings

Length of output: 2361


Race condition: concurrent modification of global ini package variables.

The code mutates package-level global variables (ini.PrettyFormat and ini.PrettyEqual) in a concurrent context. UpdateConfigurationFiles() in server/config_parser.go (line 37) creates a worker pool with runtime.NumCPU() workers and submits Parse() tasks concurrently (line 45). When parsing INI files, each goroutine executes parseIniFile() which modifies these globals at lines 322-323, then calls WriteTo() (line 390) which reads them. Multiple goroutines reading and writing the same unprotected global variables creates a data race.

Use a sync.Mutex to guard these assignments, or configure formatting before calling Parse() once rather than repeatedly within the goroutines.

🤖 Prompt for AI Agents
In parser/parser.go around lines 321 to 323, the code mutates package-level
globals ini.PrettyFormat and ini.PrettyEqual from concurrent goroutines causing
a data race; protect these assignments with a sync.Mutex (declare a
package-level or parser-scoped mutex and lock/unlock around any read/write of
those ini package globals, including WriteTo usage), or better move the
formatting configuration out of parseIniFile and set
ini.PrettyFormat/ini.PrettyEqual once before launching the worker pool so
goroutines no longer modify shared state.


for _, replacement := range f.Replace {
var (
path []string
Expand Down
Loading