cornell-zhang / heterocl

HeteroCL: A Multi-Paradigm Programming Infrastructure for Software-Defined Heterogeneous Computing
https://cornell-zhang.github.io/heterocl/
Apache License 2.0
322 stars 92 forks source link

Null pointer access causes SegFault when using `reuse_at` #222

Closed chhzh123 closed 4 years ago

chhzh123 commented 4 years ago

I use the test case in test_schedule_memory.py, and it fails when executing hcl.build.

def test_reuse_blur_x():
    hcl.init()
    A = hcl.placeholder((10, 10))
    B = hcl.compute((10, 8), lambda y, x: A[y, x] + A[y, x+1] + A[y, x+2])
    s = hcl.create_schedule([A, B])
    RB = s.reuse_at(A, s[B], B.axis[1])
    f = hcl.build(s)

It generates a segmentation fault without other output messages.

After carefully tracing, I find this bug happens in L305 of generate_reuse_buffer.cc, where alloc is trying to access its buffer_var member. However, alloc is a null pointer, causing invalid memory access, i.e. SegFault.

L300-L305 is shown below. No conditional check is enforced to the returned alloc pointer, making the program crash later.

        const AttrStmt* attr_alloc = node->body.as<AttrStmt>();
        const Allocate* alloc = attr_alloc->body.as<Allocate>();
        Array<Expr> normal_shape;
        for (int i = reuse_shape.size()-1; i >= 0; i--)
          normal_shape.push_back(reuse_shape[i]);
        shape_map_[alloc->buffer_var.get()] = normal_shape;

I have tested this case on two computers, and both of them failed. The configurations are:

chhzh123 commented 4 years ago

@Hecmay said the problem results from schedule.ScheduleOps in hcl.lower.

The lowered IR after this command is shown below.

// attr [extern(placeholder0.reuse, 0x29fb1f0)] realize_scope = ""
realize placeholder0.reuse() {
  // attr [[buffer(placeholder0, 0x2ccaa50), Tensor(shape=[10, 10], op.name=placeholder0)]] buffer_bind_scope = tvm_tuple(0, 10, 0, 10)
  // attr [[buffer(placeholder0.reuse, 0x2b2b5e0), Tensor(shape=[], op.name=placeholder0.reuse)]] buffer_bind_scope = tvm_tuple()
  produce placeholder0.reuse {
    // attr [0] extern_scope = 0
    0
  }
  // attr [extern(compute0, 0x2d0fdb0)] realize_scope = ""
  realize compute0([0, 10], [0, 8]) {
    // attr [[buffer(placeholder0, 0x2ccaa50), Tensor(shape=[10, 10], op.name=placeholder0)]] buffer_bind_scope = tvm_tuple(0, 10, 0, 10)
    // attr [[buffer(compute0, 0x2b2cc50), Tensor(shape=[10, 8], op.name=compute0)]] buffer_bind_scope = tvm_tuple(0, 10, 0, 8)
    produce compute0 {
      // attr [0] extern_scope = 0
      for (y, 0, 10) {
        for (x, 0, 8) {
          reuse placeholder0
          // attr [          for (y, 0, 10) {
            // attr [iter_var(y, Range(min=0, extent=10))] loop_scope = y
            for (x, 0, 8) {
              // attr [iter_var(x, Range(min=0, extent=8))] loop_scope = x
              compute0[(x + (y*8))] = int32((int34((int33(placeholder0[(x + (y*10))]) + int33(placeholder0[((x + 1) + (y*10))]))) + int34(placeholder0[((x + 2) + (y*10))])))
            }
          }
] attach_scope = "compute0"
          compute0[(x + (y*8))] = int32((int34((int33(placeholder0[(x + (y*10))]) + int33(placeholder0[((x + 1) + (y*10))]))) + int34(placeholder0[((x + 2) + (y*10))])))
        }
      }
    }
  }
}
seanlatias commented 4 years ago

Solved by #226.