Skip to content

Conversation

@wmh
Copy link

@wmh wmh commented Dec 5, 2025

Summary

This PR fixes a potential buffer overflow vulnerability in the Windows process report implementation by replacing unsafe sprintf with snprintf.

Changes

  • Updated toISOString helper function to accept a bufferSize parameter
  • Replaced sprintf with snprintf to prevent buffer overflow
  • Updated the call site to pass sizeof(timeBuf) for proper bounds checking

Security Impact

The previous code used sprintf without bounds checking when formatting timestamps, which could lead to buffer overflow if the formatted string exceeded the 64-byte buffer size. This change ensures the output is always truncated to fit within the allocated buffer.

Testing

This is a Windows-only code path in BunProcessReportObjectWindows.cpp. The change is minimal and maintains the same functionality while adding safety.

Copilot AI review requested due to automatic review settings December 5, 2025 11:42
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses a buffer overflow vulnerability in the Windows process report implementation by replacing unsafe sprintf with snprintf. While the security improvement is valuable, the implementation introduces an API inconsistency and duplicates existing functionality.

Key changes:

  • Added bufferSize parameter to toISOString function in Windows implementation
  • Replaced sprintf with snprintf for bounds checking
  • Updated call site to pass buffer size
Comments suppressed due to low confidence (1)

src/bun.js/bindings/BunProcessReportObjectWindows.cpp:53

  • This function appears to be a duplicate implementation of the canonical Bun::toISOString already defined in wtf-bindings.cpp (line 211). The canonical version is more robust as it:
  • Uses vm.dateCache.msToGregorianDateTime() instead of gmtime()
  • Properly handles years outside the 0-9999 range per ES spec
  • Returns the number of characters written
  • Already uses snprintf safely

Consider removing this duplicate implementation and using the canonical version instead.

static void toISOString(JSC::VM& vm, double time, char* buffer, size_t bufferSize)
{
    time_t seconds = static_cast<time_t>(time / 1000);
    int milliseconds = static_cast<int>(time) % 1000;
    struct tm* timeinfo = gmtime(&seconds);

    snprintf(buffer, bufferSize, "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ",
        timeinfo->tm_year + 1900,
        timeinfo->tm_mon + 1,
        timeinfo->tm_mday,
        timeinfo->tm_hour,
        timeinfo->tm_min,
        timeinfo->tm_sec,
        milliseconds);
}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


// Helper function to convert time to ISO string
static void toISOString(JSC::VM& vm, double time, char* buffer)
static void toISOString(JSC::VM& vm, double time, char* buffer, size_t bufferSize)
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

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

The signature change to add bufferSize parameter creates an inconsistency with the canonical Bun::toISOString function declared in wtf-bindings.h (line 12) and implemented in wtf-bindings.cpp (line 211). The canonical version has the signature:

size_t toISOString(JSC::VM& vm, double date, char buffer[64]);

This creates a name collision since both are in the Bun namespace. Consider either:

  1. Using the canonical Bun::toISOString from wtf-bindings.cpp which already uses snprintf safely
  2. Renaming this Windows-specific version to avoid the collision (e.g., toISOStringWindows)

The canonical version also handles edge cases better (years outside 0-9999 range).

Copilot uses AI. Check for mistakes.
{
time_t seconds = static_cast<time_t>(time / 1000);
int milliseconds = static_cast<int>(time) % 1000;
struct tm* timeinfo = gmtime(&seconds);
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

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

Missing null check for gmtime() return value. The gmtime() function can return nullptr if the time value is invalid or out of range. Dereferencing a null pointer would cause a crash.

The canonical implementation in wtf-bindings.cpp avoids this by using vm.dateCache.msToGregorianDateTime() which is safer. Consider adding a null check:

struct tm* timeinfo = gmtime(&seconds);
if (!timeinfo) {
    buffer[0] = '\0';
    return;
}
Suggested change
struct tm* timeinfo = gmtime(&seconds);
struct tm* timeinfo = gmtime(&seconds);
if (!timeinfo) {
buffer[0] = '\0';
return;
}

Copilot uses AI. Check for mistakes.
// Helper function to convert time to ISO string
static void toISOString(JSC::VM& vm, double time, char* buffer)
static void toISOString(JSC::VM& vm, double time, char* buffer, size_t bufferSize)
{
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

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

The vm parameter is unused in this function. Consider adding UNUSED_PARAM(vm); at the beginning of the function to suppress compiler warnings, or better yet, use the canonical implementation from wtf-bindings.cpp which properly utilizes vm.dateCache for safer date/time conversion.

Suggested change
{
{
UNUSED_PARAM(vm);

Copilot uses AI. Check for mistakes.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 5, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Removes a local ISO time-formatting helper from BunProcessReportObjectWindows.cpp, adds #include "wtf-bindings.h", and switches to Bun::toISOString(vm, time, timeBuf) for formatting. No exported or public signatures changed.

Changes

Cohort / File(s) Summary
Process report Windows binding
src/bun.js/bindings/BunProcessReportObjectWindows.cpp
Added #include "wtf-bindings.h"; removed the file-local static toISOString(JSC::VM&, double, char*) helper and its implementation; call sites now use Bun::toISOString(vm, time, timeBuf). No public/exported signature changes.

Pre-merge checks

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix buffer overflow in Windows process report' clearly and specifically summarizes the main change: addressing a buffer overflow vulnerability in Windows process reporting.
Description check ✅ Passed The description includes all required template sections: it explains what the PR does (fixes buffer overflow by replacing sprintf with snprintf) and how it was verified (Windows-only code path with maintained functionality).

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 28e79d2 and e098014.

📒 Files selected for processing (1)
  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.{cpp,zig}

📄 CodeRabbit inference engine (.cursor/rules/building-bun.mdc)

src/**/*.{cpp,zig}: Use bun bd or bun run build:debug to build debug versions for C++ and Zig source files; creates debug build at ./build/debug/bun-debug
Run tests using bun bd test <test-file> with the debug build; never use bun test directly as it will not include your changes
Execute files using bun bd <file> <...args>; never use bun <file> directly as it will not include your changes
Enable debug logs for specific scopes using BUN_DEBUG_$(SCOPE)=1 environment variable
Code generation happens automatically as part of the build process; no manual code generation commands are required

Files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
src/bun.js/bindings/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

src/bun.js/bindings/**/*.cpp: JavaScript class implementations in C++ should create three classes if there's a public constructor: Foo (JSDestructibleObject), FooPrototype (JSNonFinalObject), and FooConstructor (InternalFunction)
Define properties in C++ JavaScript classes using HashTableValue arrays
Add iso subspaces for C++ JavaScript classes with C++ fields
Cache structures in ZigGlobalObject for C++ JavaScript classes

Files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
🧠 Learnings (22)
📓 Common learnings
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.h : Add BUN_EXPORT visibility attribute to all public V8 API functions to ensure proper symbol export across platforms
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-02T05:59:51.485Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Add iso subspaces for C++ JavaScript classes with C++ fields
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.h : Add BUN_EXPORT visibility attribute to all public V8 API functions to ensure proper symbol export across platforms

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-11-24T18:37:47.899Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/AGENTS.md:0-0
Timestamp: 2025-11-24T18:37:47.899Z
Learning: Applies to src/bun.js/bindings/v8/**/<UNKNOWN> : <UNKNOWN>

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-12-02T05:59:51.485Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-02T05:59:51.485Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Add iso subspaces for C++ JavaScript classes with C++ fields

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.h : Create V8 class headers with .h extension following the pattern V8ClassName.h that include pragma once, v8.h, V8Local.h, V8Isolate.h, and declare classes extending from Data with BUN_EXPORT static methods

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Create V8 class implementations with .cpp extension following the pattern V8ClassName.cpp that include the header, v8_compatibility_assertions.h, use ASSERT_V8_TYPE_LAYOUT_MATCHES macro, and implement methods using isolate->currentHandleScope()->createLocal<T>() for handle creation

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.txt : Add symbol names without leading underscore to src/symbols.txt for each new V8 API method

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8-module/main.cpp : Create test functions in test/v8/v8-module/main.cpp that take FunctionCallbackInfo<Value> parameter, use the test V8 API, print results for comparison with Node.js, and return Undefined

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8.test.ts : Add corresponding test cases to test/v8/v8.test.ts using checkSameOutput() function to compare Node.js and Bun output

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-12-02T05:59:51.485Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-02T05:59:51.485Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : JavaScript class implementations in C++ should create three classes if there's a public constructor: `Foo` (JSDestructibleObject), `FooPrototype` (JSNonFinalObject), and `FooConstructor` (InternalFunction)

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use localToJSValue() to convert V8 handles to JSC values and perform JSC operations within V8 method implementations

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-10-01T21:59:54.571Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h:47-74
Timestamp: 2025-10-01T21:59:54.571Z
Learning: In the new bindings generator (bindgenv2) for `src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h`, the context-aware enumeration conversion overloads intentionally use stricter validation (requiring `value.isString()` without ToString coercion), diverging from Web IDL semantics. This is a design decision documented in comments.

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-10-01T21:49:27.862Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/BunIDLConvert.h:29-42
Timestamp: 2025-10-01T21:49:27.862Z
Learning: In Bun's IDL bindings (src/bun.js/bindings/BunIDLConvert.h), IDLStrictNull intentionally treats both undefined and null as null (using isUndefinedOrNull()), matching WebKit's IDLNull & IDLNullable behavior. This is the correct implementation and should not be changed to only accept null.

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/napi/napi.zig : For each new V8 C++ method, add both GCC/Clang and MSVC mangled symbol names to the V8API struct in src/napi/napi.zig using extern fn declarations

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-09-12T18:16:50.754Z
Learnt from: RiskyMH
Repo: oven-sh/bun PR: 22606
File: src/glob/GlobWalker.zig:449-452
Timestamp: 2025-09-12T18:16:50.754Z
Learning: For Bun codebase: prefer using `std.fs.path.sep` over manual platform separator detection, and use `bun.strings.lastIndexOfChar` instead of `std.mem.lastIndexOfScalar` for string operations.

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use isolate->currentHandleScope()->createLocal<T>() to create local V8 handles and ensure all V8 values are created within an active handle scope

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use V8_UNIMPLEMENTED() macro for functions not yet implemented in V8 compatibility classes

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-12-02T05:59:51.485Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-02T05:59:51.485Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Cache structures in ZigGlobalObject for C++ JavaScript classes

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-11-24T18:35:25.883Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/javascriptcore-class.mdc:0-0
Timestamp: 2025-11-24T18:35:25.883Z
Learning: Applies to *.cpp : To create JavaScript objects from Zig, implement C++ functions following the `Bun__ClassName__toJS(Zig::GlobalObject*, NativeType*)` convention that construct and return the JavaScript object as an encoded JSValue

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-11-24T18:35:39.205Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/registering-bun-modules.mdc:0-0
Timestamp: 2025-11-24T18:35:39.205Z
Learning: Applies to **/js_*.zig : Use `bun.JSError!JSValue` for proper error propagation in JavaScript bindings

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-12-02T05:59:51.485Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-02T05:59:51.485Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Define properties in C++ JavaScript classes using HashTableValue arrays

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use JSC::WriteBarrier for heap-allocated references in V8 objects and implement visitChildren() for custom heap objects to support garbage collection

Applied to files:

  • src/bun.js/bindings/BunProcessReportObjectWindows.cpp
🔇 Additional comments (2)
src/bun.js/bindings/BunProcessReportObjectWindows.cpp (2)

8-8: LGTM - Include added for canonical implementation.

The include provides access to the canonical Bun::toISOString function, which resolves the buffer overflow issue mentioned in past reviews by using a safer implementation.


60-62: The justification referencing a canonical Bun::toISOString from wtf-bindings.h appears to be based on incorrect assumptions about where toISOString is implemented. According to available documentation, toISOString is implemented in JavaScriptCore (JSC), not in wtf-bindings. The actual implementation and safety claims cannot be verified without access to the codebase.

Likely an incorrect or invalid review comment.


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.

@wmh wmh force-pushed the claude/fix-windows-process-report-buffer-overflow branch from 7a686c2 to 3e4e774 Compare December 5, 2025 11:57
Hunter and others added 2 commits December 7, 2025 11:14
Remove duplicate toISOString helper and use the existing canonical
version from wtf-bindings.h. The canonical version is more robust:
- Already uses snprintf safely
- Uses vm.dateCache.msToGregorianDateTime() instead of gmtime()
- Handles edge cases like years outside 0-9999 range per ES spec
- Returns character count for validation

This addresses the CodeRabbit review feedback about API inconsistency
and code duplication.
@wmh wmh force-pushed the claude/fix-windows-process-report-buffer-overflow branch from 28e79d2 to e098014 Compare December 7, 2025 03:14
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