# Buggy code
def copy_to_host(self, ary=None, stream=0):
    """Copy ``self`` to ``ary`` or create a new Numpy ndarray
    if ``ary`` is ``None``.

    If a CUDA ``stream`` is given, then the transfer will be made
    asynchronously as part as the given stream.  Otherwise, the transfer is
    synchronous: the function returns after the copy is finished.

    Always returns the host array.

    Example::

        import numpy as np
        from numba import cuda

        arr = np.arange(1000)
        d_arr = cuda.to_device(arr)

        my_kernel[100, 100](d_arr)

        result_array = d_arr.copy_to_host()
    """
    stream = self._default_stream(stream)
    if ary is None:
        hostary = np.empty(shape=self.alloc_size, dtype=np.byte)
    else:
        check_array_compatibility(self, ary)
        hostary = ary

    assert self.alloc_size >= 0, "Negative memory size"
    if self.alloc_size != 0:
        _driver.device_to_host(hostary, self, self.alloc_size, stream=stream)

    if ary is None:
        if self.size == 0:
            hostary = np.ndarray(shape=self.shape, dtype=self.dtype, buffer=hostary)
        else:
            hostary = np.ndarray(
                shape=self.shape, dtype=self.dtype, strides=self.strides, buffer=hostary
            )
    return hostary


# Traceback (ValueError)
Traceback (most recent call last):
File "pyarrow/tests/numba_bug.py", line 9, in <module>
d_arr[::-1].copy_to_host()
File "/home/pearu/miniconda3/envs/pyarrow-dev/lib/python3.7/site-packages/numba/cuda/cudadrv/devices.py", line 212, in _require_cuda_context
return fn(*args, **kws)
File "/home/pearu/miniconda3/envs/pyarrow-dev/lib/python3.7/site-packages/numba/cuda/cudadrv/devicearray.py", line 240, in copy_to_host
strides=self.strides, buffer=hostary)
ValueError: strides is incompatible with shape of requested array and size of buffer

# Fixed code
def copy_to_host(self, ary=None, stream=0):
    """Copy ``self`` to ``ary`` or create a new Numpy ndarray
    if ``ary`` is ``None``.

    If a CUDA ``stream`` is given, then the transfer will be made
    asynchronously as part as the given stream.  Otherwise, the transfer is
    synchronous: the function returns after the copy is finished.

    Always returns the host array.

    Example::

        import numpy as np
        from numba import cuda

        arr = np.arange(1000)
        d_arr = cuda.to_device(arr)

        my_kernel[100, 100](d_arr)

        result_array = d_arr.copy_to_host()
    """
    if any(s < 0 for s in self.strides):
        msg = "D->H copy not implemented for negative strides: {}"
        raise NotImplementedError(msg.format(self.strides))
    assert self.alloc_size >= 0, "Negative memory size"
    stream = self._default_stream(stream)
    if ary is None:
        hostary = np.empty(shape=self.alloc_size, dtype=np.byte)
    else:
        check_array_compatibility(self, ary)
        hostary = ary

    if self.alloc_size != 0:
        _driver.device_to_host(hostary, self, self.alloc_size, stream=stream)

    if ary is None:
        if self.size == 0:
            hostary = np.ndarray(shape=self.shape, dtype=self.dtype, buffer=hostary)
        else:
            hostary = np.ndarray(
                shape=self.shape, dtype=self.dtype, strides=self.strides, buffer=hostary
            )
    return hostary