Medium chrome Logic Error 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in V8
DescriptionInappropriate implementation in V8
ComponentV8
Bug ClassLogic Error
Tracker513586956
Fix commita769cf1ffbec (v8/v8) +95/-39
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-30

Changed Functions

FunctionChangeNotes
if
src/codegen/arm64/macro-assembler-arm64.cc
modified

Files Changed

  • src/codegen/arm64/assembler-arm64.cc
  • src/codegen/arm64/constants-arm64.h
  • src/codegen/arm64/macro-assembler-arm64.cc
  • src/codegen/arm64/reglist-arm64.h
  • src/compiler/backend/arm64/code-generator-arm64.cc
From a769cf1ffbec4beb7d8a3f8a6e72a425cb08f3cc Mon Sep 17 00:00:00 2001
From: Igor Sheludko <[email protected]>
Date: Wed, 27 May 2026 11:11:29 +0200
Subject: [PATCH] [arm64] Split Callee/CallerSaved FP register lists into D and V lists

... representing double and quad (128-bit SIMD) FP registers.

This CL makes sure that SIMD registers are not corrupted by a call to
C++ code by unconditionally saving/restoring them when Wasm support is
enabled.

TAG=agy

Fixed: 513586956
Change-Id: I45d656a5851db72ca20bb98c0b9d25d4c00f4d36
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7876383
Commit-Queue: Igor Sheludko <[email protected]>
Commit-Queue: Nico Hartmann <[email protected]>
Auto-Submit: Igor Sheludko <[email protected]>
Reviewed-by: Nico Hartmann <[email protected]>
Cr-Commit-Position: refs/heads/main@{#107584}
---

diff --git a/src/codegen/arm64/assembler-arm64.cc b/src/codegen/arm64/assembler-arm64.cc
index bbfb671..f3309d3 100644
--- a/src/codegen/arm64/assembler-arm64.cc
+++ b/src/codegen/arm64/assembler-arm64.cc
@@ -232,28 +232,41 @@
   DCHECK_EQ(Count() % 2, 0);
 }
 
-CPURegList CPURegList::GetCalleeSaved(int size) {
-  return CPURegList(CPURegister::kRegister, size, 19, 28);
+CPURegList CPURegList::GetCalleeSaved() {
+  return CPURegList(CPURegister::kRegister, kXRegSizeInBits, 19, 28);
 }
 
-CPURegList CPURegList::GetCalleeSavedV(int size) {
-  return CPURegList(CPURegister::kVRegister, size, 8, 15);
+CPURegList CPURegList::GetCalleeSavedD() {
+  // AAPCS64 only requires the callee to preserve d8-d15 which are the
+  // *lower* 64 bits of v8-v15.
+  return CPURegList(CPURegister::kVRegister, kDRegSizeInBits, 8, 15);
 }
 
-CPURegList CPURegList::GetCallerSaved(int size) {
+CPURegList CPURegList::GetCalleeSavedV() {
+  return CPURegList(kQRegSizeInBits, Simd128RegList{});
+}
+
+CPURegList CPURegList::GetCallerSaved() {
   // x18 is the platform register and is reserved for the use of platform ABIs.
   // Registers x0-x17 are caller-saved.
-  CPURegList list = CPURegList(CPURegister::kRegister, size, 0, 17);
+  CPURegList list = CPURegList(CPURegister::kRegister, kXRegSizeInBits, 0, 17);
   return list;
 }
 
-CPURegList CPURegList::GetCallerSavedV(int size) {
+CPURegList CPURegList::GetCallerSavedD() {
   // Registers d0-d7 and d16-d31 are caller-saved.
-  CPURegList list = CPURegList(CPURegister::kVRegister, size, 0, 7);
-  list.Combine(CPURegList(CPURegister::kVRegister, size, 16, 31));
+  CPURegList list = CPURegList(CPURegister::kVRegister, kDRegSizeInBits, 0, 7);
+  list.Combine(CPURegList(CPURegister::kVRegister, kDRegSizeInBits, 16, 31));
   return list;
 }
 
+CPURegList CPURegList::GetCallerSavedV() {
+  // AAPCS64 only requires the callee to preserve the *lower* 64 bits of v8-v15
+  // (which are essentially the d8-d15 registers), thus all V registers are
+  // caller-saved.
+  return CPURegList(CPURegister::kVRegister, kQRegSizeInBits, 0, 31);
+}
+
 // -----------------------------------------------------------------------------
 // Implementation of RelocInfo
 
diff --git a/src/codegen/arm64/constants-arm64.h b/src/codegen/arm64/constants-arm64.h
index ed9531d..6417831 100644
--- a/src/codegen/arm64/constants-arm64.h
+++ b/src/codegen/arm64/constants-arm64.h
@@ -44,7 +44,11 @@
 // Callee saved registers are x19-x28.
 constexpr int kNumberOfCalleeSavedRegisters = 10;
 // Callee saved FP registers are d8-d15.
-constexpr int kNumberOfCalleeSavedVRegisters = 8;
+constexpr int kNumberOfCalleeSavedDRegisters = 8;
+// AAPCS64 only requires the callee to preserve the *lower* 64 bits of v8-v15
+// (which are essentially the d8-d15 registers), thus none of the 128-bit
+// V registers are callee-saved.
+constexpr int kNumberOfCalleeSavedVRegisters = 0;
 constexpr int kWRegSizeInBits = 32;
 constexpr int kWRegSizeInBitsLog2 = 5;
 constexpr int kWRegSize = kWRegSizeInBits >> 3;
diff --git a/src/codegen/arm64/macro-assembler-arm64.cc b/src/codegen/arm64/macro-assembler-arm64.cc
index 398aa35..9d4ae75 100644
--- a/src/codegen/arm64/macro-assembler-arm64.cc
+++ b/src/codegen/arm64/macro-assembler-arm64.cc
@@ -49,9 +49,9 @@
 // For WebAssembly we care about the full floating point register. If we are not
 // running Wasm, we can get away with saving half of those registers.
 #if V8_ENABLE_WEBASSEMBLY
-constexpr int kStackSavedSavedFPSizeInBits = kQRegSizeInBits;
+constexpr bool kSaveFullFPRegistersOnStack = true;
 #else
-constexpr int kStackSavedSavedFPSizeInBits = kDRegSizeInBits;
+constexpr bool kSaveFullFPRegistersOnStack = false;
 #endif  // V8_ENABLE_WEBASSEMBLY
 
 }  // namespace
@@ -147,7 +147,11 @@
   int bytes = list.TotalSizeInBytes();
 
   if (fp_mode == SaveFPRegsMode::kSave) {
-    auto fp_list = CPURegList::GetCallerSavedV(kStackSavedSavedFPSizeInBits);
+    // TODO(all): consider splitting SaveFPRegsMode::kSave into kSaveFPOnly
+    // and kSaveFPAndSIMD. The former is useful for those functions that don't
+    // use SIMD registers.
+    auto fp_list = kSaveFullFPRegistersOnStack ? CPURegList::GetCallerSavedV()
+                                               : CPURegList::GetCallerSavedD();
     DCHECK_EQ(fp_list.Count() % 2, 0);
     bytes += fp_list.TotalSizeInBytes();
   }
@@ -166,7 +170,11 @@
   int bytes = list.TotalSizeInBytes();
 
   if (fp_mode == SaveFPRegsMode::kSave) {
-    auto fp_list = CPURegList::GetCallerSavedV(kStackSavedSavedFPSizeInBits);
+    // TODO(all): consider splitting SaveFPRegsMode::kSave into kSaveFPOnly
+    // and kSaveFPAndSIMD. The former is useful for those functions that don't
+    // use SIMD registers.
+    auto fp_list = kSaveFullFPRegistersOnStack ? CPURegList::GetCallerSavedV()
+                                               : CPURegList::GetCallerSavedD();
     DCHECK_EQ(fp_list.Count() % 2, 0);
     PushCPURegList(fp_list);
     bytes += fp_list.TotalSizeInBytes();
@@ -178,7 +186,11 @@
   ASM_CODE_COMMENT(this);
   int bytes = 0;
   if (fp_mode == SaveFPRegsMode::kSave) {
-    auto fp_list = CPURegList::GetCallerSavedV(kStackSavedSavedFPSizeInBits);
+    // TODO(all): consider splitting SaveFPRegsMode::kSave into kSaveFPOnly
+    // and kSaveFPAndSIMD. The former is useful for those functions that don't
+    // use SIMD registers.
+    auto fp_list = kSaveFullFPRegistersOnStack ? CPURegList::GetCallerSavedV()
+                                               : CPURegList::GetCallerSavedD();
     DCHECK_EQ(fp_list.Count() % 2, 0);
     PopCPURegList(fp_list);
     bytes += fp_list.TotalSizeInBytes();
diff --git a/src/codegen/arm64/reglist-arm64.h b/src/codegen/arm64/reglist-arm64.h
index 64a3fb2..9af1f83 100644
--- a/src/codegen/arm64/reglist-arm64.h
+++ b/src/codegen/arm64/reglist-arm64.h
@@ -99,14 +99,19 @@
   CPURegister PopHighestIndex();
 
   // AAPCS64 callee-saved registers.
-  static CPURegList GetCalleeSaved(int size = kXRegSizeInBits);
-  static CPURegList GetCalleeSavedV(int size = kDRegSizeInBits);
+  static CPURegList GetCalleeSaved();
+  // Note that D registers are the lower 64-bit parts of respective V
+  // registers.
+  static CPURegList GetCalleeSavedD();
+  static CPURegList GetCalleeSavedV();
 
   // AAPCS64 caller-saved registers. Note that this includes lr.
-  // TODO(all): Determine how we handle d8-d15 being callee-saved, but the top
-  // 64-bits being caller-saved.
-  static CPURegList GetCallerSaved(int size = kXRegSizeInBits);
-  static CPURegList GetCallerSavedV(int size = kDRegSizeInBits);
+  static CPURegList GetCallerSaved();
+  // Note that D registers are the lower 64-bit parts of respective V
+  // registers. Thus there's no need to save both D and V registers, saving
+  // just V registers is enough.
+  static CPURegList GetCallerSavedD();
+  static CPURegList GetCallerSavedV();
 
   bool IsEmpty() const { return list_ == 0; }
 
@@ -163,10 +168,12 @@
 
 // AAPCS64 callee-saved registers.
 #define kCalleeSaved CPURegList::GetCalleeSaved()
+#define kCalleeSavedD CPURegList::GetCalleeSavedD()
 #define kCalleeSavedV CPURegList::GetCalleeSavedV()
 
 // AAPCS64 caller-saved registers. Note that this includes lr.
 #define kCallerSaved CPURegList::GetCallerSaved()
+#define kCallerSavedD CPURegList::GetCallerSavedD()
 #define kCallerSavedV CPURegList::GetCallerSavedV()
 
 }  // namespace internal
diff --git a/src/compiler/backend/arm64/code-generator-arm64.cc b/src/compiler/backend/arm64/code-generator-arm64.cc
index 3354b5e..4c750a6 100644
--- a/src/compiler/backend/arm64/code-generator-arm64.cc
+++ b/src/compiler/backend/arm64/code-generator-arm64.cc
@@ -4255,7 +4255,9 @@
       CPURegList(kDRegSizeInBits, call_descriptor->CalleeSavedFPRegisters());
   int saved_count = saves_fp.Count();
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.