In my application I need to iterate over the contents of a file to make hashes of fixed-size chunks of the file. The end goal is to implement Amazon Glacier's Tree Hash algorithm, I almost verbatim copied the code from their documentation.
The problem happens when I run the following code through SonarQube though:
byte[] buff = new byte[Mio];
int bytesRead;
while ((bytesRead = await inputStream.ReadAsync(buff, 0, Mio)) > 0) {
// Process the bytes read
}
I have a Roslyn issue on the line with the while loop. The issue is "Change the 'ReadAsync' method call to use the 'Stream.ReadAsync(Memory, CancellationToken)' overload". According to the description, it is because methods using the Memory class are more efficient than those using basic arrays.
That may be true when the class can used from end to end. The thing is, I need to feed the data to the ComputeHash method of a HashAlgorithm, and they don't have any override accepting a Memory. This means I must use the ToArray method of the Memory, which makes a copy of the data. This doesn't sound very efficient to me.
I know it is possible to create a Memory instance by passing an existing array to its constructor, like this:
byte[] buff = new byte[Mio];
Memory<byte> memory = new Memory<byte>(buff);
int bytesRead;
while ((bytesRead = await inputStream.ReadAsync(memory)) > 0) {
// Use `buff` to access the bytes
}
However the documentation is unclear whether the array passed to the constructor is actually used as the underlying storage for the Memory instance.
Thus, here are my questions:
- How can I directly feed the data from a
Memoryto aHashAlgorithminstance? I'm talking about any instance of a class that derives fromHashAlgorithm, not specifically the SHA256 algorithm. My implementation is not restricted to SHA256 unlike the Glacier one. - Is the data stored in the
Memoryinstance also accesible in the array used to create it? - Is there another way to access the data stored in the
Memoryinstance as an array, without copy? - Failing that, how can I silence an external issue in SonarQube (Roslyn warning in this case)? I don't have the dropdown to change its status like normal Sonar issues.
EDIT Adding additional info on how the code works: It's the first part of AWS's example of computing a Glacier Tree Hash, the part that computes the first hashes of 1Mio blocks from the file.
These are the contents of the while loop above:
// Constructor of the class
// The class implements IDisposable to properly dispose of the Algorithm field
// Constructor is called like this
// `using TreeHash treeHash = new TreeHash(System.Security.Cryptography.SHA512.Create());`
public TreeHash(HashAlgorithm algo) {
this.Algorithm = algo;
}
// Chunk hash generation loop
// first part of the tree hash algorithm
byte[][] chunkHashes = new byte[numChunks][];
byte[] buff = new byte[Mio];
int bytesRead;
int idx = 0;
while ((bytesRead = await inputStream.ReadAsync(buff, 0, Mio)) > 0) {
chunkHashes[idx++] = this.ComputeHash(buff, bytesRead);
}
// Quick wrapper around the hash algorithm
// Also used by the second part of the tree hash computation
private byte[] ComputeHash(byte[] data, int count) => this.Algorithm.ComputeHash(data, 0, count);
I use the unprefixed versions of the hash algorithms by default but I can probably switch to the managed versions. And if needed the method can become non-async.