{"record":{"id":"056bf5426901d797","repo":"golang/go","slug":"s-malformed-cgo-argument-s","errorCode":null,"errorMessage":"%s: malformed #cgo argument: %s","messagePattern":"(.+?): malformed #cgo argument: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/modindex/build.go","lineNumber":473,"sourceCode":"\t\t\tok := false\n\t\t\tfor _, c := range cond {\n\t\t\t\tif ctxt.matchAuto(c, nil) {\n\t\t\t\t\tok = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\targs, err := splitQuoted(argstr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"%s: invalid #cgo line: %s\", filename, orig)\n\t\t}\n\t\tfor i, arg := range args {\n\t\t\tif arg, ok = expandSrcDir(arg, di.Dir); !ok {\n\t\t\t\treturn fmt.Errorf(\"%s: malformed #cgo argument: %s\", filename, arg)\n\t\t\t}\n\t\t\targs[i] = arg\n\t\t}\n\n\t\tswitch verb {\n\t\tcase \"CFLAGS\", \"CPPFLAGS\", \"CXXFLAGS\", \"FFLAGS\", \"LDFLAGS\":\n\t\t\t// Change relative paths to absolute.\n\t\t\tctxt.makePathsAbsolute(args, di.Dir)\n\t\t}\n\n\t\tswitch verb {\n\t\tcase \"CFLAGS\":\n\t\t\tdi.CgoCFLAGS = append(di.CgoCFLAGS, args...)\n\t\tcase \"CPPFLAGS\":\n\t\t\tdi.CgoCPPFLAGS = append(di.CgoCPPFLAGS, args...)\n\t\tcase \"CXXFLAGS\":\n\t\t\tdi.CgoCXXFLAGS = append(di.CgoCXXFLAGS, args...)\n\t\tcase \"FFLAGS\":","sourceCodeStart":455,"sourceCodeEnd":491,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/modindex/build.go#L455-L491","documentation":"Failure in saveCgo while expanding ${SRCDIR} placeholders in each cgo argument via expandSrcDir. The function returns ok=false when a chunk fails safeCgoName (i.e. contains characters unsafe to pass to the C compiler's shell, such as an unmatched quote or a backslash path separator on Windows). The offending (post-expansion) argument is printed.","triggerScenarios":"A cgo argument containing ${SRCDIR} where the surrounding text is unsafe for the shell, or an argument with a Windows-style backslash path that safeCgoName rejects. Reached when expandSrcDir returns ok=false.","commonSituations":"Hard-coding Windows paths like `#cgo CFLAGS: -I${SRCDIR}\\include`; mixing backslashes with ${SRCDIR}; embedding shell metacharacters in a cgo flag.","solutions":["Convert all backslashes in cgo paths to forward slashes (`/`).","Wrap ${SRCDIR} cleanly: `-I${SRCDIR}/include` with no stray quotes or shell metacharacters.","Avoid shell operators (|, &, $ outside ${SRCDIR}, ;) in cgo arguments — they are passed verbatim."],"exampleFix":"// before\n// #cgo CFLAGS: -I${SRCDIR}\\include\n// after\n// #cgo CFLAGS: -I${SRCDIR}/include","handlingStrategy":"validation","validationCode":"// Replicate safeCgoName's spirit: reject shell-unsafe chars in cgo args that contain ${SRCDIR}.\nvar safeCgoRe = regexp.MustCompile(`^[A-Za-z0-9_./+@%-]*$`)\n\nfunc lintCgoSrcDir(arg string) error {\n    if !strings.Contains(arg, \"${SRCDIR}\") {\n        return nil\n    }\n    for _, chunk := range strings.Split(arg, \"${SRCDIR}\") {\n        if chunk != \"\" && !safeCgoRe.MatchString(chunk) {\n            return fmt.Errorf(\"unsafe chars around ${SRCDIR}: %q\", arg)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use forward slashes only in cgo paths.","Never embed shell metacharacters (|, &, ;, $) in cgo directives.","On Windows, ensure ${SRCDIR} segments do not carry backslashes."],"tags":["cgo","cross-platform","build-directives","windows"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}