go-gl/gl

v4.1-core/gl: LinkProgram crashes on Linux

gmlewis opened this issue · 2 comments

I have a valid fragment shader that is causing LinkProgram to crash on Linux.
I narrowed it down to the smallest test program I could:

Go program causing crash

package main

import (
	"fmt"
	"log"
	"runtime"
	"strings"

	"github.com/go-gl/gl/v4.1-core/gl"
	"github.com/go-gl/glfw/v3.3/glfw"
)

func init() {
	// GLFW event handling must run on the main OS thread
	runtime.LockOSThread()
}

func main() {
	err := glfw.Init()
	if err != nil {
		log.Fatalln(err)
	}
	defer glfw.Terminate()

	glfw.WindowHint(glfw.Resizable, glfw.False)
	glfw.WindowHint(glfw.ContextVersionMajor, 4)
	glfw.WindowHint(glfw.ContextVersionMinor, 1)
	glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
	glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
	window, err := glfw.CreateWindow(600, 400, "IRMF Slicer", nil, nil)
	if err != nil {
		log.Fatalln(err)
	}
	window.MakeContextCurrent()

	err = gl.Init()
	if err != nil {
		log.Fatalln(err)
	}

	version := gl.GoStr(gl.GetString(gl.VERSION))
	fmt.Println("OpenGL version", version)

	vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER)
	if err != nil {
		log.Fatalln(err)
	}

	fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
	if err != nil {
		log.Fatalln(err)
	}

	program := gl.CreateProgram()

	gl.AttachShader(program, vertexShader)
	gl.AttachShader(program, fragmentShader)
	// OpenGL crashes on the following line:
	gl.LinkProgram(program)

	select {} // wait forever
}

func compileShader(source string, shaderType uint32) (uint32, error) {
	shader := gl.CreateShader(shaderType)

	csources, free := gl.Strs(source)
	gl.ShaderSource(shader, 1, csources, nil)
	free()
	gl.CompileShader(shader)

	var status int32
	gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status)
	if status == gl.FALSE {
		var logLength int32
		gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength)

		log := strings.Repeat("\x00", int(logLength+1))
		gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))

		return 0, fmt.Errorf("failed to compile %v: %v", source, log)
	}

	return shader, nil
}

const vertexShaderSource = `
#version 330
uniform mat4 projection;
uniform mat4 camera;
uniform mat4 model;
in vec3 vert;
out vec3 fragVert;
void main() {
	gl_Position = projection * camera * model * vec4(vert, 1);
	fragVert = vert;
}
` + "\x00"

const fragmentShaderSource = `
#version 330
precision highp float;
precision highp int;
in vec3 fragVert;
out vec4 outputColor;
uniform float u_slice;
uniform int u_materialNum;

vec2 superquad2(in float slices, in float e1, in float e2, in float a4, in vec3 xyz) {
  xyz.xyz *= 2.5;
  vec2 result = (mod(abs(xyz.z) * 6.0, 1.0) <= 0.5) ? vec2(1, 0) : vec2(0, 1);
  float angle = -1.3;
  float c = cos(angle);
  float s = sin(angle);
  xyz.yz = mat2(c, - s, s, c) * xyz.yz;
  xyz = abs(xyz); // Due to GLSL 'pow' definition.
  float f = pow(pow(pow(xyz.x, 2.0 / e2) + pow(xyz.y, 2.0 / e2), e2 / 2.0) - a4, 2.0 / e1) + pow(xyz.z, 2.0 / e1);
  return f <= 1.0 ? result : vec2(0);
}

void mainModel4(out vec4 materials, in vec3 xyz) {
  materials.xy = vec2(0);

  vec4 e = vec4(0.1, 0.3, 1.0, 3.0);
  vec4 o = vec4(-3.4, - 1.2, 1.2, 3.4);
  // Removing the two for loops avoids the SIGSEGV.
  for (int i = 0; i < 4; i++) {
    for (int j = 0; j < 4; j++) {
      // Alternatively, replacing superquad2(...) with vec2(0) also avoids the SIGSEGV.
      materials.xy += superquad2(6.0, e[i], e[j], 1.5, xyz - vec3(o[j], 0, o[3 - i]));
    }
  }
}

void main() {
  vec4 m;
  mainModel4(m, vec3(fragVert.xy,u_slice));
  outputColor = vec4(m.x);
}
` + "\x00"

Stack trace of crash

go run main.go
OpenGL version 4.1.0 NVIDIA 390.116
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x7f5c3557ea32]

runtime stack:
runtime.throw(0x5716da, 0x2a)
	/usr/local/go/src/runtime/panic.go:1114 +0x72
runtime.sigpanic()
	/usr/local/go/src/runtime/signal_unix.go:679 +0x46a

goroutine 1 [syscall, locked to thread]:
runtime.cgocall(0x4ed230, 0xc000045ee0, 0xc000000000)
	/usr/local/go/src/runtime/cgocall.go:133 +0x5b fp=0xc000045eb0 sp=0xc000045e78 pc=0x42757b
github.com/go-gl/gl/v4.1-core/gl._Cfunc_glowLinkProgram(0x7f5c766ff5e0, 0x200000003)
	_cgo_gotypes.go:12370 +0x41 fp=0xc000045ee0 sp=0xc000045eb0 pc=0x4c3191
github.com/go-gl/gl/v4.1-core/gl.LinkProgram(...)
	/home/glenn/go/src/github.com/go-gl/gl/v4.1-core/gl/package.go:10777
main.main()
	/home/glenn/src/glfw-bug/main.go:59 +0x3fc fp=0xc000045f88 sp=0xc000045ee0 pc=0x4e89ec
runtime.main()
	/usr/local/go/src/runtime/proc.go:203 +0x212 fp=0xc000045fe0 sp=0xc000045f88 pc=0x4566c2
runtime.goexit()
	/usr/local/go/src/runtime/asm_amd64.s:1373 +0x1 fp=0xc000045fe8 sp=0xc000045fe0 pc=0x480df1
exit status 2

Note that I found two workarounds for avoiding the crash (which I commented in the code):

  • Completely remove the two for loops, but still call superquadric2.
  • Leave the two for loops but replace the call to superquadric2 with vec2(0)

I tried using the dlv debugger but couldn't figure out how to debug into the C code.

I also tried using gdb but the results were not much better:

gdb session

$ gdb gl-bug 
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
Copyright (C) 2018 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.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Registered pretty printers for UE4 classes
Reading symbols from gl-bug...done.
warning: File "/usr/local/go1.14.1/src/runtime/runtime-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
To enable execution of this file add
	add-auto-load-safe-path /usr/local/go1.14.1/src/runtime/runtime-gdb.py
line to your configuration file "/home/glenn/.gdbinit".
To completely disable this security protection add
	set auto-load safe-path /
line to your configuration file "/home/glenn/.gdbinit".
For more information about this security protection see the
"Auto-loading safe path" section in the GDB manual.  E.g., run from the shell:
	info "(gdb)Auto-loading safe path"
(gdb) run
Starting program: /home/glenn/src/gl-bug/gl-bug 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffcf217700 (LWP 30999)]
[New Thread 0x7fffcea16700 (LWP 31000)]
[New Thread 0x7fffce215700 (LWP 31001)]
[New Thread 0x7fffcda14700 (LWP 31002)]
[New Thread 0x7fffcd213700 (LWP 31003)]
[New Thread 0x7fffcca12700 (LWP 31004)]
OpenGL version 4.1.0 NVIDIA 390.116

Thread 1 "gl-bug" received signal SIGSEGV, Segmentation fault.
0x00007fffb4d4ba32 in ?? () from /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116
(gdb) where
#0  0x00007fffb4d4ba32 in ?? () from /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116
#1  0x00007fffb4d4babd in ?? () from /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116
#2  0x00007fffb4d4d073 in ?? () from /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116
#3  0x00007fffb4d4df22 in ?? () from /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116
#4  0x00007fffb4d538a4 in ?? () from /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116
#5  0x00007fffb4d54110 in ?? () from /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116
#6  0x00007fffb5885750 in ?? () from /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116
#7  0x00007fffb589788b in ?? () from /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116
#8  0x00007fffb589a46a in ?? () from /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116
#9  0x00007fffb586260c in ?? () from /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116
#10 0x0000000000480530 in runtime.asmcgocall () at /usr/local/go/src/runtime/asm_amd64.s:655
#11 0x00000000008b0488 in runtime.memstats ()
#12 0x00007ffff7e2fb10 in ?? ()
#13 0x0000000000000001 in ?? ()
#14 0x000000c00002a000 in ?? ()
#15 0x000000c000000180 in ?? ()
#16 0x0000000000000190 in ?? ()
#17 0x000000c000000180 in ?? ()
#18 0x000000000047ed56 in runtime.systemstack () at /usr/local/go/src/runtime/asm_amd64.s:370
#19 0x0000000000458e50 in ?? () at <autogenerated>:1
#20 0x000000000047ebe4 in runtime.rt0_go () at /usr/local/go/src/runtime/asm_amd64.s:220
#21 0x00000000005087f0 in crosscall_amd64 ()
#22 0x000000000047ebeb in runtime.rt0_go () at /usr/local/go/src/runtime/asm_amd64.s:225
#23 0x0000000000000001 in ?? ()
#24 0x00007fffffffda08 in ?? ()
#25 0x0000000000000001 in ?? ()
#26 0x00007fffffffda08 in ?? ()
#27 0x0000000000000000 in ?? ()
(gdb) q
A debugging session is active.

	Inferior 1 [process 30995] will be killed.

Quit anyway? (y or n) y

From this, it actually looks like the problem might be in the NVIDIA driver library... in which case, feel free to close this bug.

Hello @gmlewis - were you able to cross test this with a different driver or version of the libraries?

Thanks for the reminder, @dertseha .

I just tried it again using an updated driver, and it works fine:

$ go run main.go
OpenGL version 4.1.0 NVIDIA 450.119.03

Closing as obsolete.