Bug 111167 - Dividing zero by a uniform in loop header causes segfault in nv50_ir::NVC0LegalizeSSA::handleDIV
Summary: Dividing zero by a uniform in loop header causes segfault in nv50_ir::NVC0Leg...
Alias: None
Product: Mesa
Classification: Unclassified
Component: Drivers/DRI/nouveau (show other bugs)
Version: git
Hardware: x86-64 (AMD64) Linux (All)
: medium minor
Assignee: Nouveau Project
QA Contact: Nouveau Project
: 111218 (view as bug list)
Depends on:
Reported: 2019-07-18 15:38 UTC by Abel Briggs
Modified: 2019-09-18 20:49 UTC (History)
1 user (show)

See Also:
i915 platform:
i915 features:

Reproduction shader_test file, core dump of crash (1.49 MB, application/zip)
2019-07-18 15:38 UTC, Abel Briggs

Description Abel Briggs 2019-07-18 15:38:38 UTC
Created attachment 144815 [details]
Reproduction shader_test file, core dump of crash

The attached archive contains a shader that, on the build and PC specified below, causes a segmentation fault in nouveau when run. A core dump of the crash is supplied as well.

void main()
  for(int i = 1; 1 >= (0 / int((injectionSwitch.y))); 1)

The value of injectionSwitch is set to (0.0, 1.0) - so (0 / int(injectionSwitch.y)) is equivalent to (0 / 1), which should evaluate to zero and make the two conditions equal. Notably, if you remove injectionSwitch and replace it with ‘1’, no segfault occurs.

Steps to reproduce:
1. Obtain and build piglit, the Mesa OpenGL test suite runner: 
2. Download the attached archive.
3. From a terminal, execute the supplied test with the piglit GLES3 shader 
   $ bin/shader_runner_gles3 minimum_testcase.shader_test

Expected results:
The shader should run without crashing (it’s an infinite loop that does nothing, but it still shouldn’t crash).

Actual results:
The shader causes nouveau to segfault.

Here is a backtrace obtained from using GDB on the core dump 
(exact command: $ gdb shader_runner_gles3 core):

#0  std::_Deque_iterator<nv50_ir::ValueRef, nv50_ir::ValueRef&, nv50_ir::ValueRef*>::_Deque_iterator (
    __x=<error reading variable: Cannot access memory at address 0xb0>, 
    this=<synthetic pointer>) at /usr/include/c++/8/bits/stl_deque.h:1401
#1  std::_Deque_iterator<nv50_ir::ValueRef, nv50_ir::ValueRef&, nv50_ir::ValueRef*>::operator+ (__n=0, this=0xb0) at /usr/include/c++/8/bits/stl_deque.h:230
#2  std::_Deque_iterator<nv50_ir::ValueRef, nv50_ir::ValueRef&, nv50_ir::ValueRef*>::operator[] (__n=0, this=0xb0) at /usr/include/c++/8/bits/stl_deque.h:247
#3  std::deque<nv50_ir::ValueRef, std::allocator<nv50_ir::ValueRef> >::operator[] (__n=0, this=0xa0) at /usr/include/c++/8/bits/stl_deque.h:1404
#4  nv50_ir::Instruction::getSrc (s=0, this=0x0)
    at ../src/gallium/drivers/nouveau/codegen/nv50_ir.h:827
#5  nv50_ir::NVC0LegalizeSSA::handleDIV (this=0x7ffd7753af60, i=0x55d2e1b132a0)
    at ../src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.cpp:54
#6  0x00007fc7191cb4b3 in nv50_ir::NVC0LegalizeSSA::visit (
    this=0x7ffd7753af60, bb=<optimized out>)
    at ../src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.cpp:334
#7  0x00007fc719111928 in nv50_ir::Pass::doRun (this=0x7ffd7753af60, 
    func=<optimized out>, ordered=<optimized out>, skipPhi=true)
    at ../src/gallium/drivers/nouveau/codegen/nv50_ir_bb.cpp:500
#8  0x00007fc7191119f4 in nv50_ir::Pass::doRun (this=0x7ffd7753af60, 
    prog=<optimized out>, ordered=false, skipPhi=true)
    at ../src/gallium/drivers/nouveau/codegen/nv50_ir_inlines.h:413

Build & PC specs:
CPU: Intel Core i7-5820k 

OS: Ubuntu 19.04
libdrm: git-5db0f7692d1fdf05f9f6c0c02ffa5a5f4379c1f3
Mesa: git-a110a8090d
Xf86-video-nouveau: 1.0.16
Linux kernel version: 5.0.0-16-generic

This bug was found with GraphicsFuzz: https://github.com/google/graphicsfuzz
Comment 1 Ilia Mirkin 2019-07-18 15:49:27 UTC

      Instruction *ld = i->getSrc(s)->getInsn();
      assert(ld->getSrc(0) != NULL);

We must end up propagating the zero imm directly into DIV's args. This is generally legal even for ops that don't allow imms because of the RZ thing. However in this case ... it screws things up, since we have to move the value to a fixed reg.

It looks like the assert() is just misplaced there. It should go into the "else" clause below and all will be well... we handle the "!ld" / "ld is not a load/mov" cases already just fine.
Comment 2 mmgrqnv 2019-07-26 13:09:04 UTC
*** Bug 111218 has been marked as a duplicate of this bug. ***
Comment 3 GitLab Migration User 2019-09-18 20:49:15 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/mesa/mesa/issues/1187.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.