# Buggy code
def _exec_fftn(
    a,
    direction,
    value_type,
    norm,
    axes,
    overwrite_x,
    plan=None,
    out=None,
    out_size=None,
):
    fft_type = _convert_fft_type(a.dtype, value_type)

    if a.flags.c_contiguous:
        order = "C"
    elif a.flags.f_contiguous:
        order = "F"
    else:
        raise ValueError("a must be contiguous")

    curr_plan = cufft.get_current_plan()
    if curr_plan is not None:
        plan = curr_plan
        # don't check repeated usage; it's done in _default_fft_func()
    if plan is None:
        # generate a plan
        plan = _get_cufft_plan_nd(
            a.shape, fft_type, axes=axes, order=order, out_size=out_size
        )
    else:
        if not isinstance(plan, cufft.PlanNd):
            raise ValueError("expected plan to have type cufft.PlanNd")
        if order != plan.order:
            raise ValueError(
                "array orders mismatch (plan: {}, input: {})".format(plan.order, order)
            )
        if a.flags.c_contiguous:
            expected_shape = [a.shape[ax] for ax in axes]
            if value_type == "C2R":
                expected_shape[-1] = out_size
        else:
            # plan.shape will be reversed for Fortran-ordered inputs
            expected_shape = [a.shape[ax] for ax in axes[::-1]]
            # TODO(leofang): modify the shape for C2R
        expected_shape = tuple(expected_shape)
        if expected_shape != plan.shape:
            raise ValueError(
                "The cuFFT plan and a.shape do not match: "
                "plan.shape = {}, expected_shape={}, a.shape = {}".format(
                    plan.shape, expected_shape, a.shape
                )
            )
        if fft_type != plan.fft_type:
            raise ValueError("cuFFT plan dtype mismatch.")
        if value_type != "C2C":
            if axes[-1] != plan.last_axis:
                raise ValueError("The last axis for R2C/C2R mismatch")
            if out_size != plan.last_size:
                raise ValueError("The size along the last R2C/C2R axis mismatch")

    # TODO(leofang): support in-place transform for R2C/C2R
    if overwrite_x and value_type == "C2C":
        out = a
    elif out is None:
        out = plan.get_output_array(a, order=order)
    else:
        plan.check_output_array(a, out)
    plan.fft(a, out, direction)

    # normalize by the product of the shape along the transformed axes
    arr = a if fft_type in (cufft.CUFFT_R2C, cufft.CUFFT_D2Z) else out
    sz = _prod([arr.shape[ax] for ax in axes])
    if norm is None:
        if direction == cufft.CUFFT_INVERSE:
            out /= sz
    else:
        out /= math.sqrt(sz)

    return out


# Traceback (ValueError)
np.fft.fft(np.array([]))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<__array_function__ internals>", line 5, in fft
File "/path/to/python3.8/site-packages/numpy-1.18.2-py3.8-linux-x86_64.egg/numpy/fft/_pocketfft.py", line 188, in fft
output = _raw_fft(a, n, axis, False, True, inv_norm)
File "/path/to/python3.8/site-packages/numpy-1.18.2-py3.8-linux-x86_64.egg/numpy/fft/_pocketfft.py", line 57, in _raw_fft
raise ValueError("Invalid number of FFT data points (%d) specified."
ValueError: Invalid number of FFT data points (0) specified.
cupy.fft.fft(cupy.array([]))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/path/to/cupy/cupy/fft/fft.py", line 496, in fft
return _fft(a, (n,), (axis,), norm, cupy.cuda.cufft.CUFFT_FORWARD)
File "/path/to/cupy/cupy/fft/fft.py", line 175, in _fft
a = _fft_c2c(a, direction, norm, axes, overwrite_x, plan=plan)
File "/path/to/cupy/cupy/fft/fft.py", line 142, in _fft_c2c
a = _exec_fft(a, direction, 'C2C', norm, axis, overwrite_x, plan=plan)
File "/path/to/cupy/cupy/fft/fft.py", line 91, in _exec_fft
batch = a.size // a.shape[-1]
ZeroDivisionError: integer division or modulo by zero
cupy.fft.fft(cupy.array([]), n=0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/path/to/cupy/cupy/fft/fft.py", line 496, in fft
return _fft(a, (n,), (axis,), norm, cupy.cuda.cufft.CUFFT_FORWARD)
File "/path/to/cupy/cupy/fft/fft.py", line 155, in _fft
raise ValueError(
ValueError: Invalid number of FFT data points (0) specified.

# Fixed code
def _exec_fftn(
    a,
    direction,
    value_type,
    norm,
    axes,
    overwrite_x,
    plan=None,
    out=None,
    out_size=None,
):
    fft_type = _convert_fft_type(a.dtype, value_type)

    if a.flags.c_contiguous:
        order = "C"
    elif a.flags.f_contiguous:
        order = "F"
    else:
        raise ValueError("a must be contiguous")

    curr_plan = cufft.get_current_plan()
    if curr_plan is not None:
        plan = curr_plan
        # don't check repeated usage; it's done in _default_fft_func()
    if plan is None:
        # generate a plan
        plan = _get_cufft_plan_nd(
            a.shape, fft_type, axes=axes, order=order, out_size=out_size
        )
    else:
        if not isinstance(plan, cufft.PlanNd):
            raise ValueError("expected plan to have type cufft.PlanNd")
        if order != plan.order:
            raise ValueError(
                "array orders mismatch (plan: {}, input: {})".format(plan.order, order)
            )
        if a.flags.c_contiguous:
            expected_shape = [a.shape[ax] for ax in axes]
            if value_type == "C2R":
                expected_shape[-1] = out_size
        else:
            # plan.shape will be reversed for Fortran-ordered inputs
            expected_shape = [a.shape[ax] for ax in axes[::-1]]
            # TODO(leofang): modify the shape for C2R
        expected_shape = tuple(expected_shape)
        if expected_shape != plan.shape:
            raise ValueError(
                "The cuFFT plan and a.shape do not match: "
                "plan.shape = {}, expected_shape={}, a.shape = {}".format(
                    plan.shape, expected_shape, a.shape
                )
            )
        if fft_type != plan.fft_type:
            raise ValueError("cuFFT plan dtype mismatch.")
        if value_type != "C2C":
            if axes[-1] != plan.last_axis:
                raise ValueError("The last axis for R2C/C2R mismatch")
            if out_size != plan.last_size:
                raise ValueError("The size along the last R2C/C2R axis mismatch")

    # TODO(leofang): support in-place transform for R2C/C2R
    if overwrite_x and value_type == "C2C":
        out = a
    elif out is None:
        out = plan.get_output_array(a, order=order)
    else:
        plan.check_output_array(a, out)

    if out.size != 0:
        plan.fft(a, out, direction)

    # normalize by the product of the shape along the transformed axes
    arr = a if fft_type in (cufft.CUFFT_R2C, cufft.CUFFT_D2Z) else out
    sz = _prod([arr.shape[ax] for ax in axes])
    if norm is None:
        if direction == cufft.CUFFT_INVERSE:
            out /= sz
    else:
        out /= math.sqrt(sz)

    return out