Skip to content

Windows: Diff fails with cgo: "day out of range" #4867

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
6 of 7 tasks
mook-as opened this issue Jul 10, 2024 · 6 comments
Closed
6 of 7 tasks

Windows: Diff fails with cgo: "day out of range" #4867

mook-as opened this issue Jul 10, 2024 · 6 comments
Assignees
Labels
platform: windows Issue that is related to Windows question Further information is requested

Comments

@mook-as
Copy link

mook-as commented Jul 10, 2024

Welcome

  • Yes, I'm using a binary release within 2 latest releases. Only such installations are supported.
  • Yes, I've searched similar issues on GitHub and didn't find any.
  • Yes, I've read the typecheck section of the FAQ.
  • Yes, I've tried with the standalone linter if available (e.g., gocritic, go vet, etc.).
  • I agree to follow this project's Code of Conduct

Description of the problem

On Windows, running goimports on a file using cgo (i.e. import "C") produces an error because the time in the diff is zero ("1900-01-00 00:00:00 +0000").

Note that the same code works fine on macOS (using Apple diff) and Linux (diff (GNU diffutils) 3.6, WSL on the same machine).

Code that does not use cgo appear to work fine on Windows as well.

Version of golangci-lint

golangci-lint.exe --version
> golangci-lint.exe --version                                       
golangci-lint has version 1.59.1 built with go1.22.3 from 1a55854a on 2024-06-09T18:08:33Z
diff.exe --version
diff (GNU diffutils) 3.6
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Paul Eggert, Mike Haertel, David Hayes,
Richard Stallman, and Len Tower.
diff.exe --help
Usage: C:\Users\Bob\scoop\apps\diffutils\current\diff.exe [OPTION]... FILES
Compare FILES line by line.

Mandatory arguments to long options are mandatory for short options too.
      --normal                  output a normal diff (the default)
  -q, --brief                   report only when files differ
  -s, --report-identical-files  report when two files are the same
  -c, -C NUM, --context[=NUM]   output NUM (default 3) lines of copied context
  -u, -U NUM, --unified[=NUM]   output NUM (default 3) lines of unified context
  -e, --ed                      output an ed script
  -n, --rcs                     output an RCS format diff
  -y, --side-by-side            output in two columns
  -W, --width=NUM               output at most NUM (default 130) print columns
      --left-column             output only the left column of common lines
      --suppress-common-lines   do not output common lines

  -p, --show-c-function         show which C function each change is in
  -F, --show-function-line=RE   show the most recent line matching RE
      --label LABEL             use LABEL instead of file name and timestamp
                                  (can be repeated)

  -t, --expand-tabs             expand tabs to spaces in output
  -T, --initial-tab             make tabs line up by prepending a tab
      --tabsize=NUM             tab stops every NUM (default 8) print columns
      --suppress-blank-empty    suppress space or tab before empty output lines
  -l, --paginate                pass output through 'pr' to paginate it

  -r, --recursive                 recursively compare any subdirectories found
      --no-dereference            don't follow symbolic links
  -N, --new-file                  treat absent files as empty
      --unidirectional-new-file   treat absent first files as empty
      --ignore-file-name-case     ignore case when comparing file names
      --no-ignore-file-name-case  consider case when comparing file names
  -x, --exclude=PAT               exclude files that match PAT
  -X, --exclude-from=FILE         exclude files that match any pattern in FILE
  -S, --starting-file=FILE        start with FILE when comparing directories
      --from-file=FILE1           compare FILE1 to all operands;
                                    FILE1 can be a directory
      --to-file=FILE2             compare all operands to FILE2;
                                    FILE2 can be a directory

  -i, --ignore-case               ignore case differences in file contents
  -E, --ignore-tab-expansion      ignore changes due to tab expansion
  -Z, --ignore-trailing-space     ignore white space at line end
  -b, --ignore-space-change       ignore changes in the amount of white space
  -w, --ignore-all-space          ignore all white space
  -B, --ignore-blank-lines        ignore changes where lines are all blank
  -I, --ignore-matching-lines=RE  ignore changes where all lines match RE

  -a, --text                      treat all files as text
      --strip-trailing-cr         strip trailing carriage return on input
      --binary                    read and write data in binary mode

  -D, --ifdef=NAME                output merged file with '#ifdef NAME' diffs
      --GTYPE-group-format=GFMT   format GTYPE input groups with GFMT
      --line-format=LFMT          format all input lines with LFMT
      --LTYPE-line-format=LFMT    format LTYPE input lines with LFMT
    These format options provide fine-grained control over the output
      of diff, generalizing -D/--ifdef.
    LTYPE is 'old', 'new', or 'unchanged'.  GTYPE is LTYPE or 'changed'.
    GFMT (only) may contain:
      %<  lines from FILE1
      %>  lines from FILE2
      %=  lines common to FILE1 and FILE2
      %[-][WIDTH][.[PREC]]{doxX}LETTER  printf-style spec for LETTER
        LETTERs are as follows for new group, lower case for old group:
          F  first line number
          L  last line number
          N  number of lines = L-F+1
          E  F-1
          M  L+1
      %(A=B?T:E)  if A equals B then T else E
    LFMT (only) may contain:
      %L  contents of line
      %l  contents of line, excluding any trailing newline
      %[-][WIDTH][.[PREC]]{doxX}n  printf-style spec for input line number
    Both GFMT and LFMT may contain:
      %%  %
      %c'C'  the single character C
      %c'\OOO'  the character with octal code OOO
      C    the character C (other characters represent themselves)

  -d, --minimal            try hard to find a smaller set of changes
      --horizon-lines=NUM  keep NUM lines of the common prefix and suffix
      --speed-large-files  assume large files and many scattered small changes
      --color[=WHEN]       colorize the output; WHEN can be 'never', 'always',
                             or 'auto' (the default)
      --palette=PALETTE    the colors to use when --color is active; PALETTE is
                             a colon-separated list of terminfo capabilities

      --help               display this help and exit
  -v, --version            output version information and exit

FILES are 'FILE1 FILE2' or 'DIR1 DIR2' or 'DIR FILE' or 'FILE DIR'.
If --from-file or --to-file is given, there are no restrictions on FILE(s).
If a FILE is '-', read standard input.
Exit status is 0 if inputs are the same, 1 if different, 2 if trouble.

Report bugs to: [email protected]
GNU diffutils home page: <http://www.gnu.org/software/diffutils/>
General help using GNU software: <http://www.gnu.org/gethelp/>

Configuration

golangci-lint.exe --verbose run --no-config --disable-all --enable=goimports .

Go environment

> go version                                                                    
go version go1.22.3 windows/amd64
> go env    
set GO111MODULE=
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\Bob\AppData\Local\go-build
set GOENV=C:\Users\Bob\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\Bob\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\Bob\go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=C:\Users\Bob\scoop\apps\go\current
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLCHAIN=auto
set GOTOOLDIR=C:\Users\Bob\scoop\apps\go\current\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.22.3
set GCCGO=gccgo
set GOAMD64=v1
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=C:\junk\go.mod
set GOWORK=
set CGO_CFLAGS=-O2 -g
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-O2 -g
set CGO_FFLAGS=-O2 -g
set CGO_LDFLAGS=-O2 -g
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=C:\Users\Bob\AppData\Local\Temp\go-build2143475260=/tmp/go-build -gno-record-gcc-switches

Verbose output of running

> $env:GL_DEBUG="loader,runner,goimports"
> golangci-lint.exe cache clean
> golangci-lint.exe --verbose run --no-config --disable-all --enable=goimports .
level=info msg="golangci-lint has version 1.59.1 built with go1.22.3 from 1a55854a on 2024-06-09T18:08:33Z"
level=info msg="[lintersdb] Active 1 linters: [goimports]"
level=debug msg="[loader] Built loader args are [.]"
level=debug msg="[loader] 90.6508ms for GOROOT=C:\\Users\\Bob\\scoop\\apps\\go\\current GOPATH= GO111MODULE=off GOPROXY= PWD=D:\\junk go list -e -f {{context.ReleaseTags}} -- unsafe"
level=debug msg="[loader] 849.2045ms for GOROOT=C:\\Users\\Bob\\scoop\\apps\\go\\current GOPATH= GO111MODULE= GOPROXY= PWD=D:\\junk go list -e -json=Name,ImportPath,Error,Dir,GoFiles,IgnoredGoFiles,IgnoredOtherFiles,CFiles,CgoFiles,CXXFiles,MFiles,HFi
les,FFiles,SFiles,SwigFiles,SwigCXXFiles,SysoFiles,TestGoFiles,XTestGoFiles,CompiledGoFiles,Export -compiled=true -test=true -export=false -deps=false -find=false -pgo=off -- ."
level=debug msg="[loader] loaded 1 pkgs"
level=debug msg="[loader] Loaded pkg #0: ID=github.com/mook-as/junk GoFiles=[D:\\junk\\main.go] CompiledGoFiles=[C:\\Users\\Bob\\AppData\\Local\\go-build\\d3\\d3471a4721bbfc7ce5e462826250c96bf7de28043ff87fd6607146c235fd0b75-d C:\\Users\\Bob\\AppData\
\Local\\go-build\\79\\79f5e1f0832f2d1793668a71558814fe207fb3e58863f0cfa3f51343a1af0534-d C:\\Users\\Bob\\AppData\\Local\\go-build\\0e\\0eece15e335c3eb4a6806dc4c9e12a42f39a530fe57f932858c29ed4b78a256f-d] Syntax=[]"
level=info msg="[loader] Go packages loading at mode 7 (compiled_files|files|name) took 1.0404772s"
level=debug msg="[loader] package with tests: map[string]bool{}"
level=info msg="[runner/filename_unadjuster] Pre-built 0 adjustments in 568.3µs"
level=info msg="[linters_context/goanalysis] analyzers took 76.2997ms with top 10 stages: goimports: 76.2394ms, typecheck: 60.3µs"
level=warning msg="[runner] Can't run linter goanalysis_metalinter: goimports: can't extract issues from gofmt diff output \"--- C:/Users/Bob/AppData/Local/go-build/d3/d3471a4721bbfc7ce5e462826250c96bf7de28043ff87fd6607146c235fd0b75-d.orig\\t1900-01-00 00:00:00 +0000\\r\\n+++ 
C:/Users/Mook/AppData/Local/go-build/d3/d3471a4721bbfc7ce5e462826250c96bf7de28043ff87fd6607146c235fd0b75-d\\t1900-01-00 00:00:00 +0000\\r\\n@@ -4,22 +4,28 @@\\r\\n \\r\\n package main\\r\\n \\r\\n-import \\\"unsafe\\\"\\r\\n+import (\\r\\n+\\t\\\"syscall\\\"\\r\\n+\\t\\\"unsafe
\\\"\\r\\n \\r\\n-import \\\"syscall\\\"\\r\\n-\\r\\n-import _cgopackage \\\"runtime/cgo\\\"\\r\\n+\\t_cgopackage \\\"runtime/cgo\\\"\\r\\n+)\\r\\n \\r\\n type _ _cgopackage.Incomplete\\r\\n+\\r\\n var _ syscall.Errno\\r\\n+\\r\\n func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointe
r { return ptr }\\r\\n \\r\\n //go:linkname _Cgo_always_false runtime.cgoAlwaysFalse\\r\\n var _Cgo_always_false bool\\r\\n+\\r\\n //go:linkname _Cgo_use runtime.cgoUse\\r\\n func _Cgo_use(interface{})\\r\\n+\\r\\n //go:linkname _Cgo_no_callback runtime.cgoNoCallback\\r\\n func
 _Cgo_no_callback(bool)\\r\\n+\\r\\n type _Ctype_ulong uint32\\r\\n \\r\\n type _Ctype_void [0]byte\\r\\n@@ -39,8 +45,8 @@\\r\\n //go:linkname _cgoexp_af0891677fe5_Foo _cgoexp_af0891677fe5_Foo\\r\\n //go:cgo_export_static _cgoexp_af0891677fe5_Foo\\r\\n func _cgoexp_af0891677fe5
_Foo(a *struct {\\r\\n-\\t\\tp0 _Ctype_ulong\\r\\n-\\t\\tr0 _Ctype_ulong\\r\\n-\\t}) {\\r\\n+\\tp0 _Ctype_ulong\\r\\n+\\tr0 _Ctype_ulong\\r\\n+}) {\\r\\n \\ta.r0 = Foo(a.p0)\\r\\n }\\r\\n\": can't parse patch: parsing time \"1900-01-00 00:00:00 +0000\": day out of range"       
level=info msg="[runner] processing took 0s with stages: exclude: 0s, max_per_file_from_linter: 0s, fixer: 0s, sort_results: 0s, cgo: 0s, filename_unadjuster: 0s, invalid_issue: 0s, path_prettifier: 0s, skip_files: 0s, identifier_marker: 0s, skip_dirs: 0s, max_same_issues: 0s, 
max_from_linter: 0s, source_code: 0s, path_prefixer: 0s, autogenerated_exclude: 0s, exclude-rules: 0s, nolint: 0s, uniq_by_line: 0s, diff: 0s, path_shortener: 0s, severity-rules: 0s"
level=info msg="[runner] linters took 165.4926ms with stages: goanalysis_metalinter: 164.0954ms"
level=error msg="Running error: can't run linter goanalysis_metalinter\ngoimports: can't extract issues from gofmt diff output \"--- C:/Users/Bob/AppData/Local/go-build/d3/d3471a4721bbfc7ce5e462826250c96bf7de28043ff87fd6607146c235fd0b75-d.orig\\t1900-01-00 00:00:00 +0000\\r\\n
+++ C:/Users/Bob/AppData/Local/go-build/d3/d3471a4721bbfc7ce5e462826250c96bf7de28043ff87fd6607146c235fd0b75-d\\t1900-01-00 00:00:00 +0000\\r\\n@@ -4,22 +4,28 @@\\r\\n \\r\\n package main\\r\\n \\r\\n-import \\\"unsafe\\\"\\r\\n+import (\\r\\n+\\t\\\"syscall\\\"\\r\\n+\\t\\\"un
safe\\\"\\r\\n \\r\\n-import \\\"syscall\\\"\\r\\n-\\r\\n-import _cgopackage \\\"runtime/cgo\\\"\\r\\n+\\t_cgopackage \\\"runtime/cgo\\\"\\r\\n+)\\r\\n \\r\\n type _ _cgopackage.Incomplete\\r\\n+\\r\\n var _ syscall.Errno\\r\\n+\\r\\n func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Po
inter { return ptr }\\r\\n \\r\\n //go:linkname _Cgo_always_false runtime.cgoAlwaysFalse\\r\\n var _Cgo_always_false bool\\r\\n+\\r\\n //go:linkname _Cgo_use runtime.cgoUse\\r\\n func _Cgo_use(interface{})\\r\\n+\\r\\n //go:linkname _Cgo_no_callback runtime.cgoNoCallback\\r\\n 
func _Cgo_no_callback(bool)\\r\\n+\\r\\n type _Ctype_ulong uint32\\r\\n \\r\\n type _Ctype_void [0]byte\\r\\n@@ -39,8 +45,8 @@\\r\\n //go:linkname _cgoexp_af0891677fe5_Foo _cgoexp_af0891677fe5_Foo\\r\\n //go:cgo_export_static _cgoexp_af0891677fe5_Foo\\r\\n func _cgoexp_af089167
7fe5_Foo(a *struct {\\r\\n-\\t\\tp0 _Ctype_ulong\\r\\n-\\t\\tr0 _Ctype_ulong\\r\\n-\\t}) {\\r\\n+\\tp0 _Ctype_ulong\\r\\n+\\tr0 _Ctype_ulong\\r\\n+}) {\\r\\n \\ta.r0 = Foo(a.p0)\\r\\n }\\r\\n\": can't parse patch: parsing time \"1900-01-00 00:00:00 +0000\": day out of range"   
level=info msg="Memory: 15 samples, avg is 27.2MB, max is 27.3MB"
level=info msg="Execution took 1.3401862s"

A minimal reproducible example or link to a public repository

https://github.com/mook-as/junk/tree/ad9838066794145336d89b4f8e549216022d0883

It's a very tiny program that uses cgo.

Validation

  • Yes, I've included all information above (version, config, etc.).

Supporter

@mook-as mook-as added the bug Something isn't working label Jul 10, 2024
Copy link

boring-cyborg bot commented Jul 10, 2024

Hey, thank you for opening your first Issue ! 🙂 If you would like to contribute we have a guide for contributors.

@ldez ldez added the platform: windows Issue that is related to Windows label Jul 10, 2024
@ldez
Copy link
Member

ldez commented Jul 10, 2024

Hello,

you checked:

  • Yes, I've tried with the standalone linter if available (e.g., gocritic, go vet, etc.).

can you give the output of goimports?

@mook-as
Copy link
Author

mook-as commented Jul 10, 2024

Oh, sorry about that; I missed the output.

> goimports.exe -v -d .                            
2024/07/09 17:36:30.755410 fixImports(filename="main.go"), abs="D:\\junk\\main.go", srcDir="D:\\junk" ...

(That was the end of the output. It returned success.)

FWIW:

> go version -m $(Get-Command goimports.exe).Source
C:\Users\Bob\go\bin\goimports.exe: go1.22.3
        path    golang.org/x/tools/cmd/goimports
        mod     golang.org/x/tools      v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
        dep     golang.org/x/mod        v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
        dep     golang.org/x/sync       v0.7.0  h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
        build   -buildmode=exe
        build   -compiler=gc
        build   DefaultGODEBUG=httplaxcontentlength=1,httpmuxgo121=1,panicnil=1,tls10server=1,tlsrsakex=1,tlsunsafeekm=1
        build   CGO_ENABLED=1
        build   CGO_CFLAGS=
        build   CGO_CPPFLAGS=
        build   CGO_CXXFLAGS=
        build   CGO_LDFLAGS=
        build   GOARCH=amd64
        build   GOOS=windows
        build   GOAMD64=v1

@ldez ldez self-assigned this Jul 10, 2024
@ldez
Copy link
Member

ldez commented Jul 10, 2024

Technically the problem is related to the fact the day 0 of January doesn't exist.
But why diff, on Windows, produces that? 🤔

Internally, the diff is produced based on real files (temp files), so there is a real date.
And cgo has no impact on that part.

@ldez
Copy link
Member

ldez commented Jul 10, 2024

Are you using a real machine? Is the system date working on this machine?

🤔 I think you have a problem somewhere else because it's just a call to diff on 2 existing files. It's independent of cgo or golangci-lint itself.
golangci-lint just read the patch produced by diff.

The call to diff (there is no .exe extension): diff -u file01 file02

Can you call diff without the .exe extension?

I think the diff command, on your system, is an alias to a PowerShell command and not the real diff command.

@ldez ldez added the feedback required Requires additional feedback label Jul 10, 2024
@mook-as
Copy link
Author

mook-as commented Jul 10, 2024

Yes, I am on a real physical machine with working time (note that the goimports output had a timestamp).

If I uninstall diff.exe, the output changes, so I'm using the correct binary:

> ./golangci-lint.exe --verbose run --no-config --disable-all --enable=goimports .
level=info msg="golangci-lint has version 1.59.1 built with go1.22.3 from 1a55854a on 2024-06-09T18:08:33Z"
level=info msg="[lintersdb] Active 1 linters: [goimports]"
level=info msg="[loader] Go packages loading at mode 7 (files|compiled_files|name) took 998.7919ms"
level=info msg="[runner/filename_unadjuster] Pre-built 0 adjustments in 615.2µs"
level=info msg="[linters_context/goanalysis] analyzers took 32.2084ms with top 10 stages: goimports: 32.2084ms, typecheck: 0s"
level=warning msg="[runner] Can't run linter goanalysis_metalinter: goimports: error computing diff: exec: \"diff\": executable file not found in %PATH%"
level=info msg="[runner] processing took 0s with stages: max_same_issues: 0s, max_from_linter: 0s, severity-rules: 0s, filename_unadjuster: 0s, nolint: 0s, max_per_file_from_linter: 0s, source_code: 0s, fixer: 0s, path_prefixer: 0s, sort_results: 0s, skip_files: 0s, invalid_iss
ue: 0s, diff: 0s, path_shortener: 0s, cgo: 0s, skip_dirs: 0s, autogenerated_exclude: 0s, identifier_marker: 0s, exclude: 0s, exclude-rules: 0s, uniq_by_line: 0s, path_prettifier: 0s"
level=info msg="[runner] linters took 34.1668ms with stages: goanalysis_metalinter: 34.0214ms"
level=error msg="Running error: can't run linter goanalysis_metalinter\ngoimports: error computing diff: exec: \"diff\": executable file not found in %PATH%"
level=info msg="Memory: 13 samples, avg is 27.0MB, max is 27.0MB"
level=info msg="Execution took 1.151631s"

Note that PowerShell aliases are like bash aliases: they are not real files, so golangci-lint can't actually call it (without explicitly invoking PowerShell).

Digging into this more, though, I think it might just be my diff.exe being broken: it returns the same date on any file. Using the diff.exe from the git installation (i.e. msys2) works fine.

Sorry for the distraction, it's all my fault!

@mook-as mook-as closed this as completed Jul 10, 2024
@ldez ldez added question Further information is requested and removed bug Something isn't working feedback required Requires additional feedback labels Jul 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
platform: windows Issue that is related to Windows question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants