Repository: opencv
Issue: cv::resize() with INTER_CUBIC on CV_32FC1 corrupts heap when using IPP
Labels: category: imgproc,incomplete,needs investigation

##### System information (version)
- OpenCV => 3.4.x, 4.x or higher
- Operating System / Platform => Linux, Ubuntu 18.04
- Compiler => gcc 7.5
- Other => CUDA 11.0

##### Detailed description

I detected a rather exotic bug located probably in IPP code for cv::resize() function. When upscaling and using multiple threads, the cv::resize() implementation will corrupt host heap allocation, resulting in double free, malloc problems and segfaults.

The bug manifests when using CUDA cudaMalloc()/cudaFree() calls from multiple threads and when using __multiple GPUs__. After some allocations and frees from mutliple threads, the host heap is corrupted and program fails.

If:
* the pixel type is not CV_32FC1 or CV64FC1
* or the interpolation is not INTER_CUBIC or INTER_LANCZOS4
* or if cv::setNumThreads(0) is set
* or I build OpenCV without IPP support, 

I cannot observe the heap corruption.

##### Steps to reproduce

I prepared the following CUDA random alloc/free "collider" multithreaded example, which fails with SEGFAULT or malloc error after some time. The threads randomly allocate and free CUDA device memory, with proper per-item mutex locking. Simultaneously, there is code which runs repeatedly cv::resize() on some small CV_32FC1 matrix.

Use attached CMakeLists.txt and cudatest.cpp source codes to reproduce the error. Note that you need to have more than one GPU in your machine to reproduce the error.

I tried OpenCV 3.4.12, 4.0.0, 4.3.0 and 4.5.0, always able to generate this bug.

`cudatest.cpp`:
```.cpp

#include <vector>
#include <cassert>
#include <thread>
#include <mutex>
#include <random>

#include <opencv2/imgproc.hpp>
#include <cuda_runtime_api.h>

const int NUMPTRS = 1024;
const int MEMSIZE = 1024*1024;
const int TRIALS  = 10000;

std::vector<void *> pointers(NUMPTRS, nullptr);
std::vector<std::mutex> locks(NUMPTRS);
std::vector<int> devices(NUMPTRS);

void openCVTest(int numTests)
{
    for (int i = 0; i < numTests; ++i)
    {
        cv::Mat src(64, 128, CV_32FC1), dst;
        cv::resize(src, dst, cv::Size(), 4.0f, 4.0f, cv::INTER_CUBIC);
    }

    fprintf(stderr, "OPENCV\n");
}

void testAllocFree(int device, int numTests)
{
    std::random_device rd;
    std::mt19937 gen(rd()); 
    std::uniform_int_distribution<> distrib;

    assert(cudaSetDevice(device) == cudaSuccess);
    fprintf(stderr, "[%d] %dx\n", device, numTests);

    for (int i = 0; i < numTests; ++i)
    {
        int index = distrib(gen)%NUMPTRS;
        std::lock_guard<std::mutex> guard(locks[index]);

        if (pointers[index] == nullptr)
        {
            assert(cudaMalloc(&pointers[index], MEMSIZE) == cudaSuccess);
            devices[index] = device;
        }
        else
        {
            assert(cudaSetDevice(devices[index]) == cudaSuccess);
            assert(cudaFree(pointers[index]) == cudaSuccess);
            assert(cudaSetDevice(device) == cudaSuccess);
            pointers[index] = nullptr;
        }
    }

    fprintf(stderr, "[%d] DONE\n", device);
}

int main(int argc, char * argv[])
{
    int numThreads = 64;
    
    int maxGpus;
    assert(cudaGetDeviceCount(&maxGpus) == cudaSuccess);
    fprintf(stderr, "Running on %d GPUs\n", maxGpus);
    
    std::vector<std::thread> threads;

    for (int i = 0; i < numThreads; ++i)
         threads.emplace_back(std::thread([i, maxGpus]() { testAllocFree(i%maxGpus, TRIALS); }));

    // cv::setNumThreads(0);
    openCVTest(numThreads*TRIALS);

    for (auto & t : threads)
        t.join();

    return 0;
}
 ```

`CMakeLists.txt`:
```
cmake_minimum_required(VERSION 3.10)
project(cudatest)

find_package(OpenCV REQUIRED)
find_package(CUDA REQUIRED)

add_executable(cudatest cudatest.cpp)
target_include_directories(cudatest PRIVATE ${CUDA_INCLUDE_DIRS})
target_link_libraries(cudatest PRIVATE opencv_core opencv_imgproc ${CUDA_LIBRARIES})
```