Skip to content

fix(gpu): fix memory leak and buffer sizing in f128 FFT host functions - #3825

Open
pdroalves wants to merge 4 commits into
mainfrom
pa/fix/fourier_leak
Open

fix(gpu): fix memory leak and buffer sizing in f128 FFT host functions#3825
pdroalves wants to merge 4 commits into
mainfrom
pa/fix/fourier_leak

Conversation

@pdroalves

@pdroalves pdroalves commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

This PR fixes several memory management issues in the f128 FFT host functions and the 128-bit BSK conversion, found while investigating a memory leak in host_fourier_transform_forward_as_torus_f128.

Memory leak in the f128 FFT host functions

host_fourier_transform_forward_as_integer_f128, host_fourier_transform_forward_as_torus_f128, and host_fourier_transform_backward_as_torus_f128 allocated a global scratch buffer for the FFT kernel but never freed it. The cleanup block only released d_standard, d_re0/d_re1/d_im0/d_im1.

Scratch buffer allocated in elements instead of bytes

The same buffer was sized with safe_mul(number_of_samples, N/2, 4), but cuda_malloc_async takes bytes, so the allocation was 8x too small (missing the sizeof(double) factor). Any call taking the no-shared-memory (NOSM) kernel path wrote out of bounds. The same defect existed in convert_u128_to_f128_and_forward_fft_128 (bootstrapping_key.cuh), which is used by the 128-bit BSK conversion.

Device buffers not sized for batched calls

The three FFT host functions launch number_of_samples kernel blocks, each indexing its own sample slice, but all device buffers and host/device copies were sized for a single sample. Calls with number_of_samples > 1 wrote out of bounds. Buffers and copies are now sized for the whole batch. (Current callers, the GPU FFT tests, pass 1, so this was latent.)

Smaller cleanups

  • The global scratch is now allocated only on the NOSM path instead of issuing a 0-byte allocation on the shared-memory path; cuda_convert_lwe_programmable_bootstrap_key also initializes its scratch pointer to nullptr instead of a 0-byte allocation that was overwritten (and lost) by the NOSM branches.
  • cuda_drop_with_size_tracking_async is now an explicit no-op for null pointers, since cudaFreeAsync (unlike cudaFree) is not documented to accept them.
  • Added missing check_cuda_error(cudaGetLastError()) after kernel launches in the two as_torus FFT variants, and replaced C-style casts with static_cast in the touched code.

closes: please link all relevant issues

PR content/description

Check-list:

  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)
  • Relevant issues are marked as resolved/closed, related issues are linked in the description
  • Check for breaking changes (including serialization changes) and add them to commit message following the conventional commit specification

@pdroalves
pdroalves requested a review from a team as a code owner August 13, 2026 18:30
@cla-bot cla-bot Bot added the cla-signed label Aug 13, 2026
@github-actions

Copy link
Copy Markdown

Backward-compat snapshot: everything looks good! No backward-compatibility issues detected.

@github-actions

Copy link
Copy Markdown

Forward Compatibility Matrix

TYPE 1.5.5 loads 1.6.3 data 1.5.5 loads 1.7.0 data 1.6.3 loads 1.7.0 data 1.5.5 loads nightly data 1.6.3 loads nightly data 1.7.0 loads nightly data
CompactPublicKey FAIL: invalid value: integer 1, expected variant index 0 <= i < 1 FAIL: invalid value: integer 1, expected variant index 0 <= i < 1 OK FAIL: invalid value: integer 1, expected variant index 0 <= i < 1 OK OK
CompactPkeCrs OK OK OK OK OK OK
ProvenCompactCiphertextList FAIL: invalid value: integer 1, expected variant index 0 <= i < 1 FAIL: invalid value: integer 1, expected variant index 0 <= i < 1 OK FAIL: invalid value: integer 1, expected variant index 0 <= i < 1 OK OK

@guillermo-oyarzun guillermo-oyarzun left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good tricky catches, if we end up removing the host calls, then i would suggest to squash the commits.

}

template <class params>
__host__ void host_fourier_transform_forward_as_integer_f128(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually this function seems like dead code, probably that's why we didn't notice the problem, better to remove it in my opinion, unless @bbarbakadze left it there for some reason?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are not using it anywhere so I guess we can remove it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's used in the C++ tests. Let me double check.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, that method is only used in cuda_fourier_transform_forward_as_integer_f128_async, which is a method we expose to core_crypto to run the FFT. We don't use it anywhere, but I don't know if we shouldn't just keep it in case we want someday.

double2 *buffer = (double2 *)cuda_malloc_async(0, stream, gpu_index);
// global scratch is only allocated on the NOSM paths below; cuda_drop_async
// accepts the nullptr left by the FULLSM paths
double2 *buffer = nullptr;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i guess this buffer thing here was not much of a problem in practice cause we don't use the NOSM flavor, and in the worse case we were allocating a 0 size. Your version seems cleaner

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants