Skip to content

軽微な仕様変更やバグ修正#3

Open
barrier15300 wants to merge 23 commits intomainfrom
alpha-develop
Open

軽微な仕様変更やバグ修正#3
barrier15300 wants to merge 23 commits intomainfrom
alpha-develop

Conversation

@barrier15300
Copy link
Owner

@barrier15300 barrier15300 commented Feb 10, 2026

Summary by CodeRabbit

リリースノート

  • New Features

    • 複数のネットワーク/暗号サンプルを追加(キー交換、署名、ネットワークチャット、バイト変換、テンプレート実行例)。
  • Refactor

    • ソケット/パケットの送受信挙動を整理し、暗号化送受信や非同期送信の扱いを改良。クライアント/サーバ起動フローを統一。
    • 可変長大整数演算を強化し、比較・シフト・乗算性能を改善。
  • Chore

    • ビルド設定と共通ヘッダの微整理(インクルード調整、型エイリアス追加)。

ついでにAESのコンストラクタを完全に定数計算対応に
変更・追加
GetBuffer -> GetRawPacketにリネーム
GetRawData -> イミュータブルな生データ参照を返す
RefRawData -> ミュータブルな生データ参照を返す

削除
SetBuffer -> ヘッダーを考慮しないバッファが渡される可能性、代替として前述のRefRawDataを実装したので削除
以下のようなエイリアスを追加
`Packet::header_bytes = std::array<byte_t, HeaderSize>`
バグが潜んでいたので摘出
@coderabbitai
Copy link

coderabbitai bot commented Feb 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

ソケット/パケットAPIを再設計し、名前空間を NetIO→Socket に変更。Send/Recv を view/ref ベースへ移行し、Packet にヘッダ/データ分離を追加。MultiWordInt に高速乗算や比較拡張を導入。複数のネットワーク/暗号/シリアライズ例を新規追加。

Changes

Cohort / File(s) Summary
ビルド設定
CMakeLists.txt
インクルード指定を単一の include_directories(...) に集約、add_executable フォーマット調整。
ソケット・Packet 共通
include/Socket.h, include/Packet.h, include/common.h, include/Cryptgraphy/common.h
namespace NetIO→Socket。basic_TCPSocket に bytearray/byte_view/byte_ref エイリアスと memcpyable テンプレートを公開。Send/Recv / Encryption API を byte_view/byte_ref ベースへ変更、非同期パスを rvalue セマンティクスへ更新。Packet に header/data 分離向けの GetRawPacket/GetRawData/RefRawData と header_bytes を追加。SocketDetail::cbytearraystd::execution の includes 追加。
多倍長整数ライブラリ
include/Cryptgraphy/MultiWordInt.h
固定長 bigint の公開 API を拡張(arr_view/arr_ref、FromWords、count_t ベースのシフト、noexcept 指定)。NormalMul/Karatuba 等の高速乗算路と三方比較(operator<=>)を追加。可変長特化の骨組みを #if 0 で追加。
アプリケーション入口 / Socket 実装
Socket.cpp
int main(int,char**) に統一し起動引数で Server/Client を切替。メッセージ送信を生文字列→Packet 包装へ変更。暗号/送受信フローを Packet ベースに整理。インクルード順・フォーマット調整。
大規模ネットワーク例
example/Network/Network.cpp
新規 TCP サーバ/クライアント例を追加:接続管理、ClientData の (De)serialize、暗号化送受信、入力スレッド、ブロードキャスト、mutex による送信同期、global sharedkey。サーバは受信を他クライアントへ Packet で中継。
追加サンプル群
example/BytesConvert/BytesConvert.cpp, example/EC_Signature/EC_Signature.cpp, example/KeyExchange/KeyExchange.cpp, example/template/template.cpp
ネストしたシリアライズの例、ECDSA 署名/検証デモ、鍵交換デモ、最小テンプレート例をそれぞれ追加。
その他小変更
(参照: include/Cryptgraphy/common.h)
std::execution 追加など軽微なヘッダ追加・フォーマット調整。

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant ClientSocket as "Client Socket"
    participant ServerSocket as "Server Socket"
    participant Server
    participant CryptEngine as "CryptEngine"

    Client->>ClientSocket: connect(addr:port)
    Client->>ClientSocket: send Packet (GetRawPacket / byte_view)
    ClientSocket->>CryptEngine: Encrypt(byte_view)
    ClientSocket->>ServerSocket: transmit bytes
    ServerSocket->>CryptEngine: Decrypt -> Packet reconstructed (GetRawData)
    CryptEngine-->>Server: deliver Packet
    Server->>Server: process, prefix with client name
    Server->>ServerSocket: broadcast Packet to other clients
    ServerSocket->>CryptEngine: Encrypt(byte_view)
    ServerSocket->>ClientSocket: deliver bytes
    ClientSocket->>CryptEngine: Decrypt -> Client displays message
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰🌿 新しい道を掘り進め、
パケットに歌をのせて跳ねる、
鍵は響き、整数は踊り、
例たちは窓を開き示す、
うさぎはコード庭で乗る。

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title check ⚠️ Warning プルリクエストのタイトルは日本語で「軽微な仕様変更やバグ修正」(軽微な仕様変更とバグ修正)となっていますが、変更内容は多くの重要な機能追加と大幅なリファクタリングを含んでいます。CMakeLists.txtの変更、Socket.h/Socket.cppの名前空間リネーム、Packetクラスの大幅なAPI変更、複数の新しい例ファイルの追加、MultiWordInt.hの拡張など、単なる「軽微な仕様変更」では説明できない規模です。 タイトルを変更内容をより正確に反映させてください。例えば「Socket APIの再設計とネットワーク機能の拡張」や「Packet/Socket API リファクタリングと暗号化通信の実装例追加」など、主要な変更を明確に示すタイトルが適切です。
Docstring Coverage ⚠️ Warning Docstring coverage is 2.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch alpha-develop

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 20

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
include/Cryptgraphy/MultiWordInt.h (1)

519-519: ⚠️ Potential issue | 🔴 Critical

文字列変換テーブルに文字順の誤りがあります: "kmnlop""klmnop"

複数箇所のルックアップテーブルで 'k' の後が "mnlop" になっていますが、正しくは "lmnop" です。影響範囲:

  • Line 519, 535, 536: CharSpanToWord / WordToString — base > 20 での解析・出力が不正
  • Line 565: Parsefind_first_not_of — 同上
  • Line 631: ToBase64 — Base64エンコード結果が不正('K','N','M','L''k','n','m','l' の位置が入れ替わっている)
  • Line 666: ToString — 同上

base 16(hex)では影響しませんが、base > 20 および Base64 で誤った結果を返します。

🐛 修正例(一部抜粋)

Line 519:

-	constexpr std::string_view list = "0123456789abcdefghijkmnlopqrstuvwxyz";
+	constexpr std::string_view list = "0123456789abcdefghijklmnopqrstuvwxyz";

Line 535-536:

-		constexpr std::string_view listlower = "0123456789abcdefghijkmnlopqrstuvwxyz";
-		constexpr std::string_view listupper = "0123456789ABCDEFGHIJKMNLOPQRSTUVWXYZ";
+		constexpr std::string_view listlower = "0123456789abcdefghijklmnopqrstuvwxyz";
+		constexpr std::string_view listupper = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

Line 631:

-	constexpr std::string_view list = "ABCDEFGHIJKNMLOPQRSTUVWXYZabcdefghijknmlopqrstuvwxyz0123456789+/";
+	constexpr std::string_view list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

Line 666:

-	constexpr std::string_view list = "0123456789abcdefghijkmnlopqrstuvwxyz";
+	constexpr std::string_view list = "0123456789abcdefghijklmnopqrstuvwxyz";

Also applies to: 535-536, 565-565, 631-631, 666-666

include/Cryptgraphy/SHAKE256.h (1)

91-98: ⚠️ Potential issue | 🟠 Major

operator bytearray() 内でも同じ std::bit_cast ポインタ問題があります。

Line 95 の std::bit_cast<const byte_t*>(m_words.data()) + i も上記コンストラクタと同じ問題を持ちます。constexpr コンテキストでの使用を想定する場合、バイトレベルのインデックスアクセスに変更が必要です。

constexpr 安全な代替案
 		constexpr operator bytearray() const {
 			bytearray ret;
 			ret.reserve(sizeof(m_words));
 			for (size_t i = 0, c = sizeof(m_words); i < c; ++i) {
-				ret.push_back(*(std::bit_cast<const byte_t*>(m_words.data()) + i));
+				size_t word_idx = i / sizeof(word_t);
+				size_t byte_idx = i % sizeof(word_t);
+				ret.push_back(static_cast<byte_t>(m_words[word_idx] >> (byte_idx * 8)));
 			}
 			return ret;
 		}
include/Packet.h (1)

276-289: ⚠️ Potential issue | 🔴 Critical

Line 282 の byte_view 初期化が誤っている

byte_view(m_buffer.begin(), HeaderSize) はヘッダ部分の最初の HeaderSize バイト分のビューを作成します。GetArray は データ部分(ヘッダの後)を処理すべきです。他の類似メソッド(line 217, line 250)では .subspan(HeaderSize) を使用してヘッダをスキップしているため、同じパターンに統一してください。

-		byte_view view = byte_view(m_buffer.begin(), HeaderSize);
+		byte_view view = byte_view(m_buffer).subspan(HeaderSize);
🤖 Fix all issues with AI agents
In `@example/KeyExchange/KeyExchange.cpp`:
- Around line 23-30: The byte-print loops over Ga and Gb can sign-extend when b
is a signed char; change the casts in both loops (the iterations over Ga and Gb
in KeyExchange.cpp) to static_cast<int>(static_cast<unsigned char>(b)) so values
>= 0x80 are printed as two hex digits instead of expanded negative ints; update
both occurrences where (int)b is used.

In `@example/Network/Network.cpp`:
- Around line 39-44: The code calls std::stoi(args[1]) without validation which
can throw std::invalid_argument or std::out_of_range; wrap the conversion in a
try-catch (catch both exceptions) or pre-validate args[1] before conversion, and
handle errors by logging and exiting or using a safe default instead of calling
Server() or Client(); update the block around the std::stoi call that decides
between Server() and Client() to perform the safe conversion and error handling
for args[1].
- Around line 104-109: The loop dereferences p->GetPeerAddress() without
checking the std::optional, causing UB when GetPeerAddress() returns nullopt;
update the loop that processes lostqueue to first test the optional (e.g., if
(auto addr = p->GetPeerAddress()) or addr.has_value()) and only call
clients.erase(*addr) when present, otherwise handle the nullopt case (skip
erase, log a warning, or use an alternative key) so no dereference of nullopt
occurs; modify the block around lostqueue, p, GetPeerAddress(), and
clients.erase accordingly.
- Line 181: The global/local variable stopflag is accessed from both the input
thread and the main thread causing a data race; change its type to
std::atomic<bool> (e.g., std::atomic<bool> stopflag{false};), add `#include`
<atomic>, and replace raw reads/writes in the input thread and main thread with
atomic operations (use stopflag.store(true) for writes and stopflag.load() for
reads or the atomic's operator bool/operator=) to ensure thread-safe
synchronization in the code that references stopflag.
- Around line 94-101: EncryptionRecv() returns std::optional<Packet> and is
being dereferenced without checking, causing UB if it returns nullopt; change
the chain to first capture the optional (e.g., auto pkt = c->EncryptionRecv())
and check it before calling pkt->Get<ClientData>(), then proceed to log and move
client into clients using c->GetPeerAddress() and clients[*addr] =
{std::move(*c), std::move(*cd)}; ensure you only call Get<ClientData>() and use
cd when pkt has value and handle the else/no-packet case appropriately.
- Line 126: The code dereferences optional results from val->Get<std::string>()
and pak->Get<std::string>() without checking for a value, which is undefined
behavior if empty; update the places building the message (the line constructing
the local variable send that uses cd.Name and cd.Level and the later use at
pak->Get<std::string>()) to first test the returned std::optional (e.g., with
has_value() or by using value_or) and handle the empty case (skip/early-return,
use a default string, or log an error) so you never directly dereference the
optional; make the check/handling adjacent to the constructs that call
Get<std::string>() so behavior is consistent.

In `@include/Cryptgraphy/MultiWordInt.h`:
- Around line 375-418: The Karatuba implementation shares temporaries (t and
z0/z1/z2) across recursion levels causing overwrites; to fix, make the recursive
helper return bigint by value and declare per-call temporaries inside the helper
instead of as outer-scope locals: move t (t[4]) and z0,z1,z2 into the lambda
body (the rec lambda in Karatuba) so each recursion has its own instances,
update the lambda signature from -> bigint& to -> bigint and adjust all uses
(calls to self(self, ...) and the final return) accordingly, ensuring
FromWords/MulBase/AssignAdd/AssignLeftShift operate on the local temporaries.
- Around line 891-907: AssignRightShift currently reads m_words[i + 1] out of
bounds and miscomputes bitshift when n is a multiple of WordBits; fix by
computing count_t whole = n / WordBits and count_t rem = n % WordBits (replace
wordshift/bitshift calc), then if rem==0 set bitshift=0 and avoid calling
WordShiftBase (use direct copy of m_words[i] into m_words[i - whole]) and only
iterate i from whole to c-1 ensuring you never access i+1 when rem==0; when
rem!=0 iterate i from whole to c-2 (or use condition i+1 < c) and call
WordShiftBase(m_words[i], m_words[i+1], WordBits - rem) so m_words[i+1] is
always in-range; finally zero out the high 'whole' words (use std::fill on the
rbegin slice) and ensure the tail element written from the last source is set to
0 if needed. Reference symbols: AssignRightShift, m_words, GetWords,
WordShiftBase, WordBits, wordshift/bitshift.
- Around line 874-890: AssignLeftShift can underflow when wordshift > GetWords()
and misuses WordShiftBase when bitshift == 0; fix by first checking if wordshift
>= GetWords() and in that case set all m_words to 0 and return *this, otherwise
compute count_t srcWords = GetWords() - wordshift safely and iterate only over
srcWords; also avoid calling WordShiftBase when bitshift == 0 by using a branch:
m_words[i + wordshift] = (bitshift == 0 ? m_words[i] :
WordShiftBase(i==0?0:m_words[i-1], m_words[i], bitshift)); this uses the
existing AssignLeftShift, GetWords, m_words, WordShiftBase, wordshift and
bitshift symbols.
- Around line 800-804: GetNBit currently subtracts 1 from GetWords() causing
underflow and out-of-bounds access when m_words is empty; update GetNBit (and
use the same safe loop pattern as GetNWord) to handle zero words: if GetWords()
== 0 return 0 (or GetAllBits() if that semantics applies) otherwise scan words
from the last down to find the highest nonzero word and compute bits using
std::bit_width(m_words[idx]) with WordBits and GetAllBits fallback; reference
functions/fields: GetNBit, GetWords, GetNWord, m_words, WordBits, GetAllBits.
- Around line 922-950: Add explicit equality operators for the variable-length
bigint: implement friend constexpr bool operator==(const bigint& lhs, const
bigint& rhs) noexcept and friend constexpr bool operator!=(const bigint& lhs,
const bigint& rhs) noexcept and have them use the existing Compare(const bigint&
lhs, const bigint& rhs) noexcept (or the member Compare(rhs) const) to return
true when Compare(...) yields std::strong_ordering::equal and false otherwise;
place these alongside the existing friend operator<=> so equality is properly
defined for the variable-length bigint.
- Around line 816-826: AssignAdd currently loops to this->GetWords() and
unconditionally accesses rhs.m_words[i], causing OOB if rhs has fewer words;
change AssignAdd to first get count_t rhsWords = rhs.GetWords() then loop i from
0 to min(this->GetWords(), rhsWords) and call AddBase(rhs.m_words[i],
std::addressof(this->m_words[i]), carry); after that, if carry remains and
this->GetWords() > rhsWords, continue a second loop from i = rhsWords to
this->GetWords() calling AddBase(0, std::addressof(this->m_words[i]), carry)
until carry clears (or you reach the end); use the bigint::AssignAdd, GetWords,
m_words and AddBase identifiers to locate the code and avoid any direct
rhs.m_words[i] access beyond rhs.GetWords().
- Around line 909-911: The unary bitwise NOT operator operator~() currently
mutates *this and returns a reference via AssignNOT(), which is surprising;
change operator~() to be non-destructive and return a new bigint by value
(mirroring the fixed-length variant). Implement it by making a copy of *this and
calling AssignNOT() on the copy (e.g., bigint tmp(*this); tmp.AssignNOT();
return tmp), adjust the signature to return bigint (and mark const/noexcept
appropriately), and remove the in-place behavior from operator~() that returns
bigint&.
- Around line 871-873: WordShiftBase performs a shift using (WordBits - n) which
becomes WordBits when n==0, causing undefined behavior; update WordShiftBase to
handle n==0 explicitly (e.g., return low when n==0) before performing (low >> n)
| (high << (WordBits - n)); reference the function WordShiftBase(word_t low,
word_t high, count_t n) noexcept and the constant WordBits (and note that
AssignLeftShift computes bitshift = n & (WordBits - 1) so n can be a multiple of
WordBits), and add the minimal conditional branch to avoid shifting by WordBits.
- Around line 828-836: The AssignNOT() constexpr method uses the
execution-policy overload of std::transform which is not constexpr; replace the
call that passes std::execution::unseq with the policy-less overload of
std::transform so the function can be evaluated in a constant expression. Locate
AssignNOT(), use std::transform(m_words.begin(), m_words.end(), m_words.begin(),
std::bit_not<word_t>()) (keeping the same m_words container and
std::bit_not<word_t>() functor) and keep the constexpr and noexcept specifiers
and return *this as before.

In `@include/Cryptgraphy/SHAKE256.h`:
- Around line 21-30: The constexpr state(byte_view from) currently uses
std::bit_cast<byte_t*> on m_words which is forbidden in constexpr; replace the
pointer-based copy with an index-based byte writer: iterate i from 0 to b (or
until from ends) and for each byte compute the target word index and byte offset
within m_words, then update m_words[word_index] by masking out the target byte
and OR-ing in (static_cast<word_t>(from[i]) << (offset*8)) so all writes are
done via integer operations (no pointer casts). Keep references to the same
symbols: state(byte_view), m_words, byte_t, byte_view, b and ensure the loop and
masking/shifting are constexpr-friendly.

In `@include/Packet.h`:
- Line 189: The constructor template Packet(enumT type, const std::vector<T>&
data) has the requires clause checking is_enum32<T> but it should check the enum
template parameter; update the constraint to use is_enum32<enumT> (i.e.,
requires (is_enum32<enumT>&& cross_convertible<T>)) so the enum parameter enumT
is validated correctly, matching the other overloads like the one at Line 167.

In `@include/Socket.h`:
- Around line 555-559: The lambda in ASyncSend is capturing byte_view parameter
src by reference which can dangle once ASyncSend returns; change the async task
to capture src by value so the span remains valid for the asynchronous call
(i.e., invoke std::async with a lambda that captures src by value and calls
this->Send(src)); apply the same fix to ASyncEncryptionSend(byte_view src) so
both use value-capture of src instead of [&].

In `@Socket.cpp`:
- Around line 28-47: The main function currently calls std::stoi(args[1])
without validation which can throw std::invalid_argument or std::out_of_range;
wrap the conversion in a try-catch or pre-validate the string (e.g., check
digits and optional sign or use std::from_chars) and handle errors by printing a
usage/error message and returning non-zero; specifically update main to guard
the std::stoi call (or replace it) and only call Server() or Client() when the
parsed value is valid, otherwise return an error code and avoid uncaught
exceptions.
🟡 Minor comments (3)
include/Cryptgraphy/MultiWordInt.h-294-328 (1)

294-328: ⚠️ Potential issue | 🟡 Minor

NormalMul の実装 — おおむね正しいですが、Line 317 のキャリー伝播に注意

Line 317: carry = upper + carryflagupperUINT64_MAXcarryflagtrue の場合、carry がラップして 0 になり、上位ワードへの繰り上げが失われます。発生確率は低いですが、大きな値の乗算で不正な結果になる可能性があります。

example/EC_Signature/EC_Signature.cpp-22-24 (1)

22-24: ⚠️ Potential issue | 🟡 Minor

ret 出力後の改行が欠落しています。

Line 22 で std::boolalpha << ret を出力した後に改行がありません。また、assert(ret) はリリースビルド(NDEBUG 定義時)では無効化されるため、検証失敗を確実に検出したい場合は明示的なチェックを検討してください。

提案
-	std::cout << std::boolalpha << ret;
-
-	assert(ret);
+	std::cout << std::boolalpha << ret << std::endl;
+
+	assert(ret);
include/Cryptgraphy/AES128.h-237-246 (1)

237-246: ⚠️ Potential issue | 🟡 Minor

std::bit_cast<byte_t*>(m_bytes.data()) は冗長なキャストです。

m_bytesstd::array<byte_t, block_size> なので、m_bytes.data() は既に byte_t* を返します。std::bit_cast<byte_t*> で同じ型へキャストするのは不要であり、constexpr コンテキストにおけるポインタの std::bit_cast はコンパイラによって定数式として拒否される可能性があります。

SHAKE256.h のパターンと統一しようとしたと思われますが、ここでは不要です。直接ポインタを使用できます。

提案
 		constexpr block_t(byte_view from) noexcept {
-			auto it = std::bit_cast<byte_t*>(m_bytes.data());
-			auto end = std::bit_cast<byte_t*>(m_bytes.data() + block_size);
+			auto it = m_bytes.data();
+			auto end = m_bytes.data() + block_size;
 			for (auto&& c : from) {
 				*it = c;
 				if (++it == end) {
 					break;
 				}
 			}
 		}
🧹 Nitpick comments (11)
example/KeyExchange/KeyExchange.cpp (2)

16-20: std::chrono::duration<double> を使った方がより簡潔

手動の / 1000 / 1000 / 1000 変換は std::chrono::duration<double> で置き換えるとより読みやすくなります。

♻️ リファクタ案
-	auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - tp).count();
-
-	bool same = Ga == Gb;
-
-	std::cout << (double)ns / 1000 / 1000 / 1000 << "s" << std::endl;
+	auto elapsed = std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - tp);
+
+	bool same = Ga == Gb;
+
+	std::cout << elapsed.count() << "s" << std::endl;

3-3: 未使用の argc / argv パラメータ

argcargv は使用されていません。シンプルに int main() で十分です。

include/Cryptgraphy/MultiWordInt.h (2)

810-815: 固定長版と可変長版で AddBase のパラメータ順序が異なります

固定長版 (Line 239): AddBase(word_t *dest, word_t src, bool carry)
可変長版 (Line 810): AddBase(word_t src, word_t *dest, bool carry)

同じ名前で引数順が逆転しているため、メンテナンス時に混乱やバグの原因になります。統一を推奨します。


75-75: std::bit_cast<T*>(words().data()) はポインタ型間の bit_cast であり、UB の懸念があります

std::bit_cast はオブジェクト表現のビット単位コピーを行いますが、ポインタ間の bit_cast は strict aliasing 違反となる可能性があります。TODO コメントにも記載されていますが、std::memcpy やバイト単位のコピーへの置き換えを検討してください。

example/EC_Signature/EC_Signature.cpp (1)

3-6: 未使用パラメータ argc, argv

argcargv が使用されていません。例示コードなので問題は小さいですが、コンパイラ警告を避けるために int main() とするか、(void)argc; (void)argv; を追加することを検討してください。

include/Cryptgraphy/AES128.h (1)

398-418: ParallelProcessor のエッジケース: size が 0 の場合の考慮。

size が 0 の場合、palc(0 / available) + 1 = 1 となり、Line 407 の end >= size (0) が即座に true となります。i = tasks.capacity() - 1 により最初のイテレーションで start=0, end=0 のタスクが1つ起動され、空のループが走ります。致命的な問題ではありませんが、size == 0 の場合は早期リターンした方がクリーンです。

CMakeLists.txt (1)

19-21: target_include_directories の使用を検討してください。

include_directories はグローバルスコープに影響します。モダン CMake のプラクティスとして、ターゲットスコープの target_include_directories を推奨します。

提案
-include_directories(
-	${PROJECT_SOURCE_DIR}/include
-)
+target_include_directories(Socket PRIVATE
+	${PROJECT_SOURCE_DIR}/include
+)
Socket.cpp (1)

7-7: 暗号化キーがソースコードにハードコードされている

共有鍵 sharedkey がリテラルとしてソースに埋め込まれています。さらに、example/Network/Network.cpp にも同一の値が重複定義されています。デモ/テスト用途であることは理解していますが、実運用を想定する場合はキーを外部化し、コード中にハードコードしないようにしてください。

example/Network/Network.cpp (1)

1-227: Socket.cpp との大規模なコード重複

このファイルは Socket.cpp とほぼ同一の内容(main(), Server(), Client(), ClientData, sharedkey)です。共通のロジックを共有ヘッダまたはライブラリに抽出し、各エントリポイントから利用する構成にすることを推奨します。

include/Packet.h (1)

125-125: デフォルトコンストラクタ: 余分なセミコロン

Packet() {}; のブレース後のセミコロンは冗長です(コンパイルに影響はありません)。

♻️ 修正案
-	Packet() {};
+	Packet() {}
include/Socket.h (1)

560-564: ASyncRecv[&] を使用しているが、明示的なキャプチャが望ましい

[&] は必要以上の変数をキャプチャする可能性があります。[this, &dest] のように明示的にキャプチャすることで意図が明確になります。

♻️ 修正案
 	std::future<bool> ASyncRecv(byte_ref dest) {
-		return std::async(std::launch::async, [&]() {
+		return std::async(std::launch::async, [this, &dest]() {
 			return this->Recv(dest);
 		});
 	}

Line 582 も同様:

 	std::future<bool> ASyncEncryptionRecv(byte_ref dest) {
-		return std::async(std::launch::async, [&]() {
+		return std::async(std::launch::async, [this, &dest]() {
 			return this->EncryptionRecv(dest);
 		});
 	}

Comment on lines +23 to +30
for (auto&& b : Ga) {
std::cout << std::hex << std::setw(2) << std::setfill('0') << std::right << (int)b;
}
std::cout << std::endl;

for (auto&& b : Gb) {
std::cout << std::hex << std::setw(2) << std::setfill('0') << std::right << (int)b;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

(int)b のキャストで符号拡張バグの可能性

bsigned char の場合、0x80以上の値で符号拡張が発生し、setw(2) にもかかわらず ffffff80 のような出力になります。static_cast<int>(static_cast<unsigned char>(b)) を使用してください。

🐛 修正案
 for (auto&& b : Ga) {
-    std::cout << std::hex << std::setw(2) << std::setfill('0') << std::right << (int)b;
+    std::cout << std::hex << std::setw(2) << std::setfill('0') << std::right << static_cast<int>(static_cast<unsigned char>(b));
 }
 std::cout << std::endl;

 for (auto&& b : Gb) {
-    std::cout << std::hex << std::setw(2) << std::setfill('0') << std::right << (int)b;
+    std::cout << std::hex << std::setw(2) << std::setfill('0') << std::right << static_cast<int>(static_cast<unsigned char>(b));
 }
🤖 Prompt for AI Agents
In `@example/KeyExchange/KeyExchange.cpp` around lines 23 - 30, The byte-print
loops over Ga and Gb can sign-extend when b is a signed char; change the casts
in both loops (the iterations over Ga and Gb in KeyExchange.cpp) to
static_cast<int>(static_cast<unsigned char>(b)) so values >= 0x80 are printed as
two hex digits instead of expanded negative ints; update both occurrences where
(int)b is used.

Comment on lines +39 to +44
if (std::stoi(args[1]) == 0) {
Server();
}
else {
Client();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

std::stoi が例外をスローする可能性がある

Socket.cpp と同様の問題です。無効な入力に対して std::invalid_argument または std::out_of_range がスローされます。

🤖 Prompt for AI Agents
In `@example/Network/Network.cpp` around lines 39 - 44, The code calls
std::stoi(args[1]) without validation which can throw std::invalid_argument or
std::out_of_range; wrap the conversion in a try-catch (catch both exceptions) or
pre-validate args[1] before conversion, and handle errors by logging and exiting
or using a safe default instead of calling Server() or Client(); update the
block around the std::stoi call that decides between Server() and Client() to
perform the safe conversion and error handling for args[1].

Comment on lines +94 to +101
auto cd = c->EncryptionRecv()->Get<ClientData>();

if (cd) {
std::cout << "connected: " << cd->Name << std::endl;
auto addr = c->GetPeerAddress();
clients[*addr] = {std::move(*c), std::move(*cd)};
c.reset();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

EncryptionRecv() の戻り値が未チェックのまま連鎖呼び出しされている — null参照でUB

EncryptionRecv()std::optional<Packet> を返します。std::nullopt が返された場合、->Get<ClientData>() は未定義動作を引き起こします。

🐛 修正案
-		auto cd = c->EncryptionRecv()->Get<ClientData>();
+		auto recvResult = c->EncryptionRecv();
+		if (!recvResult) {
+			continue;
+		}
+		auto cd = recvResult->Get<ClientData>();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
auto cd = c->EncryptionRecv()->Get<ClientData>();
if (cd) {
std::cout << "connected: " << cd->Name << std::endl;
auto addr = c->GetPeerAddress();
clients[*addr] = {std::move(*c), std::move(*cd)};
c.reset();
}
auto recvResult = c->EncryptionRecv();
if (!recvResult) {
continue;
}
auto cd = recvResult->Get<ClientData>();
if (cd) {
std::cout << "connected: " << cd->Name << std::endl;
auto addr = c->GetPeerAddress();
clients[*addr] = {std::move(*c), std::move(*cd)};
c.reset();
}
🤖 Prompt for AI Agents
In `@example/Network/Network.cpp` around lines 94 - 101, EncryptionRecv() returns
std::optional<Packet> and is being dereferenced without checking, causing UB if
it returns nullopt; change the chain to first capture the optional (e.g., auto
pkt = c->EncryptionRecv()) and check it before calling pkt->Get<ClientData>(),
then proceed to log and move client into clients using c->GetPeerAddress() and
clients[*addr] = {std::move(*c), std::move(*cd)}; ensure you only call
Get<ClientData>() and use cd when pkt has value and handle the else/no-packet
case appropriately.

Comment on lines +104 to +109
while (!lostqueue.empty()) {
auto p = lostqueue.front();
lostqueue.pop_front();

clients.erase(*p->GetPeerAddress());
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

GetPeerAddress() の戻り値が未チェック — nullopt参照でUB

p->GetPeerAddress()std::optional を返しますが、* で直接参照外しされています。接続が切れたソケットでは getpeername が失敗し std::nullopt を返す可能性が高く、その場合クラッシュします。

🐛 修正案
 	while (!lostqueue.empty()) {
 		auto p = lostqueue.front();
 		lostqueue.pop_front();
 
-		clients.erase(*p->GetPeerAddress());
+		auto addr = p->GetPeerAddress();
+		if (addr) {
+			clients.erase(*addr);
+		}
 	}
🤖 Prompt for AI Agents
In `@example/Network/Network.cpp` around lines 104 - 109, The loop dereferences
p->GetPeerAddress() without checking the std::optional, causing UB when
GetPeerAddress() returns nullopt; update the loop that processes lostqueue to
first test the optional (e.g., if (auto addr = p->GetPeerAddress()) or
addr.has_value()) and only call clients.erase(*addr) when present, otherwise
handle the nullopt case (skip erase, log a warning, or use an alternative key)
so no dereference of nullopt occurs; modify the block around lostqueue, p,
GetPeerAddress(), and clients.erase accordingly.

continue;
}

std::string send = cd.Name + "(" + std::to_string(cd.Level) + "): " + *val->Get<std::string>();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Get<std::string>() の戻り値を未チェックで参照外ししている

val->Get<std::string>()std::optional<std::string> を返します。* で直接参照外しすると、値が空の場合にUBです。Line 221 (*pak->Get<std::string>()) も同様の問題があります。

🐛 修正案(Line 126)
-		std::string send = cd.Name + "(" + std::to_string(cd.Level) + "): " + *val->Get<std::string>();
+		auto msg = val->Get<std::string>();
+		if (!msg) {
+			continue;
+		}
+		std::string send = cd.Name + "(" + std::to_string(cd.Level) + "): " + *msg;
🐛 修正案(Line 221)
-	auto val = *pak->Get<std::string>();
-	std::cout << val << std::endl;
+	auto val = pak->Get<std::string>();
+	if (!val) {
+		continue;
+	}
+	std::cout << *val << std::endl;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
std::string send = cd.Name + "(" + std::to_string(cd.Level) + "): " + *val->Get<std::string>();
auto msg = val->Get<std::string>();
if (!msg) {
continue;
}
std::string send = cd.Name + "(" + std::to_string(cd.Level) + "): " + *msg;
🤖 Prompt for AI Agents
In `@example/Network/Network.cpp` at line 126, The code dereferences optional
results from val->Get<std::string>() and pak->Get<std::string>() without
checking for a value, which is undefined behavior if empty; update the places
building the message (the line constructing the local variable send that uses
cd.Name and cd.Level and the later use at pak->Get<std::string>()) to first test
the returned std::optional (e.g., with has_value() or by using value_or) and
handle the empty case (skip/early-return, use a default string, or log an error)
so you never directly dereference the optional; make the check/handling adjacent
to the constructs that call Get<std::string>() so behavior is consistent.

Comment on lines +922 to +950
static constexpr auto Compare(const bigint& lhs, const bigint& rhs) noexcept {
count_t words[2] = {lhs.GetWords(), rhs.GetWords()};
auto [words_min, words_max] = std::minmax(words[0], words[1]);

bool is_bigger_l = words_max == words[0];

const bigint& longer = is_bigger_l ? lhs : rhs;
const bigint& shorter = is_bigger_l ? rhs : lhs;

if (!IsZeroInRef(arr_view(longer.m_words).last(words_max - words_min))) {
return is_bigger_l ?
std::strong_ordering::greater : std::strong_ordering::less;
}

for (count_t i = words_min; i-- > 0;) {
auto com = lhs.m_words[i] <=> rhs.m_words[i];
if (!std::is_eq(com)) {
return com;
}
}

return std::strong_ordering::equal;
}
constexpr auto Compare(const bigint& rhs) const noexcept {
return Compare(*this, rhs);
}
friend constexpr auto operator<=>(const bigint& lhs, const bigint& rhs) noexcept {
return Compare(lhs, rhs);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

可変長版 Compareoperator<=>operator== が未定義です

C++20 では operator<=> を定義しても operator== は自動生成されません(クラス内で = default<=> を宣言した場合のみ自動生成)。ユーザー定義の <=> の場合、==!= は別途定義する必要があります。固定長版は明示的に operator== / operator!= を定義していますが(Line 462-463)、可変長版にはありません。

🐛 修正案
 friend constexpr auto operator<=>(const bigint& lhs, const bigint& rhs) noexcept {
     return Compare(lhs, rhs);
 }
+friend constexpr bool operator==(const bigint& lhs, const bigint& rhs) noexcept {
+    return Compare(lhs, rhs) == 0;
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static constexpr auto Compare(const bigint& lhs, const bigint& rhs) noexcept {
count_t words[2] = {lhs.GetWords(), rhs.GetWords()};
auto [words_min, words_max] = std::minmax(words[0], words[1]);
bool is_bigger_l = words_max == words[0];
const bigint& longer = is_bigger_l ? lhs : rhs;
const bigint& shorter = is_bigger_l ? rhs : lhs;
if (!IsZeroInRef(arr_view(longer.m_words).last(words_max - words_min))) {
return is_bigger_l ?
std::strong_ordering::greater : std::strong_ordering::less;
}
for (count_t i = words_min; i-- > 0;) {
auto com = lhs.m_words[i] <=> rhs.m_words[i];
if (!std::is_eq(com)) {
return com;
}
}
return std::strong_ordering::equal;
}
constexpr auto Compare(const bigint& rhs) const noexcept {
return Compare(*this, rhs);
}
friend constexpr auto operator<=>(const bigint& lhs, const bigint& rhs) noexcept {
return Compare(lhs, rhs);
}
static constexpr auto Compare(const bigint& lhs, const bigint& rhs) noexcept {
count_t words[2] = {lhs.GetWords(), rhs.GetWords()};
auto [words_min, words_max] = std::minmax(words[0], words[1]);
bool is_bigger_l = words_max == words[0];
const bigint& longer = is_bigger_l ? lhs : rhs;
const bigint& shorter = is_bigger_l ? rhs : lhs;
if (!IsZeroInRef(arr_view(longer.m_words).last(words_max - words_min))) {
return is_bigger_l ?
std::strong_ordering::greater : std::strong_ordering::less;
}
for (count_t i = words_min; i-- > 0;) {
auto com = lhs.m_words[i] <=> rhs.m_words[i];
if (!std::is_eq(com)) {
return com;
}
}
return std::strong_ordering::equal;
}
constexpr auto Compare(const bigint& rhs) const noexcept {
return Compare(*this, rhs);
}
friend constexpr auto operator<=>(const bigint& lhs, const bigint& rhs) noexcept {
return Compare(lhs, rhs);
}
friend constexpr bool operator==(const bigint& lhs, const bigint& rhs) noexcept {
return Compare(lhs, rhs) == 0;
}
🤖 Prompt for AI Agents
In `@include/Cryptgraphy/MultiWordInt.h` around lines 922 - 950, Add explicit
equality operators for the variable-length bigint: implement friend constexpr
bool operator==(const bigint& lhs, const bigint& rhs) noexcept and friend
constexpr bool operator!=(const bigint& lhs, const bigint& rhs) noexcept and
have them use the existing Compare(const bigint& lhs, const bigint& rhs)
noexcept (or the member Compare(rhs) const) to return true when Compare(...)
yields std::strong_ordering::equal and false otherwise; place these alongside
the existing friend operator<=> so equality is properly defined for the
variable-length bigint.

Comment on lines +28 to 47
int main(int argc, char* argv[]) {

std::vector<std::string> names;
// arg[1]{ 0 = server, 1 = client }

Packet::bytearray ToBytes() const {
Packet::bytearray ret;
Packet::StoreBytes(ret, names);
return ret;
}
std::vector<std::string> args;
args.insert(args.end(), argv, argv + argc);

Packet::byte_view FromBytes(Packet::byte_view view) {
Packet::LoadBytes(view, names);
return view;
if (args.size() <= 1) {
return -1;
}
};

struct ContainerInVariable {
std::vector<ContainerInContainer> container;

Packet::bytearray ToBytes() const {
Packet::bytearray ret;
Packet::StoreBytes(ret, container);
return ret;
if (std::stoi(args[1]) == 0) {
Server();
}

Packet::byte_view FromBytes(Packet::byte_view view) {
Packet::LoadBytes(view, container);
return view;
}
};
#include "include/Cryptgraphy/KeyManager.h"

int main(int argc, char* argv[]) {

//KeyManager Keya;
//KeyManager Keyb;
//
//auto tp = std::chrono::high_resolution_clock::now();
//
//auto kE = Keya.MakeQKey();
//auto kF = Keyb.MakeQKey();
//
//auto Ga = Keya.MakeSharedKey(kF);
//auto Gb = Keyb.MakeSharedKey(kE);
//
//auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - tp).count();
//
//bool same = Ga == Gb;
//
//std::cout << (double)ns / 1000 / 1000 / 1000 << "s" << std::endl;
//std::cout << std::boolalpha << "shared key same: " << same << std::endl;
//
//for (auto&& b : Ga) {
// std::cout << std::hex << std::setw(2) << std::setfill('0') << std::right << (int)b;
//}
//std::cout << std::endl;
//
//for (auto&& b : Gb) {
// std::cout << std::hex << std::setw(2) << std::setfill('0') << std::right << (int)b;
//}
//std::cout << std::endl;

KeyManager key;
std::string message = "I have skill is write low level programing language.";

auto q = ECDSA::MakePublicKey(key.GetSecretKey());

auto v = ECDSA::Sign(key.GetSecretKey(), {message.begin(), message.end()});

bool ret = ECDSA::Verify(q, v, {message.begin(), message.end()});

std::cout << "message: \"" << message << "\"" << std::endl;
std::cout << "Q: {" << q.x.value.ToString(16) << ", " << q.y.value.ToString(16) << "}" << std::endl;
std::cout << "(r, s)(bytes): ";
for (auto&& b : v) {
std::cout << std::hex << std::setw(2) << std::setfill('0') << std::right << (int)b;
else {
Client();
}
std::cout << std::endl;

std::cout << std::boolalpha << ret;

//std::string message = "0123456789abcdef";
//Cryptgraphy::bytearray data{message.begin(), message.end()};
//
//auto tp = std::chrono::high_resolution_clock::now();
//
//auto ret = SHAKE256::HasherN(data, 64);
//
//auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - tp).count();
//
//std::cout << (double)ns / 1000 / 1000 << "ms" << std::endl;
//std::cout << std::boolalpha << "hash: ";
//
//for (auto&& c : ret) {
// std::cout << std::hex << std::right << std::setw(2) << std::setfill('0') << (int)c;
//}

//using int_t = bigint<8>;
//using modint_t = ModInt<int_t>;
//using projective_t = ECProjective<modint_t>;
//
//modint_t::Factory xmodp = "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff";
//projective_t::Factory projective = WeierstrassParameter<modint_t>(
// xmodp("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc"),
// xmodp("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b")
//);
//
//auto G = projective(
// xmodp("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"),
// xmodp("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"),
// xmodp(1)
//);
//
//auto view = [](const std::string& name, const projective_t& p) {
// std::cout << name << ": {"
// << p.x.value.ToString(16) << ", "
// << p.y.value.ToString(16) << ", "
// << p.z.value.ToString(16) << "}"
// << std::endl;
//};
//auto check = [](const projective_t& p) {
// auto a = p.ToAfinPoint();
// std::cout << "Check: " << std::boolalpha
// << a.GetParam().CheckPoint(a.x, a.y)
// << std::endl;
//};
//
//auto d = G.Double();
//
//view("double", d);
//check(d);
//
//auto add = G.Add(d);
//
//view("add", add);
//check(add);
//
//auto scaler = G.Scaler(xmodp(100));
//
//view("scaler", scaler);
//check(scaler);

// arg[1]{ 0 = server, 1 = client }

//std::vector<std::string> args;
//args.insert(args.end(), argv, argv + argc);
//
//if (args.size() <= 1) {
// return -1;
//}
//
//if (std::stoi(args[1]) == 0) {
// Server();
//}
//else {
// Client();
//}
//
//return 0;
return 0;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

std::stoi が例外をスローする可能性がある

args[1] が数値でない文字列の場合、std::stoistd::invalid_argument をスローし、非常に大きい数値の場合は std::out_of_range をスローします。try-catch で囲むか、事前にバリデーションを行ってください。

🛡️ 修正案
-	if (std::stoi(args[1]) == 0) {
-		Server();
-	}
-	else {
-		Client();
-	}
+	try {
+		if (std::stoi(args[1]) == 0) {
+			Server();
+		}
+		else {
+			Client();
+		}
+	}
+	catch (const std::exception& e) {
+		std::cerr << "invalid argument: " << e.what() << std::endl;
+		return -1;
+	}
🤖 Prompt for AI Agents
In `@Socket.cpp` around lines 28 - 47, The main function currently calls
std::stoi(args[1]) without validation which can throw std::invalid_argument or
std::out_of_range; wrap the conversion in a try-catch or pre-validate the string
(e.g., check digits and optional sign or use std::from_chars) and handle errors
by printing a usage/error message and returning non-zero; specifically update
main to guard the std::stoi call (or replace it) and only call Server() or
Client() when the parsed value is valid, otherwise return an error code and
avoid uncaught exceptions.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
include/Socket.h (2)

576-607: ⚠️ Potential issue | 🔴 Critical

Packet 参照の [&] キャプチャも同様にダングリング参照のリスクがあります。

ASyncSend(const Packet& src)ASyncEncryptionSend(const Packet& src)[&] キャプチャを使用しています。呼び出し元が Packet を一時オブジェクトとして渡した場合(例: ASyncSend(Packet(...)))、非同期タスク実行時に src は既に破棄されています。

Packet をコピーキャプチャするか、呼び出し側の責任を明確にドキュメント化してください。

🐛 修正案
 	std::future<bool> ASyncSend(const Packet& src) {
-		return std::async(std::launch::async, [&]() {
+		return std::async(std::launch::async, [this, src]() {
 			return this->Send(src);
 		});
 	}
 	std::future<bool> ASyncEncryptionSend(const Packet& src) {
-		return std::async(std::launch::async, [&]() {
+		return std::async(std::launch::async, [this, src]() {
 			return this->EncryptionSend(src);
 		});
 	}

730-732: ⚠️ Potential issue | 🟡 Minor

#undef SOCKET_H_USE_NAMESPACE がユーザー定義マクロを消去します。

Line 732 で SOCKET_H_USE_NAMESPACE#undef していますが、これはユーザーがインクルード前に定義するマクロです。このヘッダーをインクルードした後、同マクロが消えてしまうため、複数ヘッダーで同じマクロを参照する場合に問題になります。意図的な設計であれば問題ありませんが、影響を把握しておいてください。

include/Cryptgraphy/MultiWordInt.h (2)

88-88: ⚠️ Potential issue | 🔴 Critical

自己ムーブ代入で use-after-free が発生します

this == &from の場合、delete m_words で自身のデータを解放した後、m_words = from.m_words(既に解放済み)を代入し、最終的に from.m_words = nullptrthis->m_wordsnullptr になります。std::swap などで自己代入が発生するケースがあります。

🐛 修正案
-constexpr bigint& operator=(bigint&& from) noexcept { delete m_words; m_words = from.m_words; from.m_words = nullptr; return *this; }
+constexpr bigint& operator=(bigint&& from) noexcept {
+    if (this != &from) {
+        delete m_words;
+        m_words = from.m_words;
+        from.m_words = nullptr;
+    }
+    return *this;
+}

34-35: ⚠️ Potential issue | 🟠 Major

ムーブ後オブジェクトの words() アクセスでヌルポインタ参照が発生します

ムーブコンストラクタ(Line 35)およびムーブ代入(Line 88)の後、移動元の m_wordsnullptr になります。移動元オブジェクトに対する words()bits()Compare 等の呼び出しはヌルポインタ参照となります。

words() にアサーションを追加するか、ムーブ後に空の arr_t を再確保することを検討してください。

🛡️ 修正案(防御的アプローチ)
-constexpr bigint(bigint&& from) noexcept : m_words(nullptr) { m_words = from.m_words; from.m_words = nullptr; }
+constexpr bigint(bigint&& from) noexcept : m_words(from.m_words) { from.m_words = new arr_t(); }

もしくは words() でヌルチェック:

-constexpr arr_t& words() noexcept { return *m_words; }
+constexpr arr_t& words() noexcept { assert(m_words && "Accessing moved-from bigint"); return *m_words; }
🤖 Fix all issues with AI agents
In `@include/Cryptgraphy/MultiWordInt.h`:
- Around line 398-399: The subspan call is selecting the upper half instead of
the lower half, so xl/yl are passed as zeros to the recursive add; change
arr_view(t[0].words()).subspan(halfwords) and
arr_view(t[1].words()).subspan(halfwords) to select the lower half (e.g. use
.first(halfwords) or .subspan(0, halfwords)) so that xl/yl refer to the low half
where FromWords(xl) += FromWords(xh) stores its result (references: xl, yl, xh,
yh, arr_view, subspan, FromWords, t[0], t[1]).

In `@include/Socket.h`:
- Around line 524-535: Recv() (and EncryptionRecv()) allocates a buffer using
head.Size directly, which is untrusted network data and can cause OOM; add a
validation step after constructing Header head (from headbuf) to check head.Size
against a defined maximum allowed packet size (e.g., MAX_PACKET_SIZE constant or
config) and return std::nullopt (or an error) if it exceeds that limit or is
zero, before allocating bytearray data(head.Size); apply the same size-check
logic in EncryptionRecv() where it uses head.Size to guard buffer allocation and
any subsequent reads.
🧹 Nitpick comments (4)
include/Socket.h (2)

609-629: _Send / _Recv / _ASyncSend / _ASyncRecv が public スコープにあります。

アンダースコアプレフィックス付きのメソッドは内部実装を示唆していますが、public セクション(Line 379 以降)に配置されています。protected セクションに移動するか、プレフィックスを外して正式な public API として扱うことを検討してください。

また、Line 625-629 の _ASyncRecv[this, &target]target を参照キャプチャしていますが、_ASyncSend(Line 620)が target を値キャプチャしているのとは非対称です。出力パラメータなので参照は意図的と思われますが、呼び出し元がバッファの生存期間を保証する必要がある点を明記すべきです。


381-386: bytearraymemcpyableSocketBase(Line 245-248)と basic_TCPSocket で二重定義されています。

basic_TCPSocketSocketBase を継承しているため、基底クラスの bytearraymemcpyable がそのまま使えます。byte_viewbyte_ref のみ追加すれば十分です。

♻️ 重複削除の提案
-	using bytearray = SocketDetail::bytearray;
 	using byte_view = SocketDetail::byte_view;
 	using byte_ref = SocketDetail::byte_ref;
-
-	template<class T>
-	static constexpr bool memcpyable = SocketDetail::memcpyable<T>;
include/Cryptgraphy/MultiWordInt.h (2)

745-745: 固定長 bigint が毎回ヒープ確保するのはパフォーマンスに影響します

arr_t* m_words = new arr_t() により、すべての bigint インスタンス生成時にヒープ確保が行われます。特に NormalMulKaratuba_Legacy のような関数内で大量の一時オブジェクトが生成されるため、アロケーションコストが蓄積します。

constexpr 評価のための設計であると理解しますが、bits()reinterpret_cast(Line 737)の TODO が解決できれば、直接 arr_t m_words{}; に変更してヒープ確保を排除できます。


753-956: 可変長 bigint<0, _sign> にコンストラクタ・代入演算子・算術演算子が未実装です

現状ではデフォルトコンストラクタ(m_words{} で空ベクター)しか生成されず、以下が欠けています:

  • word_t / sword_t からの変換コンストラクタ
  • initializer_list / 文字列からのコンストラクタ
  • operator+=, -=, *=, /= およびフリー関数版の算術演算子
  • operator<<=, >>= およびフリー関数版のシフト演算子
  • operator&, |, ^ のフリー関数版(&=, |=, ^= は定義済み)
  • Parse, ToString, ToHex 等の I/O サポート

意図的に段階的実装であれば問題ありませんが、現状では外部から実質利用不可能です。

このタスクの追跡用に Issue を作成しますか?

Comment on lines 524 to 535
std::optional<Packet> Recv() {
bytearray head(Packet::HeaderSize);
if (!Recv(head)) {
Packet::header_bytes headbuf{};
if (!Recv(headbuf)) {
return std::nullopt;
}
Packet pak;
pak.SetBuffer(std::move(head));
bytearray data(pak.GetHeader()->Size);
Header head = std::bit_cast<Header>(headbuf);
bytearray data(head.Size);
if (!Recv(data)) {
return std::nullopt;
}
return Packet(pak.GetHeader()->Type, data);
return Packet(head.Type, data);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

ネットワークから受信した head.Size によるバッファ割り当てにサイズ制限がありません。

Line 530 で bytearray data(head.Size) としていますが、head.Size はネットワークから受信した生データから bit_cast で得られた値です。悪意あるピアが巨大な Size を送信した場合、OOM(メモリ不足)によるサービス拒否が発生します。Lines 557-558 の EncryptionRecv() にも同じ問題があります。

最大パケットサイズの上限チェックを追加することを推奨します。

🛡️ 修正案の例
+	static constexpr uint32_t MaxPacketSize = 16 * 1024 * 1024; // 16MB upper limit
+
 	std::optional<Packet> Recv() {
 		Packet::header_bytes headbuf{};
 		if (!Recv(headbuf)) {
 			return std::nullopt;
 		}
 		Header head = std::bit_cast<Header>(headbuf);
+		if (head.Size > MaxPacketSize) {
+			return std::nullopt;
+		}
 		bytearray data(head.Size);
 		if (!Recv(data)) {
 			return std::nullopt;
 		}
 		return Packet(head.Type, data);
 	}

EncryptionRecv() にも同様のチェックを追加してください。

🤖 Prompt for AI Agents
In `@include/Socket.h` around lines 524 - 535, Recv() (and EncryptionRecv())
allocates a buffer using head.Size directly, which is untrusted network data and
can cause OOM; add a validation step after constructing Header head (from
headbuf) to check head.Size against a defined maximum allowed packet size (e.g.,
MAX_PACKET_SIZE constant or config) and return std::nullopt (or an error) if it
exceeds that limit or is zero, before allocating bytearray data(head.Size);
apply the same size-check logic in EncryptionRecv() where it uses head.Size to
guard buffer allocation and any subsequent reads.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
include/Packet.h (1)

265-274: ⚠️ Potential issue | 🔴 Critical

GetArray<T>()memcpy のサイズ不整合によるバッファオーバーフローの可能性。

Line 270 で dataSize はデータ部分のバイト数を sizeof(T) で切り捨て除算して算出されますが、Line 272 の memcpy は切り捨て前の全バイト数 (m_buffer.size() - HeaderSize) をコピーします。

データ部分のバイト数が sizeof(T) の倍数でない場合、vector の確保領域を超えて書き込みが発生します。

例: sizeof(T)==4、データ部分が5バイトの場合:

  • dataSize = 5/4 = 1 → vector は4バイト分
  • memcpy は5バイトコピー → 1バイト超過書き込み
🐛 修正案
 	template<class T>
 	std::optional<std::vector<T>> GetArray() const requires (memcpyable<T> && !from_byteable<T>) {
 		if (CheckHeader()) {
 			return std::nullopt;
 		}
 		size_t dataSize = (m_buffer.size() - HeaderSize) / sizeof(T);
 		std::vector<T> data(dataSize);
-		std::memcpy(data.data(), m_buffer.data() + HeaderSize, m_buffer.size() - HeaderSize);
+		std::memcpy(data.data(), m_buffer.data() + HeaderSize, dataSize * sizeof(T));
 		return data;
 	}
🤖 Fix all issues with AI agents
In `@include/Packet.h`:
- Around line 213-224: GetRawData() and RefRawData() incorrectly use
CheckHeader() with its default option (which enforces HeaderSize+1), causing
zero-length payload packets to return nullopt; change both to call
CheckHeader(0) so only header presence is validated (refer to GetRawData,
RefRawData, CheckHeader, HeaderSize, and m_buffer when making the change).
🧹 Nitpick comments (1)
include/Packet.h (1)

403-405: CheckHeader の命名とデフォルト引数について。

CheckHeadertrue = 不正(バッファ不足)を返しますが、一般的に "Check" や "Is" 系のメソッドは true = 正常を期待する慣例があります。IsBufferTooSmall や、反転して HasValidHeader(size_t minDataSize = 0) のような命名にすると、呼び出し側の if 文の意図が明確になります。

また、デフォルト引数 option = 1 は上述の GetRawData 等のバグの原因となっています。デフォルトを 0 に変更するか、データサイズ検証が必要な箇所で明示的に引数を渡す方が安全です。

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
include/Cryptgraphy/MultiWordInt.h (1)

743-746: ⚠️ Potential issue | 🟠 Major

m_words を生ポインタで new するのは constexpr のための妥協と理解しますが、リスクがあります

arr_t* m_words = new arr_t() はヒープ割り当てを行いますが、std::unique_ptr を使用できない制約がある場合でも、以下の点に注意してください:

  • Line 88 の operator=(bigint&&) に自己代入保護がありません。a = std::move(a)delete m_words 後に無効なポインタを読みます。
  • コピーコンストラクタ(Line 34)は *m_words = *from.m_words でデフォルトの new arr_t() に書き込むため正しいですが、ムーブ後の from に対して from.words() を呼ぶと nullptr デリファレンスになります。
🛡️ 自己代入保護の修正案
 constexpr bigint& operator=(bigint&& from) noexcept {
+    if (this == &from) return *this;
     delete m_words;
     m_words = from.m_words;
     from.m_words = nullptr;
     return *this;
 }
include/Socket.h (1)

576-585: ⚠️ Potential issue | 🟠 Major

ASyncSend(const Packet&) / ASyncRecv() のラムダが [&] でキャプチャしており、ダングリングリスクがあります

Line 577 と 582 で [&] キャプチャを使用しています。byte_view 版(Line 566)では [=] に修正済みですが、Packet 版は未修正です。

ASyncSend(const Packet&) では、呼び出し元が future を待つ前に Packet がスコープを抜ける可能性があります。this のキャプチャは問題ありませんが、src の参照キャプチャは危険です。

🐛 修正案
 	std::future<bool> ASyncSend(const Packet& src) {
-		return std::async(std::launch::async, [&]() {
+		return std::async(std::launch::async, [this, src]() {
 			return this->Send(src);
 		});
 	}

Line 598-601 の ASyncEncryptionSend(const Packet&) にも同じ問題があります。

🤖 Fix all issues with AI agents
In `@include/Cryptgraphy/MultiWordInt.h`:
- Around line 320-365: The Karatuba_Legacy implementation incorrectly calls
Karatuba for recursive multiplies (z0, z2, z1) which pulls in the buggy
shared-state Karatuba; update the three recursive calls inside Karatuba_Legacy
so they call Karatuba_Legacy(xl, yl), Karatuba_Legacy(xh, yh), and
Karatuba_Legacy(xl, yl) respectively (replace references to Karatuba with
Karatuba_Legacy) to ensure pure value-based recursion and correct behavior.
- Around line 214-226: FromWords currently copies elements from the input range
r into the bigint's words() but stops early when r is exhausted, leaving higher
words unchanged; update FromWords to zero-clear any remaining elements of
words() after the copy (e.g., using std::fill/std::fill_n or a loop) so that
bigint::FromWords(R&& r) guarantees higher words are set to 0 when r has fewer
elements — adjust the body of bigint::FromWords (the loop over words() and the
post-copy handling) to perform that zero-fill; keep the existing signature and
constraints intact so calls like z0.FromWords(words) produce a fully zeroed high
part.

In `@include/Socket.h`:
- Around line 549-550: The current logic sends the header in plaintext
(Send(head)) and then dereferences *src.GetRawData() into EncryptionSend(),
leaking packet type/size and risking a nullptr when payload is absent; update
the send path so EncryptionSend(Packet) covers both header and payload (or
explicitly include the header bytes in the encrypted buffer) and avoid directly
dereferencing GetRawData()—instead call GetRawData() safely (check std::optional
before use) or use a GetRawData variant consistent with CheckHeader() (e.g.,
pass the same option flag) so header-only packets don't blow up; adjust the
Send(head) / EncryptionSend usage and add a presence check for GetRawData()
where Send(head) and EncryptionSend are combined.
🧹 Nitpick comments (2)
include/Socket.h (2)

565-569: ASyncSend(byte_view)[=] キャプチャ — byte_viewstd::span のため、参照先バッファのライフタイムに注意

byte_viewstd::span)は値コピーされますが、参照先のバッファ自体はコピーされません。呼び出し元が非同期タスク完了前にバッファを解放すると、ダングリングアクセスになります。

これはAPI設計上の注意事項であり、ドキュメントに明記することを推奨します。ASyncEncryptionRecv(byte_ref) (Line 592) も同様です。


609-629: _Send / _Recv テンプレートヘルパーは便利ですが、命名規約の懸念

_ プレフィックスは C++ 標準で予約されている名前と衝突する可能性があります(グローバルスコープではアンダースコア+大文字は予約)。クラスメンバーとしては技術的に問題ありませんが、一般的に _ プレフィックスは避けることが推奨されます。

Comment on lines 320 to 365
static constexpr bigint Karatuba_Legacy(const bigint& x, const bigint& y) {
bigint ret = 0;

return *this;
if (x == 0 || y == 0) {
return ret;
}

count_t nbit = std::max(x.GetNBit(), y.GetNBit());
count_t halfbits = (nbit + (nbit & 1)) / 2;

if (halfbits <= WordBits * 2) {
ret = NormalMul(x, y);
return ret;
}

bigint halfmask = (bigint(1) << halfbits) - 1;

bigint xl = x;
bigint xh = x;
bigint yl = y;
bigint yh = y;

xl &= halfmask;
xh >>= halfbits;
yl &= halfmask;
yh >>= halfbits;

bigint z0 = Karatuba(xl, yl);
bigint z2 = Karatuba(xh, yh);

xl += xh;
yl += yh;
bigint z1 = Karatuba(xl, yl);

z1 -= z0;
z1 -= z2;
ret += z0;

z1 <<= halfbits;
z2 <<= (2 * halfbits);

ret += z1;
ret += z2;

return ret;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Karatuba_Legacy の実装は正しい Karatsuba アルゴリズムです。

各再帰レベルで独自のローカル変数を持ち、値渡しで結果を返すため、Karatuba(Line 366)のような共有状態の問題がありません。ただし一点:Line 347 で Karatuba_Legacy ではなく Karatuba を再帰呼び出ししています。Karatuba には前述の致命的なバグがあるため、意図通りに動作しません。

🐛 修正案:再帰呼び出しを `Karatuba_Legacy` に統一
-		bigint z0 = Karatuba(xl, yl);
-		bigint z2 = Karatuba(xh, yh);
+		bigint z0 = Karatuba_Legacy(xl, yl);
+		bigint z2 = Karatuba_Legacy(xh, yh);
 		
 		xl += xh;
 		yl += yh;
-		bigint z1 = Karatuba(xl, yl);
+		bigint z1 = Karatuba_Legacy(xl, yl);
🤖 Prompt for AI Agents
In `@include/Cryptgraphy/MultiWordInt.h` around lines 320 - 365, The
Karatuba_Legacy implementation incorrectly calls Karatuba for recursive
multiplies (z0, z2, z1) which pulls in the buggy shared-state Karatuba; update
the three recursive calls inside Karatuba_Legacy so they call
Karatuba_Legacy(xl, yl), Karatuba_Legacy(xh, yh), and Karatuba_Legacy(xl, yl)
respectively (replace references to Karatuba with Karatuba_Legacy) to ensure
pure value-based recursion and correct behavior.

Comment on lines +549 to +550
auto head = std::bit_cast<Packet::header_bytes>(*src.GetHeader());
return Send(head) && EncryptionSend(*src.GetRawData());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

EncryptionSend(Packet) でヘッダーは暗号化せず、データのみ暗号化する設計は意図的ですか?

Line 549-550 でヘッダーは平文で送信し、GetRawData() のみ暗号化しています。ヘッダーにはパケットタイプとサイズが含まれるため、ネットワーク上でこれらのメタデータが漏洩します。

また GetRawData()std::optional を返しますが、ここで *src.GetRawData() と直接デリファレンスしています。CheckHeader() が先に呼ばれているため通常は安全ですが、CheckHeader()option=1(デフォルト)を使用し、GetRawData()CheckHeader(0) を使用しているため、ヘッダーのみでデータが空のパケットの場合に不整合が生じ得ます。

🤖 Prompt for AI Agents
In `@include/Socket.h` around lines 549 - 550, The current logic sends the header
in plaintext (Send(head)) and then dereferences *src.GetRawData() into
EncryptionSend(), leaking packet type/size and risking a nullptr when payload is
absent; update the send path so EncryptionSend(Packet) covers both header and
payload (or explicitly include the header bytes in the encrypted buffer) and
avoid directly dereferencing GetRawData()—instead call GetRawData() safely
(check std::optional before use) or use a GetRawData variant consistent with
CheckHeader() (e.g., pass the same option flag) so header-only packets don't
blow up; adjust the Send(head) / EncryptionSend usage and add a presence check
for GetRawData() where Send(head) and EncryptionSend are combined.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@include/Socket.h`:
- Around line 624-629: _ASyncRecv currently captures target by reference ([this,
&target]) causing potential dangling references if the caller's target goes out
of scope before the async task completes; change the implementation to avoid
referencing caller-owned storage: either capture a copy of the buffer by value
(e.g., capture a move/copy of target similar to _ASyncSend) and call _Recv on
that copy, or change the API to accept a std::shared_ptr<T> (update the template
and call site) and capture that shared_ptr by value so lifetime is extended;
update references to _Recv accordingly and adjust callers to pass the
copied/made-shared object.
🧹 Nitpick comments (4)
include/Cryptgraphy/MultiWordInt.h (2)

377-379: AssignMul は常に NormalMul を使用 — Karatuba の活用を検討

Karatuba が実装されていますが、AssignMul は常に NormalMul を使用しています。大きなワード数でのパフォーマンスが重要な場合、閾値に基づいて Karatuba に切り替える仕組みを検討してください。

♻️ 提案例
 constexpr bigint& AssignMul(bigint src) {
-    return *this = NormalMul(*this, src);
+    constexpr count_t KaratsubaThreshold = 4; // Words threshold
+    if constexpr (Words >= KaratsubaThreshold) {
+        return *this = Karatuba(*this, src);
+    } else {
+        return *this = NormalMul(*this, src);
+    }
 }

222-237: const auto&& は正しく動作しますが、const auto& で明確にしましょう

Line 227: const auto&& はフォワーディング参照ではありませんが、参照の畳み込み規則により lvalue 反復子でも正しくコンパイルされます。ただし、rvalue を扱うときに move セマンティクスを無効化するため、読み取り専用のアクセスが意図されている場合は const auto& を使用して意図をより明確にしてください。

🔄 推奨される変更
 	template<std::ranges::range R>
 		requires (std::is_convertible_v<word_t, std::ranges::range_value_t<R>>)
 	constexpr bigint& FromWords(R&& r) {
 		auto beg = m_words->begin();
 		auto end = m_words->end();
-		for (const auto&& elem : r) {
+		for (const auto& elem : r) {
 			if (beg == end) {
 				break;
 			}
 			*(beg++) = elem;
 		}
 		for (; beg != end; ++beg) {
 			*beg = 0;
 		}
 		return *this;
 	}
include/Socket.h (2)

565-607: 非同期ラムダで [&] の暗黙キャプチャが使われています — [this] を明示してください

Lines 566, 577, 582, 588, 599, 604 で [&] または [&, target = ...] が使われています。src はムーブ済みのため直接のダングリングリスクはありませんが、[&] による暗黙の this キャプチャは意図を不明確にします。[this, target = std::move(src)][this] を使用して明示的にしてください。

特に Lines 582, 604 の [&]()this のみが必要なので [this] で十分です。

♻️ 修正案(一部)
 std::future<bool> ASyncSend(bytearray&& src) {
-    return std::async(std::launch::async, [&, target = std::move(src)]() {
+    return std::async(std::launch::async, [this, target = std::move(src)]() {
         return this->Send(target);
     });
 }

 std::future<std::optional<Packet>> ASyncRecv() {
-    return std::async(std::launch::async, [&]() {
+    return std::async(std::launch::async, [this]() {
         return this->Recv();
     });
 }

他の ASyncSend(Packet&&), ASyncEncryptionSend, ASyncEncryptionRecv() にも同様に適用してください。


609-629: _Send/_Recv/_ASyncSend/_ASyncRecv: memcpyable テンプレートヘルパー — 命名の検討

機能的には正しく便利なヘルパーですが、先頭アンダースコア付きの名前(_Send 等)は C++ では予約名に近い印象を与えます(グローバルスコープではアンダースコア+大文字は予約)。クラススコープでは技術的に合法ですが、SendValue/RecvValue のような名前の方が慣習に沿います。

Comment on lines +624 to +629
template<class T>
std::future<bool> _ASyncRecv(T& target) requires (memcpyable<T>) {
return std::async(std::launch::async, [this, &target]() {
return this->_Recv<T>(target);
});
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

_ASyncRecvtarget を参照キャプチャ — 呼び出し元のライフタイム管理が必要

Line 626: [this, &target]target を参照キャプチャしていますが、非同期タスクの完了前に呼び出し元の target 変数がスコープを抜けるとダングリング参照になります。_ASyncSend (Line 620) のように値キャプチャが望ましいですが、_Recv はバッファへの書き込みが目的のため、ドキュメントで呼び出し元にライフタイム保証を要求するか、std::shared_ptr ラッパーの使用を検討してください。

🤖 Prompt for AI Agents
In `@include/Socket.h` around lines 624 - 629, _ASyncRecv currently captures
target by reference ([this, &target]) causing potential dangling references if
the caller's target goes out of scope before the async task completes; change
the implementation to avoid referencing caller-owned storage: either capture a
copy of the buffer by value (e.g., capture a move/copy of target similar to
_ASyncSend) and call _Recv on that copy, or change the API to accept a
std::shared_ptr<T> (update the template and call site) and capture that
shared_ptr by value so lifetime is extended; update references to _Recv
accordingly and adjust callers to pass the copied/made-shared object.

ルックアップテーブルに誤りがあったのを訂正
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant