Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SymmetricMatrix::GetEigen memory corruption #59

Closed
chpatrick opened this issue Mar 4, 2021 · 8 comments
Closed

SymmetricMatrix::GetEigen memory corruption #59

chpatrick opened this issue Mar 4, 2021 · 8 comments
Labels

Comments

@chpatrick
Copy link

I found some memory corruption in the SymmetricMatrix::GetEigen function. I think it's caused by the following line:

pEigenValue[i] = pRowHeader[i][i];

In this for loop i goes up to i < dwDimension - 1, but pEigenValue is of size dwMaxRange, and dwMaxRange <= dwDimension.

I have a version that replaces that function with a call to the Eigen library here: chpatrick@d009630

@chpatrick chpatrick changed the title SymmetricMatrix::GetEigen SymmetricMatrix::GetEigen memory corruption Mar 4, 2021
@nh2
Copy link

nh2 commented Mar 4, 2021

I have a version that replaces that function with a call to the Eigen library here: chpatrick@d009630

This also replaces the O(n^3) sorting (!) algorithm used so far to emit eivenvalues/vector in descending order.

// Sort eigenvalues and corresponding vectors.
for (size_t i = 0; i < dwDimension - 1; i++)
{
for (size_t j = i + 1; j < dwDimension; j++)
{
if (pEigenValue[j] > pEigenValue[i])
{
std::swap(pEigenValue[i], pEigenValue[j]);
for (size_t k = 0; k < dwDimension; k++)
{
std::swap(pRowHeader[k][i], pRowHeader[k][j]);
}
}
}
}

So far if you called GetEigen() on a 14k-square matrix, just the sorting of the results of at the end would require 14000^3 = 2744000000000 = ~3 Tera-swaps.

@nh2
Copy link

nh2 commented Mar 5, 2021

This also replaces the O(n^3) sorting (!) algorithm

Embarassingly, I am wrong; Eigen also uses a O(n^3) sort:

https://gitlab.com/libeigen/eigen/-/blob/6cbb3038ac48cb5fe17eba4dfbf26e3e798041f1/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h#L535-551

// TODO use a better sort algorithm !!

@walbourn walbourn added the bug label Mar 6, 2021
@walbourn
Copy link
Member

The test at the start of GetEigen establishes that dwMaxRange >= dwDimension, but you wrote <=.

            if (dwDimension < dwMaxRange
                || dwMaxRange == 0
                || dwDimension == 0)
            {
                return false;
            }

@chpatrick
Copy link
Author

chpatrick commented May 30, 2021

No, that check establishes that dwMaxRange <= dwDimension, otherwise it returns false.

The opposite wouldn't make any sense because the goal of this function is to compute only dwMaxRange eigenvalues out of a maximum of dwDimension. The memory corruption is caused by mistakenly copying out dwDimension - 1 many eigenvalues, even if only dwMaxRange were requested (and space allocated for).

@walbourn walbourn reopened this May 30, 2021
@walbourn
Copy link
Member

walbourn commented May 30, 2021

OK, I'll take another look.

I'll also integrate the opt-in use of the Eigen library to my CMakeList.txt, probably through a build option. For my vcpkg port, I should be able to make use of the eigen3 port for the dependency. This is certainly the more robust & reliable thing to use instead of the 'home-rolled' GetEigen the library currently uses, but I don't want to force all users to take another dependency.

@walbourn
Copy link
Member

walbourn commented May 31, 2021

OK, I think the problem is that the algorithm in that header is trying to use pEigenValues as the temporary space as well as the final answer, which is obviously going to fail in some conditions. It looks like in most cases it worked by accident because the allocation within the library of the return eigen vectors gave it sufficient space to not crash IIF it was allocated right after the value:

m_pfEigenValue = new (std::nothrow) float[dwSelectedDimension];
m_pfEigenVector = new (std::nothrow) float[m_dwMatrixDimension * dwSelectedDimension];

@walbourn
Copy link
Member

Fixed in this commit

@walbourn
Copy link
Member

Added an opt-in build-option to CMake to support using the Eigen library. See this commit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants