2 votes

Accéder en toute sécurité aux données d'un MemoryStream

Supposons que je dispose d'un MemoryStream et une fonction qui opère sur des octets.

Le code actuel est à peu près le suivant :

void caller()
{
    MemoryStream ms = // not important
    func(ms.GetBuffer(), 0, (int)ms.Length);
}

void func(byte[] buffer, int offset, int length)
{
    // not important
}

Je ne peux pas changer func mais j'aimerais réduire au minimum la possibilité de modifier les données du flux à partir de l'application func .

Comment pourrais-je / devrais-je réécrire le code pour m'assurer que les données du flux ne seront pas modifiées ?

Ou ce n'est pas possible ?

EDITAR:

Je suis désolé, je n'ai pas mentionné que j'aimerais ne pas faire de copies des données.

5voto

Austin Salonen Points 28057

Appeler .ToArray .

func(ms.GetBuffer().ToArray(), 0, (int)ms.Length);

En MSDN (souligné par moi) :

Notez que la mémoire tampon contient des octets alloués qui peuvent être inutilisés. Par exemple, si la chaîne "test" est écrite dans l'objet MemoryStream la longueur de la mémoire tampon renvoyée par GetBuffer est de 256, et non de 4, avec 252 octets inutilisés. Pour obtenir uniquement les données contenues dans la mémoire tampon, utilisez la méthode ToArray ; cependant, ToArray crée une copie des données en mémoire.


Idéalement, vous devriez modifier func de prendre un IEnumerable<byte> . Une fois qu'une méthode possède le tableau, vous êtes sûr qu'elle ne modifiera pas les données si vous ne le souhaitez pas. Si le contrat était de fournir IEnumerable<byte> Le responsable de la mise en œuvre devra décider s'il a besoin d'une copie pour l'éditer ou non.

3voto

Alexei Levenkov Points 49945

Si vous ne pouvez pas faire de copie (ToArray comme suggéré dans d'autres réponses) et que vous ne pouvez pas changer la signature de l'élément func il ne reste plus qu'à essayer de valider que la fonction n'a pas modifié les données.

Vous pouvez calculer une sorte de hachage avant/après l'appel et vérifier s'il est identique. Cela ne garantira pas que func n'a pas modifié les données sous-jacentes (en raison des collisions de hachage), mais cela vous donnera au moins une bonne chance de savoir si cela s'est produit. Cela peut être utile pour le code de non-production...

La véritable solution consiste soit à fournir une copie des données au code non fiable, soit à passer une interface/objet enveloppant qui ne permet pas de modifier les données (ce qui nécessite des modifications/réécritures de la signature pour le code func ).

2voto

Roger Lipscombe Points 34344

Copier les données hors du flux en utilisant ms.ToArray() . Il est évident qu'il y aura une baisse de performance.

2voto

dtb Points 104373

Il n'est pas possible de ne transmettre qu'une "tranche" d'un tableau à une méthode. Vous devez passer une copie du tableau à la méthode et copier le résultat en retour :

byte[] slice = new byte[length];
Buffer.BlockCopy(bytes, offset, slice, 0, length);
func(slice, 0, length);
Buffer.BlockCopy(slice, 0, bytes, offset, length);

ou, si vous pouvez modifier la méthode, vous passez une sorte d'objet proxy qui enveloppe le tableau et vérifie pour chaque accès s'il est dans la plage autorisée :

class ArrayView<T>
{
    private T[] array;
    private int offset;
    private int length;

    public T this[int index]
    {
        get
        {
            if (index < offset || index >= offset + length)
                throw new ArgumentOutOfRange("index");
            return array[index];
        }
        set
        {
            if (index < offset || index >= offset + length)
                throw new ArgumentOutOfRange("index");
            array[index] = value;
        }
    }
}

0voto

Kjartan Points 5805

Essayez-vous de vous assurer que func() n'est jamais en mesure de modifier le flux de mémoire, ou est-il suffisant que votre code puisse lancer une exception si quelque chose se produit dans le flux de mémoire ? est changé ? On dirait que vous voulez faire quelque chose comme.. :

void caller()
{
    MemoryStream ms = // not important
    var checksum = CalculateMyChecksum(ms);
    func(ms.GetBuffer(), 0, (int)ms.Length);
    if(checksum != CalculateMyChecksum(ms)){
        throw new Exception("Hey! Someone has been fiddling with my memory!");
    }
}

Cependant, je ne me sentirais pas à l'aise de recommander cette solution pour des tâches importantes ou critiques. Pourriez-vous nous donner plus d'informations ? Il existe peut-être une meilleure solution à votre problème et un moyen de l'éviter complètement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X