Spaces:
Running
Running
Commit Β·
74d99be
1
Parent(s): 5ce4119
Add Java rate limiter and C++ event dispatcher tasks; update requirements
Browse files- server/environment.py +142 -1
server/environment.py
CHANGED
|
@@ -144,6 +144,147 @@ TASKS: Dict[str, dict] = {
|
|
| 144 |
"severity_valid": ["critical"],
|
| 145 |
},
|
| 146 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 147 |
}
|
| 148 |
|
| 149 |
|
|
@@ -303,4 +444,4 @@ class CodeReviewEnvironment:
|
|
| 303 |
step_number=step_number,
|
| 304 |
max_steps=MAX_STEPS,
|
| 305 |
previous_feedback=previous_feedback,
|
| 306 |
-
)
|
|
|
|
| 144 |
"severity_valid": ["critical"],
|
| 145 |
},
|
| 146 |
},
|
| 147 |
+
|
| 148 |
+
# ββ EXPERT ββββββββββββββββββββββββββββββββ
|
| 149 |
+
"expert": {
|
| 150 |
+
"id": "task_expert_001",
|
| 151 |
+
"difficulty": "expert",
|
| 152 |
+
"language": "java",
|
| 153 |
+
"description": (
|
| 154 |
+
"This Java class implements a token bucket rate limiter. "
|
| 155 |
+
"Identify the logic bug that could allow users to bypass the rate limit."
|
| 156 |
+
),
|
| 157 |
+
"code": (
|
| 158 |
+
"import java.util.concurrent.atomic.AtomicLong;\n\n"
|
| 159 |
+
"public class TokenBucketRateLimiter {\n"
|
| 160 |
+
" private final long maxTokens;\n"
|
| 161 |
+
" private final long refillRatePerSecond;\n"
|
| 162 |
+
" private AtomicLong currentTokens;\n"
|
| 163 |
+
" private AtomicLong lastRefillTimestamp;\n\n"
|
| 164 |
+
" public TokenBucketRateLimiter(long maxTokens, long refillRatePerSecond) {\n"
|
| 165 |
+
" this.maxTokens = maxTokens;\n"
|
| 166 |
+
" this.refillRatePerSecond = refillRatePerSecond;\n"
|
| 167 |
+
" this.currentTokens = new AtomicLong(maxTokens);\n"
|
| 168 |
+
" this.lastRefillTimestamp = new AtomicLong(System.currentTimeMillis());\n"
|
| 169 |
+
" }\n\n"
|
| 170 |
+
" /**\n"
|
| 171 |
+
" * Checks if the requested number of tokens is available.\n"
|
| 172 |
+
" * Decrements the bucket if allowed.\n"
|
| 173 |
+
" */\n"
|
| 174 |
+
" public synchronized boolean allowRequest(int tokensNeeded) {\n"
|
| 175 |
+
" refill();\n"
|
| 176 |
+
" if (currentTokens.get() >= tokensNeeded) {\n"
|
| 177 |
+
" currentTokens.addAndGet(-tokensNeeded);\n"
|
| 178 |
+
" return true;\n"
|
| 179 |
+
" }\n"
|
| 180 |
+
" return false;\n"
|
| 181 |
+
" }\n\n"
|
| 182 |
+
" private void refill() {\n"
|
| 183 |
+
" long now = System.currentTimeMillis();\n"
|
| 184 |
+
" long timeElapsedMs = now - lastRefillTimestamp.get();\n"
|
| 185 |
+
" \n"
|
| 186 |
+
" // Calculate how many tokens to add based on time elapsed\n"
|
| 187 |
+
" long tokensToAdd = (timeElapsedMs / 1000) * refillRatePerSecond;\n\n"
|
| 188 |
+
" if (tokensToAdd > 0) {\n"
|
| 189 |
+
" // Hint: Look closely at how the tokens are updated here.\n"
|
| 190 |
+
" // Consider what happens if a user stops making requests for a long time.\n"
|
| 191 |
+
" currentTokens.addAndGet(tokensToAdd);\n"
|
| 192 |
+
" lastRefillTimestamp.set(now);\n"
|
| 193 |
+
" }\n"
|
| 194 |
+
" }\n"
|
| 195 |
+
"}"
|
| 196 |
+
),
|
| 197 |
+
"ground_truth": {
|
| 198 |
+
"bug_identified": True,
|
| 199 |
+
"bug_type_keywords": [
|
| 200 |
+
"logic", "limit", "overflow", "cap", "bound", "maximum", "exceed",
|
| 201 |
+
"logic error", "capacity",
|
| 202 |
+
],
|
| 203 |
+
"location_keywords": [
|
| 204 |
+
"currentTokens.addAndGet", "refill()", "tokensToAdd",
|
| 205 |
+
"currentTokens.get()", "addAndGet(tokensToAdd)",
|
| 206 |
+
],
|
| 207 |
+
"description_keywords": [
|
| 208 |
+
"exceed", "maxTokens", "cap", "limit", "bound",
|
| 209 |
+
"overflow", "infinite", "burst", "accumulate",
|
| 210 |
+
],
|
| 211 |
+
"fix_keywords": [
|
| 212 |
+
"Math.min", "min(", "set(", "if (currentTokens.get() > maxTokens)",
|
| 213 |
+
"compareAndSet", "cap",
|
| 214 |
+
],
|
| 215 |
+
"severity_valid": ["high", "medium"],
|
| 216 |
+
},
|
| 217 |
+
},
|
| 218 |
+
|
| 219 |
+
# ββ EXPERT 2 (C++) ββββββββββββββββββββββββ
|
| 220 |
+
"expert2": {
|
| 221 |
+
"id": "task_expert_002",
|
| 222 |
+
"difficulty": "expert2",
|
| 223 |
+
"language": "cpp",
|
| 224 |
+
"description": (
|
| 225 |
+
"This C++ class implements an event dispatcher. "
|
| 226 |
+
"Identify the concurrency bug that can occur when an event is dispatched."
|
| 227 |
+
),
|
| 228 |
+
"code": (
|
| 229 |
+
"#include <iostream>\n"
|
| 230 |
+
"#include <vector>\n"
|
| 231 |
+
"#include <functional>\n"
|
| 232 |
+
"#include <mutex>\n"
|
| 233 |
+
"#include <algorithm>\n"
|
| 234 |
+
"#include <string>\n\n"
|
| 235 |
+
"class EventDispatcher {\n"
|
| 236 |
+
"public:\n"
|
| 237 |
+
" using Callback = std::function<void(const std::string&)>;\n\n"
|
| 238 |
+
" void subscribe(int listener_id, Callback cb) {\n"
|
| 239 |
+
" std::lock_guard<std::mutex> lock(mut_);\n"
|
| 240 |
+
" listeners_.push_back({listener_id, cb});\n"
|
| 241 |
+
" }\n\n"
|
| 242 |
+
" void unsubscribe(int listener_id) {\n"
|
| 243 |
+
" std::lock_guard<std::mutex> lock(mut_);\n"
|
| 244 |
+
" listeners_.erase(\n"
|
| 245 |
+
" std::remove_if(listeners_.begin(), listeners_.end(),\n"
|
| 246 |
+
" [listener_id](const Listener& l) { return l.id == listener_id; }),\n"
|
| 247 |
+
" listeners_.end()\n"
|
| 248 |
+
" );\n"
|
| 249 |
+
" }\n\n"
|
| 250 |
+
" void dispatch(const std::string& event_data) {\n"
|
| 251 |
+
" std::lock_guard<std::mutex> lock(mut_);\n"
|
| 252 |
+
" for (const auto& listener : listeners_) {\n"
|
| 253 |
+
" // Hint: What happens if a listener decides to call unsubscribe() \n"
|
| 254 |
+
" // from inside their own callback function when an event fires?\n"
|
| 255 |
+
" listener.cb(event_data);\n"
|
| 256 |
+
" }\n"
|
| 257 |
+
" }\n\n"
|
| 258 |
+
"private:\n"
|
| 259 |
+
" struct Listener {\n"
|
| 260 |
+
" int id;\n"
|
| 261 |
+
" Callback cb;\n"
|
| 262 |
+
" };\n \n"
|
| 263 |
+
" std::vector<Listener> listeners_;\n"
|
| 264 |
+
" std::mutex mut_;\n"
|
| 265 |
+
"};"
|
| 266 |
+
),
|
| 267 |
+
"ground_truth": {
|
| 268 |
+
"bug_identified": True,
|
| 269 |
+
"bug_type_keywords": [
|
| 270 |
+
"deadlock", "concurrency", "lock", "recursive", "reentrant", "hang",
|
| 271 |
+
"iterator validation", "undefined behavior"
|
| 272 |
+
],
|
| 273 |
+
"location_keywords": [
|
| 274 |
+
"listener.cb", "unsubscribe", "dispatch", "mut_", "std::lock_guard",
|
| 275 |
+
"lock(mut_)"
|
| 276 |
+
],
|
| 277 |
+
"description_keywords": [
|
| 278 |
+
"deadlock", "already locked", "same thread", "recursive_mutex",
|
| 279 |
+
"reentrant", "hangs", "blocks", "invalidate", "iterator"
|
| 280 |
+
],
|
| 281 |
+
"fix_keywords": [
|
| 282 |
+
"std::recursive_mutex", "copy", "local copy", "copy the vector",
|
| 283 |
+
"unlock before", "queue", "deferred"
|
| 284 |
+
],
|
| 285 |
+
"severity_valid": ["high", "critical"],
|
| 286 |
+
},
|
| 287 |
+
},
|
| 288 |
}
|
| 289 |
|
| 290 |
|
|
|
|
| 444 |
step_number=step_number,
|
| 445 |
max_steps=MAX_STEPS,
|
| 446 |
previous_feedback=previous_feedback,
|
| 447 |
+
)
|