unitaryfund / qrack

Comprehensive, GPU accelerated framework for developing universal virtual quantum processors
https://qrack.readthedocs.io/en/latest/
GNU Lesser General Public License v3.0
174 stars 38 forks source link

Qrack API v8: Memory safety #977

Closed WrathfulSpatula closed 1 year ago

WrathfulSpatula commented 2 years ago

Right now, we're hearing rumblings that C++ is not "memory-safe" in comparison to Rust. A reasonable counterpoint to this particular brand of Rust evangelism, to the exclusion of C++, is that some have said, "Unsafe C++ is bad C++," meaning that a mature C++ program or library should achieve "memory safety" anyway, or it's simply poorly engineered code, and Rust doesn't immediately fix that other kind of problem.

Qrack has been vetted well enough to assert with reasonable confidence that it doesn't have leaks or mistakes in manual memory management. In fact, Qrack is completely "RAII," since around the time of the Qrack v7 API, and there are no occurrences of a bare new or delete keyword in the entire breadth of library internals, all instead being wrapped in "smart pointers," from C++11. However, Qrack effectively assumes that user input is exactly correct and not malicious to the underlying system. Neither of these conditions is actually guaranteed, and, if either assumption fails, Qrack is likely to produce segmentation faults, from incorrect or malicious input. These are not only difficult to catch and recover from in user code, but also a genuine security concern, we've learned well by now.

To set a reasonable but high-enough bar for "memory safety" in Qrack, we'd hypothetically like to never see a segmentation fault, in the case of bad input or otherwise. Ironically, for the C interface exposed to PyQrack, we basically can't guarantee this, since PyQrack deals in raw pointers to use the C interface. However, for static linkage, in C++11, it is possible to achieve this guarantee with reasonable effort directed into an API signature refactor: we don't have to pass raw pointers at all. Instead, we can usually or always rely on std::vector parameter inputs and check their size() for self-consistency, instead of passing in secondary length parameters alongside raw pointer parameters.

Call this Qrack API v8. Expect it around New Year, like the v7 release last year. The concern over "memory safety" is reasonable, but it's obviously worth investing in Qrack to support that guarantee in C++, rather than leaving for greener pastures. (I think there's an element of fashion to the current dialog around Rust vs. C/C++, when FORTRAN solved problems in computational linear algebra so well over 50 years ago that the same code is still in use, and I expect a similar "EOL" for C/C++, a long time from now, but the discussion of "memory safety" is not wholly or even mostly vacuous. I would have banged this out tonight, except for the disruption to downstream users, and except for more pressing development concerns in Qrack and other repositories I maintain.)

WrathfulSpatula commented 2 years ago

There might be cases in the shared library interface and elsewhere where this fundamental design pattern would force us to copy twice, into a vector as parameter and then into a Qrack internal array. We will prioritize speed in these cases. Honestly, I'm happy to accept easy gains in reducing the potential to segfault.