ffi: refresh cached string buffers on every call - #65051

Merged
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
trivikr:ffi-temp-string-buffer-reuse
Aug 14, 2026
Merged

ffi: refresh cached string buffers on every call#65051
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
trivikr:ffi-temp-string-buffer-reuse

Conversation

@trivikr

Copy link
Copy Markdown
Member

Fixes: #65050

Native code can mutate temporary string storage during an FFI call. Rewrite cached buffers on every conversion so a later call with the same JavaScript string receives a fresh copy of its UTF-8 bytes.


Assisted-by: codex:gpt-5.6-sol

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/ffi

@nodejs-github-botnodejs-github-bot added ffi Issues and PRs related to experimental Foreign Function Interface support. needs-ci PRs that need a full CI run. labels Aug 5, 2026
@codecov

codecovBot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.31%. Comparing base (a576f1c) to head (8ef6d08).
⚠️ Report is 51 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #65051 +/- ##
=======================================
Coverage 90.30% 90.31% =======================================
Files 760 760 Lines 248526 248521 -5 Branches 46886 46896 +10 =======================================
+ Hits 224439 224445 +6 + Misses 15515 15502 -13 - Partials 8572 8574 +2 
Files with missing linesCoverage Δ
lib/internal/ffi/fast-api.js95.54% <ø> (+0.76%)⬆️

... and 28 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
MILLERMARRU

This comment was marked as low quality.

@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from a88fe4c to 8f76513CompareAugust 9, 2026 23:22

@mcollinamcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

@trivikrtrivikr added the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 10, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 10, 2026
@nodejs-github-bot

This comment was marked as outdated.

@trivikrtrivikr added request-ci Add this label to start a Jenkins CI on a PR. needs-ci PRs that need a full CI run. and removed needs-ci PRs that need a full CI run. request-ci Add this label to start a Jenkins CI on a PR. labels Aug 10, 2026
@nodejs-github-bot

This comment was marked as resolved.

@trivikr

Copy link
Copy Markdown
MemberAuthor

Converted to draft as test-ffi-fast-buffer is failing on ci.nodejs.org/job/node-test-commit-aix/64314

---duration_ms: 1355.201exitcode: 1severity: failstack: |- Test failure: 'fast FFI refreshes cached temporary string buffers' Location: test/ffi/test-ffi-fast-buffer.js:99:1 AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: '' !== 'yello' at TestContext.<anonymous> (/home/iojs/build/workspace/node-test-commit-aix/nodes/aix72-power9/test/ffi/test-ffi-fast-buffer.js:108:12) at Test.runInAsyncScope (node:async_hooks:227:14) at Test.run (node:internal/test_runner/test:1397:25) at Test.processPendingSubtests (node:internal/test_runner/test:969:18) at Test.postRun (node:internal/test_runner/test:1537:19) at Test.run (node:internal/test_runner/test:1462:12) at process.processTicksAndRejections (node:internal/process/task_queues:104:5) at async Test.processPendingSubtests (node:internal/test_runner/test:969:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: '', expected: 'yello', operator: 'strictEqual', diff: 'simple' } (node:38469944) internal/test/binding: These APIs are for internal testing only. Do not use them. (Use `node --trace-warnings ...` to show where the warning was created) (node:38469944) ExperimentalWarning: FFI is an experimental feature and might change at any time...

@trivikr
trivikr marked this pull request as draft August 10, 2026 20:51
@trivikr
trivikr marked this pull request as ready for review August 11, 2026 01:43
@trivikr

Copy link
Copy Markdown
MemberAuthor

There was a bug in test.

AIX does not support Node’s PPC64 fast-call trampoline, so it exposes the test’s invalid assumption: the pointer returned by overwrite_string() points into temporary storage owned by Node’s generic FFI invocation. That storage is only valid during the native call. AIX frees/reuses the storage immediately, yielding ''.

Fast-path platforms retain the cached Buffer, so "yello" remains readable.

It was fixed in 89cc17f by observing the mutation during the native call instead of returning a pointer to temporary storage.

I'll re-request review after the CI is successful.

Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from 89cc17f to d225103CompareAugust 11, 2026 01:46
@trivikrtrivikr removed the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 11, 2026
@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from d225103 to 8ef6d08CompareAugust 11, 2026 01:52
@trivikr

Copy link
Copy Markdown
MemberAuthor

The ffi contract explicitly says JavaScript strings are copied to temporary NUL-terminated UTF-8 storage “for the duration of the call”

string values are copied to temporary NUL-terminated UTF-8 strings for the duration of the call.

The fast path happens to retain reusable buffers longer, but that is an implementation detail, not a lifetime guarantee.
The test should return the observed byte by value as done in 8ef6d08 and not the pointer.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@trivikr

Copy link
Copy Markdown
MemberAuthor

@mcollina@jasnell One of the tests was incorrect, and it surfaced in CI failures in AIX.
It's fixed now in 8ef6d08 and CI is successful.

Can you please provide your approval again?

@trivikrtrivikr added commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue PRs queued for automated landing through the Commit Queue. labels Aug 14, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 54ac460 into nodejs:mainAug 14, 2026
71 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 54ac460

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 14, 2026
@trivikr
trivikr deleted the ffi-temp-string-buffer-reuse branch August 16, 2026 16:01
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: #65051Fixes: #65050
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: #65051Fixes: #65050
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commit-queue-squashPRs the Commit Queue should land as one squashed commit.ffiIssues and PRs related to experimental Foreign Function Interface support.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ffi reuses mutated temporary string buffer without restoring its contents

5 participants

@trivikr@nodejs-github-bot@mcollina@jasnell@MILLERMARRU
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

ffi: refresh cached string buffers on every call - #65051

Merged
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
trivikr:ffi-temp-string-buffer-reuse
Aug 14, 2026
Merged

ffi: refresh cached string buffers on every call#65051
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
trivikr:ffi-temp-string-buffer-reuse

Conversation

@trivikr

Copy link
Copy Markdown
Member

Fixes: #65050

Native code can mutate temporary string storage during an FFI call. Rewrite cached buffers on every conversion so a later call with the same JavaScript string receives a fresh copy of its UTF-8 bytes.


Assisted-by: codex:gpt-5.6-sol

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/ffi

@nodejs-github-botnodejs-github-bot added ffi Issues and PRs related to experimental Foreign Function Interface support. needs-ci PRs that need a full CI run. labels Aug 5, 2026
@codecov

codecovBot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.31%. Comparing base (a576f1c) to head (8ef6d08).
⚠️ Report is 51 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #65051 +/- ##
=======================================
Coverage 90.30% 90.31% =======================================
Files 760 760 Lines 248526 248521 -5 Branches 46886 46896 +10 =======================================
+ Hits 224439 224445 +6 + Misses 15515 15502 -13 - Partials 8572 8574 +2 
Files with missing linesCoverage Δ
lib/internal/ffi/fast-api.js95.54% <ø> (+0.76%)⬆️

... and 28 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
MILLERMARRU

This comment was marked as low quality.

@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from a88fe4c to 8f76513CompareAugust 9, 2026 23:22

@mcollinamcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

@trivikrtrivikr added the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 10, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 10, 2026
@nodejs-github-bot

This comment was marked as outdated.

@trivikrtrivikr added request-ci Add this label to start a Jenkins CI on a PR. needs-ci PRs that need a full CI run. and removed needs-ci PRs that need a full CI run. request-ci Add this label to start a Jenkins CI on a PR. labels Aug 10, 2026
@nodejs-github-bot

This comment was marked as resolved.

@trivikr

Copy link
Copy Markdown
MemberAuthor

Converted to draft as test-ffi-fast-buffer is failing on ci.nodejs.org/job/node-test-commit-aix/64314

---duration_ms: 1355.201exitcode: 1severity: failstack: |- Test failure: 'fast FFI refreshes cached temporary string buffers' Location: test/ffi/test-ffi-fast-buffer.js:99:1 AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: '' !== 'yello' at TestContext.<anonymous> (/home/iojs/build/workspace/node-test-commit-aix/nodes/aix72-power9/test/ffi/test-ffi-fast-buffer.js:108:12) at Test.runInAsyncScope (node:async_hooks:227:14) at Test.run (node:internal/test_runner/test:1397:25) at Test.processPendingSubtests (node:internal/test_runner/test:969:18) at Test.postRun (node:internal/test_runner/test:1537:19) at Test.run (node:internal/test_runner/test:1462:12) at process.processTicksAndRejections (node:internal/process/task_queues:104:5) at async Test.processPendingSubtests (node:internal/test_runner/test:969:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: '', expected: 'yello', operator: 'strictEqual', diff: 'simple' } (node:38469944) internal/test/binding: These APIs are for internal testing only. Do not use them. (Use `node --trace-warnings ...` to show where the warning was created) (node:38469944) ExperimentalWarning: FFI is an experimental feature and might change at any time...

@trivikr
trivikr marked this pull request as draft August 10, 2026 20:51
@trivikr
trivikr marked this pull request as ready for review August 11, 2026 01:43
@trivikr

Copy link
Copy Markdown
MemberAuthor

There was a bug in test.

AIX does not support Node’s PPC64 fast-call trampoline, so it exposes the test’s invalid assumption: the pointer returned by overwrite_string() points into temporary storage owned by Node’s generic FFI invocation. That storage is only valid during the native call. AIX frees/reuses the storage immediately, yielding ''.

Fast-path platforms retain the cached Buffer, so "yello" remains readable.

It was fixed in 89cc17f by observing the mutation during the native call instead of returning a pointer to temporary storage.

I'll re-request review after the CI is successful.

Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from 89cc17f to d225103CompareAugust 11, 2026 01:46
@trivikrtrivikr removed the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 11, 2026
@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from d225103 to 8ef6d08CompareAugust 11, 2026 01:52
@trivikr

Copy link
Copy Markdown
MemberAuthor

The ffi contract explicitly says JavaScript strings are copied to temporary NUL-terminated UTF-8 storage “for the duration of the call”

string values are copied to temporary NUL-terminated UTF-8 strings for the duration of the call.

The fast path happens to retain reusable buffers longer, but that is an implementation detail, not a lifetime guarantee.
The test should return the observed byte by value as done in 8ef6d08 and not the pointer.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@trivikr

Copy link
Copy Markdown
MemberAuthor

@mcollina@jasnell One of the tests was incorrect, and it surfaced in CI failures in AIX.
It's fixed now in 8ef6d08 and CI is successful.

Can you please provide your approval again?

@trivikrtrivikr added commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue PRs queued for automated landing through the Commit Queue. labels Aug 14, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 54ac460 into nodejs:mainAug 14, 2026
71 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 54ac460

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 14, 2026
@trivikr
trivikr deleted the ffi-temp-string-buffer-reuse branch August 16, 2026 16:01
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: #65051Fixes: #65050
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: #65051Fixes: #65050
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commit-queue-squashPRs the Commit Queue should land as one squashed commit.ffiIssues and PRs related to experimental Foreign Function Interface support.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ffi reuses mutated temporary string buffer without restoring its contents

5 participants

@trivikr@nodejs-github-bot@mcollina@jasnell@MILLERMARRU
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ffi: refresh cached string buffers on every call - #65051

Merged
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
trivikr:ffi-temp-string-buffer-reuse
Aug 14, 2026
Merged

ffi: refresh cached string buffers on every call#65051
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
trivikr:ffi-temp-string-buffer-reuse

Conversation

@trivikr

Copy link
Copy Markdown
Member

Fixes: #65050

Native code can mutate temporary string storage during an FFI call. Rewrite cached buffers on every conversion so a later call with the same JavaScript string receives a fresh copy of its UTF-8 bytes.


Assisted-by: codex:gpt-5.6-sol

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/ffi

@nodejs-github-botnodejs-github-bot added ffi Issues and PRs related to experimental Foreign Function Interface support. needs-ci PRs that need a full CI run. labels Aug 5, 2026
@codecov

codecovBot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.31%. Comparing base (a576f1c) to head (8ef6d08).
⚠️ Report is 51 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #65051 +/- ##
=======================================
Coverage 90.30% 90.31% =======================================
Files 760 760 Lines 248526 248521 -5 Branches 46886 46896 +10 =======================================
+ Hits 224439 224445 +6 + Misses 15515 15502 -13 - Partials 8572 8574 +2 
Files with missing linesCoverage Δ
lib/internal/ffi/fast-api.js95.54% <ø> (+0.76%)⬆️

... and 28 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
MILLERMARRU

This comment was marked as low quality.

@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from a88fe4c to 8f76513CompareAugust 9, 2026 23:22

@mcollinamcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

@trivikrtrivikr added the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 10, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 10, 2026
@nodejs-github-bot

This comment was marked as outdated.

@trivikrtrivikr added request-ci Add this label to start a Jenkins CI on a PR. needs-ci PRs that need a full CI run. and removed needs-ci PRs that need a full CI run. request-ci Add this label to start a Jenkins CI on a PR. labels Aug 10, 2026
@nodejs-github-bot

This comment was marked as resolved.

@trivikr

Copy link
Copy Markdown
MemberAuthor

Converted to draft as test-ffi-fast-buffer is failing on ci.nodejs.org/job/node-test-commit-aix/64314

---duration_ms: 1355.201exitcode: 1severity: failstack: |- Test failure: 'fast FFI refreshes cached temporary string buffers' Location: test/ffi/test-ffi-fast-buffer.js:99:1 AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: '' !== 'yello' at TestContext.<anonymous> (/home/iojs/build/workspace/node-test-commit-aix/nodes/aix72-power9/test/ffi/test-ffi-fast-buffer.js:108:12) at Test.runInAsyncScope (node:async_hooks:227:14) at Test.run (node:internal/test_runner/test:1397:25) at Test.processPendingSubtests (node:internal/test_runner/test:969:18) at Test.postRun (node:internal/test_runner/test:1537:19) at Test.run (node:internal/test_runner/test:1462:12) at process.processTicksAndRejections (node:internal/process/task_queues:104:5) at async Test.processPendingSubtests (node:internal/test_runner/test:969:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: '', expected: 'yello', operator: 'strictEqual', diff: 'simple' } (node:38469944) internal/test/binding: These APIs are for internal testing only. Do not use them. (Use `node --trace-warnings ...` to show where the warning was created) (node:38469944) ExperimentalWarning: FFI is an experimental feature and might change at any time...

@trivikr
trivikr marked this pull request as draft August 10, 2026 20:51
@trivikr
trivikr marked this pull request as ready for review August 11, 2026 01:43
@trivikr

Copy link
Copy Markdown
MemberAuthor

There was a bug in test.

AIX does not support Node’s PPC64 fast-call trampoline, so it exposes the test’s invalid assumption: the pointer returned by overwrite_string() points into temporary storage owned by Node’s generic FFI invocation. That storage is only valid during the native call. AIX frees/reuses the storage immediately, yielding ''.

Fast-path platforms retain the cached Buffer, so "yello" remains readable.

It was fixed in 89cc17f by observing the mutation during the native call instead of returning a pointer to temporary storage.

I'll re-request review after the CI is successful.

Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from 89cc17f to d225103CompareAugust 11, 2026 01:46
@trivikrtrivikr removed the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 11, 2026
@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from d225103 to 8ef6d08CompareAugust 11, 2026 01:52
@trivikr

Copy link
Copy Markdown
MemberAuthor

The ffi contract explicitly says JavaScript strings are copied to temporary NUL-terminated UTF-8 storage “for the duration of the call”

string values are copied to temporary NUL-terminated UTF-8 strings for the duration of the call.

The fast path happens to retain reusable buffers longer, but that is an implementation detail, not a lifetime guarantee.
The test should return the observed byte by value as done in 8ef6d08 and not the pointer.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@trivikr

Copy link
Copy Markdown
MemberAuthor

@mcollina@jasnell One of the tests was incorrect, and it surfaced in CI failures in AIX.
It's fixed now in 8ef6d08 and CI is successful.

Can you please provide your approval again?

@trivikrtrivikr added commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue PRs queued for automated landing through the Commit Queue. labels Aug 14, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 54ac460 into nodejs:mainAug 14, 2026
71 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 54ac460

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 14, 2026
@trivikr
trivikr deleted the ffi-temp-string-buffer-reuse branch August 16, 2026 16:01
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: #65051Fixes: #65050
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: #65051Fixes: #65050
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commit-queue-squashPRs the Commit Queue should land as one squashed commit.ffiIssues and PRs related to experimental Foreign Function Interface support.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ffi reuses mutated temporary string buffer without restoring its contents

5 participants

@trivikr@nodejs-github-bot@mcollina@jasnell@MILLERMARRU
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ffi: refresh cached string buffers on every call - #65051

Merged
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
trivikr:ffi-temp-string-buffer-reuse
Aug 14, 2026
Merged

ffi: refresh cached string buffers on every call#65051
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
trivikr:ffi-temp-string-buffer-reuse

Conversation

@trivikr

Copy link
Copy Markdown
Member

Fixes: #65050

Native code can mutate temporary string storage during an FFI call. Rewrite cached buffers on every conversion so a later call with the same JavaScript string receives a fresh copy of its UTF-8 bytes.


Assisted-by: codex:gpt-5.6-sol

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/ffi

@nodejs-github-botnodejs-github-bot added ffi Issues and PRs related to experimental Foreign Function Interface support. needs-ci PRs that need a full CI run. labels Aug 5, 2026
@codecov

codecovBot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.31%. Comparing base (a576f1c) to head (8ef6d08).
⚠️ Report is 51 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #65051 +/- ##
=======================================
Coverage 90.30% 90.31% =======================================
Files 760 760 Lines 248526 248521 -5 Branches 46886 46896 +10 =======================================
+ Hits 224439 224445 +6 + Misses 15515 15502 -13 - Partials 8572 8574 +2 
Files with missing linesCoverage Δ
lib/internal/ffi/fast-api.js95.54% <ø> (+0.76%)⬆️

... and 28 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
MILLERMARRU

This comment was marked as low quality.

@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from a88fe4c to 8f76513CompareAugust 9, 2026 23:22

@mcollinamcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

@trivikrtrivikr added the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 10, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 10, 2026
@nodejs-github-bot

This comment was marked as outdated.

@trivikrtrivikr added request-ci Add this label to start a Jenkins CI on a PR. needs-ci PRs that need a full CI run. and removed needs-ci PRs that need a full CI run. request-ci Add this label to start a Jenkins CI on a PR. labels Aug 10, 2026
@nodejs-github-bot

This comment was marked as resolved.

@trivikr

Copy link
Copy Markdown
MemberAuthor

Converted to draft as test-ffi-fast-buffer is failing on ci.nodejs.org/job/node-test-commit-aix/64314

---duration_ms: 1355.201exitcode: 1severity: failstack: |- Test failure: 'fast FFI refreshes cached temporary string buffers' Location: test/ffi/test-ffi-fast-buffer.js:99:1 AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: '' !== 'yello' at TestContext.<anonymous> (/home/iojs/build/workspace/node-test-commit-aix/nodes/aix72-power9/test/ffi/test-ffi-fast-buffer.js:108:12) at Test.runInAsyncScope (node:async_hooks:227:14) at Test.run (node:internal/test_runner/test:1397:25) at Test.processPendingSubtests (node:internal/test_runner/test:969:18) at Test.postRun (node:internal/test_runner/test:1537:19) at Test.run (node:internal/test_runner/test:1462:12) at process.processTicksAndRejections (node:internal/process/task_queues:104:5) at async Test.processPendingSubtests (node:internal/test_runner/test:969:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: '', expected: 'yello', operator: 'strictEqual', diff: 'simple' } (node:38469944) internal/test/binding: These APIs are for internal testing only. Do not use them. (Use `node --trace-warnings ...` to show where the warning was created) (node:38469944) ExperimentalWarning: FFI is an experimental feature and might change at any time...

@trivikr
trivikr marked this pull request as draft August 10, 2026 20:51
@trivikr
trivikr marked this pull request as ready for review August 11, 2026 01:43
@trivikr

Copy link
Copy Markdown
MemberAuthor

There was a bug in test.

AIX does not support Node’s PPC64 fast-call trampoline, so it exposes the test’s invalid assumption: the pointer returned by overwrite_string() points into temporary storage owned by Node’s generic FFI invocation. That storage is only valid during the native call. AIX frees/reuses the storage immediately, yielding ''.

Fast-path platforms retain the cached Buffer, so "yello" remains readable.

It was fixed in 89cc17f by observing the mutation during the native call instead of returning a pointer to temporary storage.

I'll re-request review after the CI is successful.

Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from 89cc17f to d225103CompareAugust 11, 2026 01:46
@trivikrtrivikr removed the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 11, 2026
@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from d225103 to 8ef6d08CompareAugust 11, 2026 01:52
@trivikr

Copy link
Copy Markdown
MemberAuthor

The ffi contract explicitly says JavaScript strings are copied to temporary NUL-terminated UTF-8 storage “for the duration of the call”

string values are copied to temporary NUL-terminated UTF-8 strings for the duration of the call.

The fast path happens to retain reusable buffers longer, but that is an implementation detail, not a lifetime guarantee.
The test should return the observed byte by value as done in 8ef6d08 and not the pointer.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@trivikr

Copy link
Copy Markdown
MemberAuthor

@mcollina@jasnell One of the tests was incorrect, and it surfaced in CI failures in AIX.
It's fixed now in 8ef6d08 and CI is successful.

Can you please provide your approval again?

@trivikrtrivikr added commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue PRs queued for automated landing through the Commit Queue. labels Aug 14, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 54ac460 into nodejs:mainAug 14, 2026
71 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 54ac460

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 14, 2026
@trivikr
trivikr deleted the ffi-temp-string-buffer-reuse branch August 16, 2026 16:01
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: #65051Fixes: #65050
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: #65051Fixes: #65050
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commit-queue-squashPRs the Commit Queue should land as one squashed commit.ffiIssues and PRs related to experimental Foreign Function Interface support.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ffi reuses mutated temporary string buffer without restoring its contents

5 participants

@trivikr@nodejs-github-bot@mcollina@jasnell@MILLERMARRU
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

ffi: refresh cached string buffers on every call - #65051

Merged
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
trivikr:ffi-temp-string-buffer-reuse
Aug 14, 2026
Merged

ffi: refresh cached string buffers on every call#65051
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
trivikr:ffi-temp-string-buffer-reuse

Conversation

@trivikr

Copy link
Copy Markdown
Member

Fixes: #65050

Native code can mutate temporary string storage during an FFI call. Rewrite cached buffers on every conversion so a later call with the same JavaScript string receives a fresh copy of its UTF-8 bytes.


Assisted-by: codex:gpt-5.6-sol

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/ffi

@nodejs-github-botnodejs-github-bot added ffi Issues and PRs related to experimental Foreign Function Interface support. needs-ci PRs that need a full CI run. labels Aug 5, 2026
@codecov

codecovBot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.31%. Comparing base (a576f1c) to head (8ef6d08).
⚠️ Report is 51 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #65051 +/- ##
=======================================
Coverage 90.30% 90.31% =======================================
Files 760 760 Lines 248526 248521 -5 Branches 46886 46896 +10 =======================================
+ Hits 224439 224445 +6 + Misses 15515 15502 -13 - Partials 8572 8574 +2 
Files with missing linesCoverage Δ
lib/internal/ffi/fast-api.js95.54% <ø> (+0.76%)⬆️

... and 28 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
MILLERMARRU

This comment was marked as low quality.

@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from a88fe4c to 8f76513CompareAugust 9, 2026 23:22

@mcollinamcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

@trivikrtrivikr added the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 10, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 10, 2026
@nodejs-github-bot

This comment was marked as outdated.

@trivikrtrivikr added request-ci Add this label to start a Jenkins CI on a PR. needs-ci PRs that need a full CI run. and removed needs-ci PRs that need a full CI run. request-ci Add this label to start a Jenkins CI on a PR. labels Aug 10, 2026
@nodejs-github-bot

This comment was marked as resolved.

@trivikr

Copy link
Copy Markdown
MemberAuthor

Converted to draft as test-ffi-fast-buffer is failing on ci.nodejs.org/job/node-test-commit-aix/64314

---duration_ms: 1355.201exitcode: 1severity: failstack: |- Test failure: 'fast FFI refreshes cached temporary string buffers' Location: test/ffi/test-ffi-fast-buffer.js:99:1 AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: '' !== 'yello' at TestContext.<anonymous> (/home/iojs/build/workspace/node-test-commit-aix/nodes/aix72-power9/test/ffi/test-ffi-fast-buffer.js:108:12) at Test.runInAsyncScope (node:async_hooks:227:14) at Test.run (node:internal/test_runner/test:1397:25) at Test.processPendingSubtests (node:internal/test_runner/test:969:18) at Test.postRun (node:internal/test_runner/test:1537:19) at Test.run (node:internal/test_runner/test:1462:12) at process.processTicksAndRejections (node:internal/process/task_queues:104:5) at async Test.processPendingSubtests (node:internal/test_runner/test:969:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: '', expected: 'yello', operator: 'strictEqual', diff: 'simple' } (node:38469944) internal/test/binding: These APIs are for internal testing only. Do not use them. (Use `node --trace-warnings ...` to show where the warning was created) (node:38469944) ExperimentalWarning: FFI is an experimental feature and might change at any time...

@trivikr
trivikr marked this pull request as draft August 10, 2026 20:51
@trivikr
trivikr marked this pull request as ready for review August 11, 2026 01:43
@trivikr

Copy link
Copy Markdown
MemberAuthor

There was a bug in test.

AIX does not support Node’s PPC64 fast-call trampoline, so it exposes the test’s invalid assumption: the pointer returned by overwrite_string() points into temporary storage owned by Node’s generic FFI invocation. That storage is only valid during the native call. AIX frees/reuses the storage immediately, yielding ''.

Fast-path platforms retain the cached Buffer, so "yello" remains readable.

It was fixed in 89cc17f by observing the mutation during the native call instead of returning a pointer to temporary storage.

I'll re-request review after the CI is successful.

Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from 89cc17f to d225103CompareAugust 11, 2026 01:46
@trivikrtrivikr removed the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 11, 2026
@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from d225103 to 8ef6d08CompareAugust 11, 2026 01:52
@trivikr

Copy link
Copy Markdown
MemberAuthor

The ffi contract explicitly says JavaScript strings are copied to temporary NUL-terminated UTF-8 storage “for the duration of the call”

string values are copied to temporary NUL-terminated UTF-8 strings for the duration of the call.

The fast path happens to retain reusable buffers longer, but that is an implementation detail, not a lifetime guarantee.
The test should return the observed byte by value as done in 8ef6d08 and not the pointer.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@trivikr

Copy link
Copy Markdown
MemberAuthor

@mcollina@jasnell One of the tests was incorrect, and it surfaced in CI failures in AIX.
It's fixed now in 8ef6d08 and CI is successful.

Can you please provide your approval again?

@trivikrtrivikr added commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue PRs queued for automated landing through the Commit Queue. labels Aug 14, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 54ac460 into nodejs:mainAug 14, 2026
71 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 54ac460

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 14, 2026
@trivikr
trivikr deleted the ffi-temp-string-buffer-reuse branch August 16, 2026 16:01
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: #65051Fixes: #65050
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: #65051Fixes: #65050
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commit-queue-squashPRs the Commit Queue should land as one squashed commit.ffiIssues and PRs related to experimental Foreign Function Interface support.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ffi reuses mutated temporary string buffer without restoring its contents

5 participants

@trivikr@nodejs-github-bot@mcollina@jasnell@MILLERMARRU
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ffi: refresh cached string buffers on every call - #65051

Merged
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
trivikr:ffi-temp-string-buffer-reuse
Aug 14, 2026
Merged

ffi: refresh cached string buffers on every call#65051
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
trivikr:ffi-temp-string-buffer-reuse

Conversation

@trivikr

Copy link
Copy Markdown
Member

Fixes: #65050

Native code can mutate temporary string storage during an FFI call. Rewrite cached buffers on every conversion so a later call with the same JavaScript string receives a fresh copy of its UTF-8 bytes.


Assisted-by: codex:gpt-5.6-sol

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/ffi

@nodejs-github-botnodejs-github-bot added ffi Issues and PRs related to experimental Foreign Function Interface support. needs-ci PRs that need a full CI run. labels Aug 5, 2026
@codecov

codecovBot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.31%. Comparing base (a576f1c) to head (8ef6d08).
⚠️ Report is 51 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #65051 +/- ##
=======================================
Coverage 90.30% 90.31% =======================================
Files 760 760 Lines 248526 248521 -5 Branches 46886 46896 +10 =======================================
+ Hits 224439 224445 +6 + Misses 15515 15502 -13 - Partials 8572 8574 +2 
Files with missing linesCoverage Δ
lib/internal/ffi/fast-api.js95.54% <ø> (+0.76%)⬆️

... and 28 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
MILLERMARRU

This comment was marked as low quality.

@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from a88fe4c to 8f76513CompareAugust 9, 2026 23:22

@mcollinamcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

@trivikrtrivikr added the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 10, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 10, 2026
@nodejs-github-bot

This comment was marked as outdated.

@trivikrtrivikr added request-ci Add this label to start a Jenkins CI on a PR. needs-ci PRs that need a full CI run. and removed needs-ci PRs that need a full CI run. request-ci Add this label to start a Jenkins CI on a PR. labels Aug 10, 2026
@nodejs-github-bot

This comment was marked as resolved.

@trivikr

Copy link
Copy Markdown
MemberAuthor

Converted to draft as test-ffi-fast-buffer is failing on ci.nodejs.org/job/node-test-commit-aix/64314

---duration_ms: 1355.201exitcode: 1severity: failstack: |- Test failure: 'fast FFI refreshes cached temporary string buffers' Location: test/ffi/test-ffi-fast-buffer.js:99:1 AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: '' !== 'yello' at TestContext.<anonymous> (/home/iojs/build/workspace/node-test-commit-aix/nodes/aix72-power9/test/ffi/test-ffi-fast-buffer.js:108:12) at Test.runInAsyncScope (node:async_hooks:227:14) at Test.run (node:internal/test_runner/test:1397:25) at Test.processPendingSubtests (node:internal/test_runner/test:969:18) at Test.postRun (node:internal/test_runner/test:1537:19) at Test.run (node:internal/test_runner/test:1462:12) at process.processTicksAndRejections (node:internal/process/task_queues:104:5) at async Test.processPendingSubtests (node:internal/test_runner/test:969:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: '', expected: 'yello', operator: 'strictEqual', diff: 'simple' } (node:38469944) internal/test/binding: These APIs are for internal testing only. Do not use them. (Use `node --trace-warnings ...` to show where the warning was created) (node:38469944) ExperimentalWarning: FFI is an experimental feature and might change at any time...

@trivikr
trivikr marked this pull request as draft August 10, 2026 20:51
@trivikr
trivikr marked this pull request as ready for review August 11, 2026 01:43
@trivikr

Copy link
Copy Markdown
MemberAuthor

There was a bug in test.

AIX does not support Node’s PPC64 fast-call trampoline, so it exposes the test’s invalid assumption: the pointer returned by overwrite_string() points into temporary storage owned by Node’s generic FFI invocation. That storage is only valid during the native call. AIX frees/reuses the storage immediately, yielding ''.

Fast-path platforms retain the cached Buffer, so "yello" remains readable.

It was fixed in 89cc17f by observing the mutation during the native call instead of returning a pointer to temporary storage.

I'll re-request review after the CI is successful.

Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from 89cc17f to d225103CompareAugust 11, 2026 01:46
@trivikrtrivikr removed the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 11, 2026
@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from d225103 to 8ef6d08CompareAugust 11, 2026 01:52
@trivikr

Copy link
Copy Markdown
MemberAuthor

The ffi contract explicitly says JavaScript strings are copied to temporary NUL-terminated UTF-8 storage “for the duration of the call”

string values are copied to temporary NUL-terminated UTF-8 strings for the duration of the call.

The fast path happens to retain reusable buffers longer, but that is an implementation detail, not a lifetime guarantee.
The test should return the observed byte by value as done in 8ef6d08 and not the pointer.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@trivikr

Copy link
Copy Markdown
MemberAuthor

@mcollina@jasnell One of the tests was incorrect, and it surfaced in CI failures in AIX.
It's fixed now in 8ef6d08 and CI is successful.

Can you please provide your approval again?

@trivikrtrivikr added commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue PRs queued for automated landing through the Commit Queue. labels Aug 14, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 54ac460 into nodejs:mainAug 14, 2026
71 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 54ac460

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 14, 2026
@trivikr
trivikr deleted the ffi-temp-string-buffer-reuse branch August 16, 2026 16:01
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: #65051Fixes: #65050
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: #65051Fixes: #65050
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commit-queue-squashPRs the Commit Queue should land as one squashed commit.ffiIssues and PRs related to experimental Foreign Function Interface support.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ffi reuses mutated temporary string buffer without restoring its contents

5 participants

@trivikr@nodejs-github-bot@mcollina@jasnell@MILLERMARRU
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ffi: refresh cached string buffers on every call - #65051

Merged
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
trivikr:ffi-temp-string-buffer-reuse
Aug 14, 2026
Merged

ffi: refresh cached string buffers on every call#65051
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
trivikr:ffi-temp-string-buffer-reuse

Conversation

@trivikr

Copy link
Copy Markdown
Member

Fixes: #65050

Native code can mutate temporary string storage during an FFI call. Rewrite cached buffers on every conversion so a later call with the same JavaScript string receives a fresh copy of its UTF-8 bytes.


Assisted-by: codex:gpt-5.6-sol

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/ffi

@nodejs-github-botnodejs-github-bot added ffi Issues and PRs related to experimental Foreign Function Interface support. needs-ci PRs that need a full CI run. labels Aug 5, 2026
@codecov

codecovBot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.31%. Comparing base (a576f1c) to head (8ef6d08).
⚠️ Report is 51 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #65051 +/- ##
=======================================
Coverage 90.30% 90.31% =======================================
Files 760 760 Lines 248526 248521 -5 Branches 46886 46896 +10 =======================================
+ Hits 224439 224445 +6 + Misses 15515 15502 -13 - Partials 8572 8574 +2 
Files with missing linesCoverage Δ
lib/internal/ffi/fast-api.js95.54% <ø> (+0.76%)⬆️

... and 28 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
MILLERMARRU

This comment was marked as low quality.

@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from a88fe4c to 8f76513CompareAugust 9, 2026 23:22

@mcollinamcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

@trivikrtrivikr added the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 10, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 10, 2026
@nodejs-github-bot

This comment was marked as outdated.

@trivikrtrivikr added request-ci Add this label to start a Jenkins CI on a PR. needs-ci PRs that need a full CI run. and removed needs-ci PRs that need a full CI run. request-ci Add this label to start a Jenkins CI on a PR. labels Aug 10, 2026
@nodejs-github-bot

This comment was marked as resolved.

@trivikr

Copy link
Copy Markdown
MemberAuthor

Converted to draft as test-ffi-fast-buffer is failing on ci.nodejs.org/job/node-test-commit-aix/64314

---duration_ms: 1355.201exitcode: 1severity: failstack: |- Test failure: 'fast FFI refreshes cached temporary string buffers' Location: test/ffi/test-ffi-fast-buffer.js:99:1 AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: '' !== 'yello' at TestContext.<anonymous> (/home/iojs/build/workspace/node-test-commit-aix/nodes/aix72-power9/test/ffi/test-ffi-fast-buffer.js:108:12) at Test.runInAsyncScope (node:async_hooks:227:14) at Test.run (node:internal/test_runner/test:1397:25) at Test.processPendingSubtests (node:internal/test_runner/test:969:18) at Test.postRun (node:internal/test_runner/test:1537:19) at Test.run (node:internal/test_runner/test:1462:12) at process.processTicksAndRejections (node:internal/process/task_queues:104:5) at async Test.processPendingSubtests (node:internal/test_runner/test:969:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: '', expected: 'yello', operator: 'strictEqual', diff: 'simple' } (node:38469944) internal/test/binding: These APIs are for internal testing only. Do not use them. (Use `node --trace-warnings ...` to show where the warning was created) (node:38469944) ExperimentalWarning: FFI is an experimental feature and might change at any time...

@trivikr
trivikr marked this pull request as draft August 10, 2026 20:51
@trivikr
trivikr marked this pull request as ready for review August 11, 2026 01:43
@trivikr

Copy link
Copy Markdown
MemberAuthor

There was a bug in test.

AIX does not support Node’s PPC64 fast-call trampoline, so it exposes the test’s invalid assumption: the pointer returned by overwrite_string() points into temporary storage owned by Node’s generic FFI invocation. That storage is only valid during the native call. AIX frees/reuses the storage immediately, yielding ''.

Fast-path platforms retain the cached Buffer, so "yello" remains readable.

It was fixed in 89cc17f by observing the mutation during the native call instead of returning a pointer to temporary storage.

I'll re-request review after the CI is successful.

Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from 89cc17f to d225103CompareAugust 11, 2026 01:46
@trivikrtrivikr removed the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 11, 2026
@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from d225103 to 8ef6d08CompareAugust 11, 2026 01:52
@trivikr

Copy link
Copy Markdown
MemberAuthor

The ffi contract explicitly says JavaScript strings are copied to temporary NUL-terminated UTF-8 storage “for the duration of the call”

string values are copied to temporary NUL-terminated UTF-8 strings for the duration of the call.

The fast path happens to retain reusable buffers longer, but that is an implementation detail, not a lifetime guarantee.
The test should return the observed byte by value as done in 8ef6d08 and not the pointer.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@trivikr

Copy link
Copy Markdown
MemberAuthor

@mcollina@jasnell One of the tests was incorrect, and it surfaced in CI failures in AIX.
It's fixed now in 8ef6d08 and CI is successful.

Can you please provide your approval again?

@trivikrtrivikr added commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue PRs queued for automated landing through the Commit Queue. labels Aug 14, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 54ac460 into nodejs:mainAug 14, 2026
71 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 54ac460

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 14, 2026
@trivikr
trivikr deleted the ffi-temp-string-buffer-reuse branch August 16, 2026 16:01
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: #65051Fixes: #65050
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: #65051Fixes: #65050
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commit-queue-squashPRs the Commit Queue should land as one squashed commit.ffiIssues and PRs related to experimental Foreign Function Interface support.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ffi reuses mutated temporary string buffer without restoring its contents

5 participants

@trivikr@nodejs-github-bot@mcollina@jasnell@MILLERMARRU
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

ffi: refresh cached string buffers on every call - #65051

Merged
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
trivikr:ffi-temp-string-buffer-reuse
Aug 14, 2026
Merged

ffi: refresh cached string buffers on every call#65051
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
trivikr:ffi-temp-string-buffer-reuse

Conversation

@trivikr

Copy link
Copy Markdown
Member

Fixes: #65050

Native code can mutate temporary string storage during an FFI call. Rewrite cached buffers on every conversion so a later call with the same JavaScript string receives a fresh copy of its UTF-8 bytes.


Assisted-by: codex:gpt-5.6-sol

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/ffi

@nodejs-github-botnodejs-github-bot added ffi Issues and PRs related to experimental Foreign Function Interface support. needs-ci PRs that need a full CI run. labels Aug 5, 2026
@codecov

codecovBot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.31%. Comparing base (a576f1c) to head (8ef6d08).
⚠️ Report is 51 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #65051 +/- ##
=======================================
Coverage 90.30% 90.31% =======================================
Files 760 760 Lines 248526 248521 -5 Branches 46886 46896 +10 =======================================
+ Hits 224439 224445 +6 + Misses 15515 15502 -13 - Partials 8572 8574 +2 
Files with missing linesCoverage Δ
lib/internal/ffi/fast-api.js95.54% <ø> (+0.76%)⬆️

... and 28 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
MILLERMARRU

This comment was marked as low quality.

@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from a88fe4c to 8f76513CompareAugust 9, 2026 23:22

@mcollinamcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

@trivikrtrivikr added the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 10, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 10, 2026
@nodejs-github-bot

This comment was marked as outdated.

@trivikrtrivikr added request-ci Add this label to start a Jenkins CI on a PR. needs-ci PRs that need a full CI run. and removed needs-ci PRs that need a full CI run. request-ci Add this label to start a Jenkins CI on a PR. labels Aug 10, 2026
@nodejs-github-bot

This comment was marked as resolved.

@trivikr

Copy link
Copy Markdown
MemberAuthor

Converted to draft as test-ffi-fast-buffer is failing on ci.nodejs.org/job/node-test-commit-aix/64314

---duration_ms: 1355.201exitcode: 1severity: failstack: |- Test failure: 'fast FFI refreshes cached temporary string buffers' Location: test/ffi/test-ffi-fast-buffer.js:99:1 AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: '' !== 'yello' at TestContext.<anonymous> (/home/iojs/build/workspace/node-test-commit-aix/nodes/aix72-power9/test/ffi/test-ffi-fast-buffer.js:108:12) at Test.runInAsyncScope (node:async_hooks:227:14) at Test.run (node:internal/test_runner/test:1397:25) at Test.processPendingSubtests (node:internal/test_runner/test:969:18) at Test.postRun (node:internal/test_runner/test:1537:19) at Test.run (node:internal/test_runner/test:1462:12) at process.processTicksAndRejections (node:internal/process/task_queues:104:5) at async Test.processPendingSubtests (node:internal/test_runner/test:969:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: '', expected: 'yello', operator: 'strictEqual', diff: 'simple' } (node:38469944) internal/test/binding: These APIs are for internal testing only. Do not use them. (Use `node --trace-warnings ...` to show where the warning was created) (node:38469944) ExperimentalWarning: FFI is an experimental feature and might change at any time...

@trivikr
trivikr marked this pull request as draft August 10, 2026 20:51
@trivikr
trivikr marked this pull request as ready for review August 11, 2026 01:43
@trivikr

Copy link
Copy Markdown
MemberAuthor

There was a bug in test.

AIX does not support Node’s PPC64 fast-call trampoline, so it exposes the test’s invalid assumption: the pointer returned by overwrite_string() points into temporary storage owned by Node’s generic FFI invocation. That storage is only valid during the native call. AIX frees/reuses the storage immediately, yielding ''.

Fast-path platforms retain the cached Buffer, so "yello" remains readable.

It was fixed in 89cc17f by observing the mutation during the native call instead of returning a pointer to temporary storage.

I'll re-request review after the CI is successful.

Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from 89cc17f to d225103CompareAugust 11, 2026 01:46
@trivikrtrivikr removed the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 11, 2026
@trivikr
trivikrforce-pushed the ffi-temp-string-buffer-reuse branch from d225103 to 8ef6d08CompareAugust 11, 2026 01:52
@trivikr

Copy link
Copy Markdown
MemberAuthor

The ffi contract explicitly says JavaScript strings are copied to temporary NUL-terminated UTF-8 storage “for the duration of the call”

string values are copied to temporary NUL-terminated UTF-8 strings for the duration of the call.

The fast path happens to retain reusable buffers longer, but that is an implementation detail, not a lifetime guarantee.
The test should return the observed byte by value as done in 8ef6d08 and not the pointer.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@trivikr

Copy link
Copy Markdown
MemberAuthor

@mcollina@jasnell One of the tests was incorrect, and it surfaced in CI failures in AIX.
It's fixed now in 8ef6d08 and CI is successful.

Can you please provide your approval again?

@trivikrtrivikr added commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue PRs queued for automated landing through the Commit Queue. labels Aug 14, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 54ac460 into nodejs:mainAug 14, 2026
71 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 54ac460

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 14, 2026
@trivikr
trivikr deleted the ffi-temp-string-buffer-reuse branch August 16, 2026 16:01
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: #65051Fixes: #65050
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Native code can mutate temporary string storage during an FFI call.
Rewrite cached buffers on every conversion so a later call with the
same JavaScript string receives a fresh copy of its UTF-8 bytes.
Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: #65051Fixes: #65050
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commit-queue-squashPRs the Commit Queue should land as one squashed commit.ffiIssues and PRs related to experimental Foreign Function Interface support.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ffi reuses mutated temporary string buffer without restoring its contents

5 participants

@trivikr@nodejs-github-bot@mcollina@jasnell@MILLERMARRU