From 2a70c459375703d9511ea3b1e52b35fbe4b242ad Mon Sep 17 00:00:00 2001 From: X512 Date: Sat, 2 Aug 2025 15:11:23 +0900 Subject: [PATCH] TokenSpace: fix token wraparound Fix bug that allocating/freeing a lot of BHandler cause token wraparound and overwriting existing assigned tokens. Change-Id: I12527126644bca1793a8475dc487f131e6f83437 Reviewed-on: https://review.haiku-os.org/c/haiku/+/9533 Reviewed-by: waddlesplash --- headers/private/app/TokenSpace.h | 2 +- src/kits/app/TokenSpace.cpp | 35 ++++++++++++++++++++++++-------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/headers/private/app/TokenSpace.h b/headers/private/app/TokenSpace.h index a3aacef566..609533d403 100644 --- a/headers/private/app/TokenSpace.h +++ b/headers/private/app/TokenSpace.h @@ -62,7 +62,7 @@ private: typedef std::map TokenMap; TokenMap fTokenMap; - int32 fTokenCount; + int32 fNextToken; }; diff --git a/src/kits/app/TokenSpace.cpp b/src/kits/app/TokenSpace.cpp index 60c8ba2aa0..dc4ec3e9bd 100644 --- a/src/kits/app/TokenSpace.cpp +++ b/src/kits/app/TokenSpace.cpp @@ -20,10 +20,20 @@ BTokenSpace gDefaultTokens; // the default token space - all handlers will go into that one +static int32 +get_next_token(int32 token) +{ + if (token == INT32_MAX) + return 1; + else + return token + 1; +} + + BTokenSpace::BTokenSpace() : BLocker("token space"), - fTokenCount(1) + fNextToken(1) { } @@ -39,17 +49,24 @@ BTokenSpace::NewToken(int16 type, void* object) BAutolock locker(this); token_info tokenInfo = { type, object, NULL }; - int32 token = fTokenCount; + + int32 wraparoundToken = fNextToken; try { - fTokenMap[token] = tokenInfo; + for (;;) { + int32 token = fNextToken; + bool done = fTokenMap.insert(std::pair(token, tokenInfo)).second; + fNextToken = get_next_token(token); + + if (done) + return token; + + if (fNextToken == wraparoundToken) + return -1; + } } catch (std::bad_alloc& exception) { return -1; } - - fTokenCount++; - - return token; } @@ -73,8 +90,8 @@ BTokenSpace::SetToken(int32 token, int16 type, void* object) } // this makes sure SetToken() plays more or less nice with NewToken() - if (token >= fTokenCount) - fTokenCount = token + 1; + if (token >= fNextToken) + fNextToken = get_next_token(token); return true; }