23. 배치 메시지 디코딩과 길이/개수 검증 (OOB / 메모리 증폭 / 부분 프레임)
난이도 중 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] C# - 배치(batch) 메시지 디코딩과 길이/개수 검증
// ----------------------------------------------------------------------------
// 시나리오 (프로토콜/직렬화 · 서버-서버):
// - 존 서버가 한 틱에 모인 여러 논리 메시지를 한 프레임으로 묶어 게이트웨이로 보낸다.
// - 와이어 포맷(리틀엔디안):
// [u16 count] 그 다음 count 개의 항목, 각 항목 = [u16 type][u16 len][len 바이트 payload]
// - 수신 측은 한 프레임(buf)을 받아 항목들로 풀어 처리 큐에 넣는다.
// - buf 는 네트워크에서 온 신뢰할 수 없는 바이트이며, 길이도 다양하다.
//
// 과제:
// 이 코드의 잠재적 문제를 모두 찾고, 손상되거나 악의적으로 조작된 프레임(예: 큰 count,
// 실제 남은 바이트보다 큰 len)이 들어왔을 때 무슨 일이 일어나는지 설명하라. 또 프레임이
// 덜 도착한 경우(부분 수신)의 동작도 함께 논하라. 수정안과 더 나은 설계를 제시하라.
// (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================
using System;
using System.Collections.Generic;
public struct Msg
{
public ushort Type;
public byte[] Payload;
}
public class BatchDecoder
{
public List<Msg> Decode(byte[] buf)
{
var list = new List<Msg>();
int off = 0;
ushort count = ReadU16(buf, ref off); // (A) 항목 개수
for (int i = 0; i < count; i++)
{
ushort type = ReadU16(buf, ref off); // (B) 타입
ushort len = ReadU16(buf, ref off); // (C) 항목 길이
var payload = new byte[len]; // (D) 길이만큼 선할당
Array.Copy(buf, off, payload, 0, len); // (E) 페이로드 복사
off += len;
list.Add(new Msg { Type = type, Payload = payload });
}
return list;
}
private static ushort ReadU16(byte[] b, ref int o) // (F) 경계 확인 없음
{
ushort v = (ushort)(b[o] | (b[o + 1] << 8));
o += 2;
return v;
}
} 결함 코드 · C++
// ============================================================================
// [코드리뷰 문제] C++ - 배치(batch) 메시지 디코딩과 길이/개수 검증
// ----------------------------------------------------------------------------
// 시나리오 (프로토콜/직렬화 · 서버-서버):
// - 존 서버가 한 틱에 모인 여러 논리 메시지를 한 프레임으로 묶어 게이트웨이로 보낸다.
// - 와이어 포맷(리틀엔디안):
// [u16 count] 그 다음 count 개의 항목, 각 항목 = [u16 type][u16 len][len 바이트 payload]
// - 수신 측은 한 프레임(data..data+size)을 받아 항목들로 풀어 처리한다.
// - data 는 네트워크에서 온 신뢰할 수 없는 바이트이며, size 도 다양하다.
//
// 과제:
// 이 코드의 잠재적 문제를 모두 찾고, 손상되거나 악의적으로 조작된 프레임(예: 큰 count,
// 실제 남은 바이트보다 큰 len)이 들어왔을 때 무슨 일이 일어나는지 설명하라. 프레임이
// 덜 도착한 경우(부분 수신)의 동작도 함께 논하라. 수정안과 더 나은 설계를 제시하라.
// (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================
#include <cstdint>
#include <cstring>
#include <vector>
struct Msg {
uint16_t type = 0;
std::vector<uint8_t> payload;
};
class BatchDecoder {
public:
std::vector<Msg> decode(const uint8_t* data, size_t size) {
std::vector<Msg> out;
size_t off = 0;
uint16_t count = readU16(data, off); // (A) 항목 개수
out.reserve(count); // (B) 개수만큼 예약
for (uint16_t i = 0; i < count; i++) {
uint16_t type = readU16(data, off); // (C) 타입
uint16_t len = readU16(data, off); // (D) 항목 길이
Msg m;
m.type = type;
m.payload.resize(len); // (E) 길이만큼 할당
std::memcpy(m.payload.data(), data + off, len); // (F) 복사
off += len;
out.push_back(std::move(m));
}
(void)size; // size 를 쓰지 않는다
return out;
}
private:
static uint16_t readU16(const uint8_t* b, size_t& o) { // (G) 경계 확인 없음
uint16_t v = static_cast<uint16_t>(b[o] | (b[o + 1] << 8));
o += 2;
return v;
}
}; 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.