static private NegativeSize ( ) : |
||
리턴 |
/// <summary> /// Sets currentLimit to (current position) + byteLimit. This is called /// when descending into a length-delimited embedded message. The previous /// limit is returned. /// </summary> /// <returns>The old limit.</returns> internal int PushLimit(int byteLimit) { if (byteLimit < 0) { throw InvalidProtocolBufferException.NegativeSize(); } byteLimit += totalBytesRetired + bufferPos; int oldLimit = currentLimit; if (byteLimit > oldLimit) { throw InvalidProtocolBufferException.TruncatedMessage(); } currentLimit = byteLimit; RecomputeBufferSizeAfterLimit(); return(oldLimit); }
/// <summary> /// Sets currentLimit to (current position) + byteLimit. This is called /// when descending into a length-delimited embedded message. The previous /// limit is returned. /// </summary> /// <returns>The old limit.</returns> public static int PushLimit(ref ParserInternalState state, int byteLimit) { if (byteLimit < 0) { throw InvalidProtocolBufferException.NegativeSize(); } byteLimit += state.totalBytesRetired + state.bufferPos; int oldLimit = state.currentLimit; if (byteLimit > oldLimit) { throw InvalidProtocolBufferException.TruncatedMessage(); } state.currentLimit = byteLimit; RecomputeBufferSizeAfterLimit(ref state); return(oldLimit); }
/// <summary> /// Reads and discards <paramref name="size"/> bytes. /// </summary> /// <exception cref="InvalidProtocolBufferException">the end of the stream /// or the current limit was reached</exception> public static void SkipRawBytes(ref ReadOnlySpan <byte> buffer, ref ParserInternalState state, int size) { if (size < 0) { throw InvalidProtocolBufferException.NegativeSize(); } if (state.totalBytesRetired + state.bufferPos + size > state.currentLimit) { // Read to the end of the stream anyway. SkipRawBytes(ref buffer, ref state, state.currentLimit - state.totalBytesRetired - state.bufferPos); // Then fail. throw InvalidProtocolBufferException.TruncatedMessage(); } if (size <= state.bufferSize - state.bufferPos) { // We have all the bytes we need already. state.bufferPos += size; } else { // Skipping more bytes than are in the buffer. First skip what we have. int pos = state.bufferSize - state.bufferPos; state.bufferPos = state.bufferSize; // TODO: If our segmented buffer is backed by a Stream that is seekable, we could skip the bytes more efficiently // by simply updating stream's Position property. This used to be supported in the past, but the support was dropped // because it would make the segmentedBufferHelper more complex. Support can be reintroduced if needed. state.segmentedBufferHelper.RefillBuffer(ref buffer, ref state, true); while (size - pos > state.bufferSize) { pos += state.bufferSize; state.bufferPos = state.bufferSize; state.segmentedBufferHelper.RefillBuffer(ref buffer, ref state, true); } state.bufferPos = size - pos; } }
/// <summary> /// Reads a fixed size of bytes from the input. /// </summary> /// <exception cref="InvalidProtocolBufferException"> /// the end of the stream or the current limit was reached /// </exception> internal byte[] ReadRawBytes(int size) { if (size < 0) { throw InvalidProtocolBufferException.NegativeSize(); } if (totalBytesRetired + bufferPos + size > currentLimit) { // Read to the end of the stream (up to the current limit) anyway. SkipRawBytes(currentLimit - totalBytesRetired - bufferPos); // Then fail. throw InvalidProtocolBufferException.TruncatedMessage(); } if (size <= bufferSize - bufferPos) { // We have all the bytes we need already. byte[] bytes = new byte[size]; ByteArray.Copy(buffer, bufferPos, bytes, 0, size); bufferPos += size; return(bytes); } else if (size < buffer.Length) { // Reading more bytes than are in the buffer, but not an excessive number // of bytes. We can safely allocate the resulting array ahead of time. // First copy what we have. byte[] bytes = new byte[size]; int pos = bufferSize - bufferPos; ByteArray.Copy(buffer, bufferPos, bytes, 0, pos); bufferPos = bufferSize; // We want to use RefillBuffer() and then copy from the buffer into our // byte array rather than reading directly into our byte array because // the input may be unbuffered. RefillBuffer(true); while (size - pos > bufferSize) { Buffer.BlockCopy(buffer, 0, bytes, pos, bufferSize); pos += bufferSize; bufferPos = bufferSize; RefillBuffer(true); } ByteArray.Copy(buffer, 0, bytes, pos, size - pos); bufferPos = size - pos; return(bytes); } else { // The size is very large. For security reasons, we can't allocate the // entire byte array yet. The size comes directly from the input, so a // maliciously-crafted message could provide a bogus very large size in // order to trick the app into allocating a lot of memory. We avoid this // by allocating and reading only a small chunk at a time, so that the // malicious message must actually *be* extremely large to cause // problems. Meanwhile, we limit the allowed size of a message elsewhere. // Remember the buffer markers since we'll have to copy the bytes out of // it later. int originalBufferPos = bufferPos; int originalBufferSize = bufferSize; // Mark the current buffer consumed. totalBytesRetired += bufferSize; bufferPos = 0; bufferSize = 0; // Read all the rest of the bytes we need. int sizeLeft = size - (originalBufferSize - originalBufferPos); List <byte[]> chunks = new List <byte[]>(); while (sizeLeft > 0) { byte[] chunk = new byte[Math.Min(sizeLeft, buffer.Length)]; int pos = 0; while (pos < chunk.Length) { int n = (input == null) ? -1 : input.Read(chunk, pos, chunk.Length - pos); if (n <= 0) { throw InvalidProtocolBufferException.TruncatedMessage(); } totalBytesRetired += n; pos += n; } sizeLeft -= chunk.Length; chunks.Add(chunk); } // OK, got everything. Now concatenate it all into one buffer. byte[] bytes = new byte[size]; // Start by copying the leftover bytes from this.buffer. int newPos = originalBufferSize - originalBufferPos; ByteArray.Copy(buffer, originalBufferPos, bytes, 0, newPos); // And now all the chunks. foreach (byte[] chunk in chunks) { Buffer.BlockCopy(chunk, 0, bytes, newPos, chunk.Length); newPos += chunk.Length; } // Done. return(bytes); } }
/// <summary> /// Reads a fixed size of bytes from the input. /// </summary> /// <exception cref="InvalidProtocolBufferException"> /// the end of the stream or the current limit was reached /// </exception> public static byte[] ReadRawBytes(ref ReadOnlySpan <byte> buffer, ref ParserInternalState state, int size) { if (size < 0) { throw InvalidProtocolBufferException.NegativeSize(); } if (state.totalBytesRetired + state.bufferPos + size > state.currentLimit) { // Read to the end of the stream (up to the current limit) anyway. SkipRawBytes(ref buffer, ref state, state.currentLimit - state.totalBytesRetired - state.bufferPos); // Then fail. throw InvalidProtocolBufferException.TruncatedMessage(); } if (size <= state.bufferSize - state.bufferPos) { // We have all the bytes we need already. byte[] bytes = new byte[size]; buffer.Slice(state.bufferPos, size).CopyTo(bytes); state.bufferPos += size; return(bytes); } else if (size < buffer.Length || size < state.segmentedBufferHelper.TotalLength) { // Reading more bytes than are in the buffer, but not an excessive number // of bytes. We can safely allocate the resulting array ahead of time. // First copy what we have. byte[] bytes = new byte[size]; var bytesSpan = new Span <byte>(bytes); int pos = state.bufferSize - state.bufferPos; buffer.Slice(state.bufferPos, pos).CopyTo(bytesSpan.Slice(0, pos)); state.bufferPos = state.bufferSize; // We want to use RefillBuffer() and then copy from the buffer into our // byte array rather than reading directly into our byte array because // the input may be unbuffered. state.segmentedBufferHelper.RefillBuffer(ref buffer, ref state, true); while (size - pos > state.bufferSize) { buffer.Slice(0, state.bufferSize) .CopyTo(bytesSpan.Slice(pos, state.bufferSize)); pos += state.bufferSize; state.bufferPos = state.bufferSize; state.segmentedBufferHelper.RefillBuffer(ref buffer, ref state, true); } buffer.Slice(0, size - pos) .CopyTo(bytesSpan.Slice(pos, size - pos)); state.bufferPos = size - pos; return(bytes); } else { // The size is very large. For security reasons, we can't allocate the // entire byte array yet. The size comes directly from the input, so a // maliciously-crafted message could provide a bogus very large size in // order to trick the app into allocating a lot of memory. We avoid this // by allocating and reading only a small chunk at a time, so that the // malicious message must actually *be* extremely large to cause // problems. Meanwhile, we limit the allowed size of a message elsewhere. List <byte[]> chunks = new List <byte[]>(); int pos = state.bufferSize - state.bufferPos; byte[] firstChunk = new byte[pos]; buffer.Slice(state.bufferPos, pos).CopyTo(firstChunk); chunks.Add(firstChunk); state.bufferPos = state.bufferSize; // Read all the rest of the bytes we need. int sizeLeft = size - pos; while (sizeLeft > 0) { state.segmentedBufferHelper.RefillBuffer(ref buffer, ref state, true); byte[] chunk = new byte[Math.Min(sizeLeft, state.bufferSize)]; buffer.Slice(0, chunk.Length) .CopyTo(chunk); state.bufferPos += chunk.Length; sizeLeft -= chunk.Length; chunks.Add(chunk); } // OK, got everything. Now concatenate it all into one buffer. byte[] bytes = new byte[size]; int newPos = 0; foreach (byte[] chunk in chunks) { Buffer.BlockCopy(chunk, 0, bytes, newPos, chunk.Length); newPos += chunk.Length; } // Done. return(bytes); } }