From f7ddcd2795ee5997d3ee9ab2cbfdb11385e9802d Mon Sep 17 00:00:00 2001 From: Shahar Naveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Tue, 18 Nov 2025 18:00:41 +0200 Subject: [PATCH 001/577] Break after annotation future found (#6284) --- crates/codegen/src/symboltable.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/codegen/src/symboltable.rs b/crates/codegen/src/symboltable.rs index 0464e09c13..3c8454b9e2 100644 --- a/crates/codegen/src/symboltable.rs +++ b/crates/codegen/src/symboltable.rs @@ -736,12 +736,10 @@ impl SymbolTableBuilder { if let Stmt::ImportFrom(StmtImportFrom { module, names, .. }) = &statement && module.as_ref().map(|id| id.as_str()) == Some("__future__") { - for feature in names { - if &feature.name == "annotations" { - self.future_annotations = true; - } - } + self.future_annotations = + self.future_annotations || names.iter().any(|future| &future.name == "annotations"); } + match &statement { Stmt::Global(StmtGlobal { names, .. }) => { for name in names { From 567fb4dec05fa15b73af26c1cd203039912e0437 Mon Sep 17 00:00:00 2001 From: Jiseok CHOI Date: Sat, 22 Nov 2025 20:42:24 +0900 Subject: [PATCH 002/577] fix(sqlite): raise `ProgrammingError` when operating on a blob with a closed connection, (#6286) Fixed #6285 --- Lib/test/test_sqlite3/test_dbapi.py | 2 -- crates/stdlib/src/sqlite.rs | 11 +++++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index 49c9764a1b..a2530a03e2 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -1469,8 +1469,6 @@ def test_blob_closed(self): with self.assertRaisesRegex(sqlite.ProgrammingError, msg): blob[0] = b"" - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_blob_closed_db_read(self): with memory_database() as cx: cx.execute("create table test(b blob)") diff --git a/crates/stdlib/src/sqlite.rs b/crates/stdlib/src/sqlite.rs index e19aca1f6d..b875c60944 100644 --- a/crates/stdlib/src/sqlite.rs +++ b/crates/stdlib/src/sqlite.rs @@ -1007,6 +1007,10 @@ mod _sqlite { Ok(()) } + fn is_closed(&self) -> bool { + self.db.lock().is_none() + } + #[pymethod] fn commit(&self, vm: &VirtualMachine) -> PyResult<()> { self.db_lock(vm)?.implicit_commit(vm) @@ -2169,6 +2173,13 @@ mod _sqlite { length: OptionalArg, vm: &VirtualMachine, ) -> PyResult> { + if self.connection.is_closed() { + return Err(new_programming_error( + vm, + "Cannot operate on a closed database".to_owned(), + )); + } + let mut length = length.unwrap_or(-1); let mut inner = self.inner(vm)?; let blob_len = inner.blob.bytes(); From a9469a20d57d809fb1ee04e8d0259f4374b10533 Mon Sep 17 00:00:00 2001 From: Jiseok CHOI Date: Sat, 22 Nov 2025 22:13:06 +0900 Subject: [PATCH 003/577] Fix sqlite connection reinitialization (#6288) * Fix sqlite connection reinitialization * Align sqlite connection reinit with CPython * Enable sqlite test_connection_bad_reinit * Fix sqlite reinit flag without threading * Use stronger memory ordering for initialized flag synchronization --- Lib/test/test_sqlite3/test_dbapi.py | 2 - crates/stdlib/src/sqlite.rs | 88 +++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 26 deletions(-) diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index a2530a03e2..d8772dfffb 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -573,8 +573,6 @@ def test_connection_reinit(self): self.assertTrue(all(isinstance(r, sqlite.Row) for r in rows)) self.assertEqual([r[0] for r in rows], ["2", "3"]) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_connection_bad_reinit(self): cx = sqlite.connect(":memory:") with cx: diff --git a/crates/stdlib/src/sqlite.rs b/crates/stdlib/src/sqlite.rs index b875c60944..6851462e52 100644 --- a/crates/stdlib/src/sqlite.rs +++ b/crates/stdlib/src/sqlite.rs @@ -833,10 +833,11 @@ mod _sqlite { #[derive(PyPayload)] struct Connection { db: PyMutex>, - detect_types: c_int, + initialized: PyAtomic, + detect_types: PyAtomic, isolation_level: PyAtomicRef>, - check_same_thread: bool, - thread_ident: ThreadId, + check_same_thread: PyAtomic, + thread_ident: PyMutex, // TODO: Use atomic row_factory: PyAtomicRef>, text_factory: PyAtomicRef, } @@ -865,12 +866,15 @@ mod _sqlite { None }; + let initialized = db.is_some(); + let conn = Self { db: PyMutex::new(db), - detect_types: args.detect_types, + initialized: Radium::new(initialized), + detect_types: Radium::new(args.detect_types), isolation_level: PyAtomicRef::from(args.isolation_level), - check_same_thread: args.check_same_thread, - thread_ident: std::thread::current().id(), + check_same_thread: Radium::new(args.check_same_thread), + thread_ident: PyMutex::new(std::thread::current().id()), row_factory: PyAtomicRef::from(None), text_factory: PyAtomicRef::from(text_factory), }; @@ -899,20 +903,51 @@ mod _sqlite { type Args = ConnectArgs; fn init(zelf: PyRef, args: Self::Args, vm: &VirtualMachine) -> PyResult<()> { - let mut guard = zelf.db.lock(); - if guard.is_some() { - // Already initialized - return Ok(()); + let was_initialized = Radium::swap(&zelf.initialized, false, Ordering::AcqRel); + + // Reset factories to their defaults, matching CPython's behavior. + zelf.reset_factories(vm); + + if was_initialized { + zelf.drop_db(); } + // Attempt to open the new database before mutating other state so failures leave + // the connection uninitialized (and subsequent operations raise ProgrammingError). let db = Self::initialize_db(&args, vm)?; + + let ConnectArgs { + detect_types, + isolation_level, + check_same_thread, + .. + } = args; + + zelf.detect_types.store(detect_types, Ordering::Relaxed); + zelf.check_same_thread + .store(check_same_thread, Ordering::Relaxed); + *zelf.thread_ident.lock() = std::thread::current().id(); + let _ = unsafe { zelf.isolation_level.swap(isolation_level) }; + + let mut guard = zelf.db.lock(); *guard = Some(db); + Radium::store(&zelf.initialized, true, Ordering::Release); Ok(()) } } #[pyclass(with(Constructor, Callable, Initializer), flags(BASETYPE))] impl Connection { + fn drop_db(&self) { + self.db.lock().take(); + } + + fn reset_factories(&self, vm: &VirtualMachine) { + let default_text_factory = PyStr::class(&vm.ctx).to_owned().into_object(); + let _ = unsafe { self.row_factory.swap(None) }; + let _ = unsafe { self.text_factory.swap(default_text_factory) }; + } + fn initialize_db(args: &ConnectArgs, vm: &VirtualMachine) -> PyResult { let path = args.database.to_cstring(vm)?; let db = Sqlite::from(SqliteRaw::open(path.as_ptr(), args.uri, vm)?); @@ -1003,7 +1038,7 @@ mod _sqlite { #[pymethod] fn close(&self, vm: &VirtualMachine) -> PyResult<()> { self.check_thread(vm)?; - self.db.lock().take(); + self.drop_db(); Ok(()) } @@ -1450,15 +1485,17 @@ mod _sqlite { } fn check_thread(&self, vm: &VirtualMachine) -> PyResult<()> { - if self.check_same_thread && (std::thread::current().id() != self.thread_ident) { - Err(new_programming_error( - vm, - "SQLite objects created in a thread can only be used in that same thread." - .to_owned(), - )) - } else { - Ok(()) + if self.check_same_thread.load(Ordering::Relaxed) { + let creator_id = *self.thread_ident.lock(); + if std::thread::current().id() != creator_id { + return Err(new_programming_error( + vm, + "SQLite objects created in a thread can only be used in that same thread." + .to_owned(), + )); + } } + Ok(()) } #[pygetset] @@ -1632,7 +1669,8 @@ mod _sqlite { inner.row_cast_map = zelf.build_row_cast_map(&st, vm)?; - inner.description = st.columns_description(zelf.connection.detect_types, vm)?; + let detect_types = zelf.connection.detect_types.load(Ordering::Relaxed); + inner.description = st.columns_description(detect_types, vm)?; if ret == SQLITE_ROW { drop(st); @@ -1680,7 +1718,8 @@ mod _sqlite { )); } - inner.description = st.columns_description(zelf.connection.detect_types, vm)?; + let detect_types = zelf.connection.detect_types.load(Ordering::Relaxed); + inner.description = st.columns_description(detect_types, vm)?; inner.rowcount = if stmt.is_dml { 0 } else { -1 }; @@ -1845,7 +1884,8 @@ mod _sqlite { st: &SqliteStatementRaw, vm: &VirtualMachine, ) -> PyResult>> { - if self.connection.detect_types == 0 { + let detect_types = self.connection.detect_types.load(Ordering::Relaxed); + if detect_types == 0 { return Ok(vec![]); } @@ -1853,7 +1893,7 @@ mod _sqlite { let num_cols = st.column_count(); for i in 0..num_cols { - if self.connection.detect_types & PARSE_COLNAMES != 0 { + if detect_types & PARSE_COLNAMES != 0 { let col_name = st.column_name(i); let col_name = ptr_to_str(col_name, vm)?; let col_name = col_name @@ -1868,7 +1908,7 @@ mod _sqlite { continue; } } - if self.connection.detect_types & PARSE_DECLTYPES != 0 { + if detect_types & PARSE_DECLTYPES != 0 { let decltype = st.column_decltype(i); let decltype = ptr_to_str(decltype, vm)?; if let Some(decltype) = decltype.split_terminator(&[' ', '(']).next() { From f61b62e5a2e126a8cf16793f94e2801a6a47da02 Mon Sep 17 00:00:00 2001 From: Jiseok CHOI Date: Mon, 24 Nov 2025 00:04:43 +0900 Subject: [PATCH 004/577] Ensure sqlite blob methods respect closed connections (#6290) --- crates/stdlib/src/sqlite.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/crates/stdlib/src/sqlite.rs b/crates/stdlib/src/sqlite.rs index 6851462e52..9fdb1716ac 100644 --- a/crates/stdlib/src/sqlite.rs +++ b/crates/stdlib/src/sqlite.rs @@ -2207,18 +2207,24 @@ mod _sqlite { self.inner.lock().take(); } + fn ensure_connection_open(&self, vm: &VirtualMachine) -> PyResult<()> { + if self.connection.is_closed() { + Err(new_programming_error( + vm, + "Cannot operate on a closed database".to_owned(), + )) + } else { + Ok(()) + } + } + #[pymethod] fn read( &self, length: OptionalArg, vm: &VirtualMachine, ) -> PyResult> { - if self.connection.is_closed() { - return Err(new_programming_error( - vm, - "Cannot operate on a closed database".to_owned(), - )); - } + self.ensure_connection_open(vm)?; let mut length = length.unwrap_or(-1); let mut inner = self.inner(vm)?; @@ -2245,6 +2251,7 @@ mod _sqlite { #[pymethod] fn write(&self, data: PyBuffer, vm: &VirtualMachine) -> PyResult<()> { + self.ensure_connection_open(vm)?; let mut inner = self.inner(vm)?; let blob_len = inner.blob.bytes(); let length = Self::expect_write(blob_len, data.desc.len, inner.offset, vm)?; @@ -2260,6 +2267,7 @@ mod _sqlite { #[pymethod] fn tell(&self, vm: &VirtualMachine) -> PyResult { + self.ensure_connection_open(vm)?; self.inner(vm).map(|x| x.offset) } @@ -2270,6 +2278,7 @@ mod _sqlite { origin: OptionalArg, vm: &VirtualMachine, ) -> PyResult<()> { + self.ensure_connection_open(vm)?; let origin = origin.unwrap_or(libc::SEEK_SET); let mut inner = self.inner(vm)?; let blob_len = inner.blob.bytes(); @@ -2299,12 +2308,14 @@ mod _sqlite { #[pymethod] fn __enter__(zelf: PyRef, vm: &VirtualMachine) -> PyResult> { + zelf.ensure_connection_open(vm)?; let _ = zelf.inner(vm)?; Ok(zelf) } #[pymethod] fn __exit__(&self, _args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> { + self.ensure_connection_open(vm)?; let _ = self.inner(vm)?; self.close(); Ok(()) @@ -2351,6 +2362,7 @@ mod _sqlite { } fn subscript(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult { + self.ensure_connection_open(vm)?; let inner = self.inner(vm)?; if let Some(index) = needle.try_index_opt(vm) { let blob_len = inner.blob.bytes(); @@ -2396,6 +2408,7 @@ mod _sqlite { let Some(value) = value else { return Err(vm.new_type_error("Blob doesn't support slice deletion")); }; + self.ensure_connection_open(vm)?; let inner = self.inner(vm)?; if let Some(index) = needle.try_index_opt(vm) { From 817f91b5bfd314aa44a5caebc2c689c6da53812d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Nov 2025 05:29:53 +0900 Subject: [PATCH 005/577] Bump xml from 1.0.1 to 1.2.0 (#6292) Bumps [xml](https://github.com/kornelski/xml-rs) from 1.0.1 to 1.2.0. - [Changelog](https://github.com/kornelski/xml-rs/blob/main/Changelog.md) - [Commits](https://github.com/kornelski/xml-rs/compare/1.0.1...1.2.0) --- updated-dependencies: - dependency-name: xml dependency-version: 1.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- crates/stdlib/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f749bc49b..718631a8d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4756,9 +4756,9 @@ dependencies = [ [[package]] name = "xml" -version = "1.0.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58a4274c410d957424a1502b21126915b45d9956b2f80a88d4f6f906af29facc" +checksum = "2df5825faced2427b2da74d9100f1e2e93c533fff063506a81ede1cf517b2e7e" [[package]] name = "xz2" diff --git a/crates/stdlib/Cargo.toml b/crates/stdlib/Cargo.toml index e62872324e..dbff752b99 100644 --- a/crates/stdlib/Cargo.toml +++ b/crates/stdlib/Cargo.toml @@ -51,7 +51,7 @@ base64 = "0.22" csv-core = "0.1.11" dyn-clone = "1.0.10" pymath = { workspace = true } -xml = "1.0" +xml = "1.2" # random rand_core = { workspace = true } From ea3eb2a9efac84018f390ecf3af29d5ab7ec0bd3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Nov 2025 05:30:13 +0900 Subject: [PATCH 006/577] Bump actions/checkout from 4 to 6 (#6294) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Commits](https://github.com/actions/checkout/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yaml | 14 +++++++------- .github/workflows/cron-ci.yaml | 8 ++++---- .github/workflows/pr-auto-commit.yaml | 2 +- .github/workflows/release.yml | 4 ++-- .github/workflows/update-doc-db.yml | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 95a1ac98d6..23d16ffadb 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -120,7 +120,7 @@ jobs: os: [macos-latest, ubuntu-latest, windows-latest] fail-fast: false steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable with: components: clippy @@ -179,7 +179,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable with: target: i686-unknown-linux-gnu @@ -246,7 +246,7 @@ jobs: os: [macos-latest, ubuntu-latest, windows-latest] fail-fast: false steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - uses: actions/setup-python@v6 @@ -311,7 +311,7 @@ jobs: name: Check Rust code with clippy runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable with: components: clippy @@ -350,7 +350,7 @@ jobs: env: NIGHTLY_CHANNEL: nightly steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@master with: @@ -372,7 +372,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 @@ -435,7 +435,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable with: target: wasm32-wasip1 diff --git a/.github/workflows/cron-ci.yaml b/.github/workflows/cron-ci.yaml index a94c8df9e2..e10c5ac0d1 100644 --- a/.github/workflows/cron-ci.yaml +++ b/.github/workflows/cron-ci.yaml @@ -21,7 +21,7 @@ jobs: # Disable this scheduled job when running on a fork. if: ${{ github.repository == 'RustPython/RustPython' || github.event_name != 'schedule' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable - uses: taiki-e/install-action@cargo-llvm-cov - uses: actions/setup-python@v6 @@ -49,7 +49,7 @@ jobs: # Disable this scheduled job when running on a fork. if: ${{ github.repository == 'RustPython/RustPython' || github.event_name != 'schedule' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable - name: build rustpython run: cargo build --release --verbose @@ -80,7 +80,7 @@ jobs: # Disable this scheduled job when running on a fork. if: ${{ github.repository == 'RustPython/RustPython' || github.event_name != 'schedule' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable - uses: actions/setup-python@v6 with: @@ -137,7 +137,7 @@ jobs: # Disable this scheduled job when running on a fork. if: ${{ github.repository == 'RustPython/RustPython' || github.event_name != 'schedule' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable - uses: actions/setup-python@v6 with: diff --git a/.github/workflows/pr-auto-commit.yaml b/.github/workflows/pr-auto-commit.yaml index 8546c2abe5..62f9eb9c33 100644 --- a/.github/workflows/pr-auto-commit.yaml +++ b/.github/workflows/pr-auto-commit.yaml @@ -26,7 +26,7 @@ jobs: steps: - name: Checkout PR branch - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.ref }} repository: ${{ github.event.pull_request.head.repo.full_name }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 43286780ef..a69169c323 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,7 +50,7 @@ jobs: # target: aarch64-pc-windows-msvc fail-fast: false steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable - uses: cargo-bins/cargo-binstall@main @@ -93,7 +93,7 @@ jobs: # Disable this scheduled job when running on a fork. if: ${{ github.repository == 'RustPython/RustPython' || github.event_name != 'schedule' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable with: targets: wasm32-wasip1 diff --git a/.github/workflows/update-doc-db.yml b/.github/workflows/update-doc-db.yml index dcef94f20d..0f84b8d23a 100644 --- a/.github/workflows/update-doc-db.yml +++ b/.github/workflows/update-doc-db.yml @@ -26,7 +26,7 @@ jobs: - windows-latest - macos-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: persist-credentials: false sparse-checkout: | @@ -51,7 +51,7 @@ jobs: runs-on: ubuntu-latest needs: generate steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: persist-credentials: false sparse-checkout: | From 1e7a49036a9e6f22867511b553ffcb76be62ac5f Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" <69878+youknowone@users.noreply.github.com> Date: Tue, 25 Nov 2025 20:04:30 +0900 Subject: [PATCH 007/577] try auto-format again (#6295) --- .github/workflows/pr-auto-commit.yaml | 60 ++++++++------------------- 1 file changed, 18 insertions(+), 42 deletions(-) diff --git a/.github/workflows/pr-auto-commit.yaml b/.github/workflows/pr-auto-commit.yaml index 62f9eb9c33..118f7bcd4d 100644 --- a/.github/workflows/pr-auto-commit.yaml +++ b/.github/workflows/pr-auto-commit.yaml @@ -1,4 +1,4 @@ -name: PR Auto-format +name: Auto-format PR # This workflow triggers when a PR is opened/updated on: @@ -9,42 +9,26 @@ on: - release concurrency: - group: pr-fmt-${{ github.event.pull_request.number }} + group: auto-format-${{ github.event.pull_request.number }} cancel-in-progress: true jobs: auto_format: - if: | - !contains(github.event.pull_request.labels.*.name, 'skip:ci') && - !contains(github.event.pull_request.head.sha, '[skip ci]') + if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip:ci') }} permissions: contents: write pull-requests: write - checks: read runs-on: ubuntu-latest timeout-minutes: 60 - steps: - name: Checkout PR branch uses: actions/checkout@v6 with: - ref: ${{ github.event.pull_request.head.ref }} + ref: ${{ github.event.pull_request.head.sha }} repository: ${{ github.event.pull_request.head.repo.full_name }} - token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ secrets.AUTO_COMMIT_PAT }} fetch-depth: 0 - # Wait for all PR check runs to complete - - name: Wait for all checks to complete - uses: poseidon/wait-for-status-checks@v0.6.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} - delay: 60 - interval: 30 - timeout: 7200 - - - name: CI completed successfully - run: echo "CI workflow completed successfully - proceeding with auto-format" - - name: Setup Rust uses: dtolnay/rust-toolchain@stable with: @@ -55,8 +39,13 @@ jobs: echo "Running cargo fmt --all on PR #${{ github.event.pull_request.number }}" cargo fmt --all - - name: Check for formatting changes - id: check_changes + - name: Configure git + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Check for changes + id: check-changes run: | if [ -n "$(git status --porcelain)" ]; then echo "has_changes=true" >> $GITHUB_OUTPUT @@ -65,35 +54,22 @@ jobs: fi - name: Commit and push formatting changes - if: steps.check_changes.outputs.has_changes == 'true' + if: steps.check-changes.outputs.has_changes == 'true' run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add -u - git commit -m "Auto-format code [skip ci]" - + git commit -m "Auto-format: cargo fmt --all" git push origin HEAD:${{ github.event.pull_request.head.ref }} - name: Comment on PR - if: steps.check_changes.outputs.has_changes == 'true' + if: steps.check-changes.outputs.has_changes == 'true' uses: marocchino/sticky-pull-request-comment@v2 with: number: ${{ github.event.pull_request.number }} message: | **Code has been automatically formatted** - - The code in this PR has been formatted using `cargo fmt`. - The changes have been committed with `[skip ci]` to avoid triggering another CI run. - - **Triggered by commit:** `${{ github.event.pull_request.head.sha }}` - **Last formatted:** ${{ github.event.pull_request.updated_at }} - - You may need to pull the latest changes before pushing again: + + The code in this PR has been formatted using `cargo fmt --all`. + Please pull the latest changes before pushing again: ```bash git pull origin ${{ github.event.pull_request.head.ref }} ``` - - - name: No formatting needed - if: steps.check_changes.outputs.has_changes == 'false' - run: echo "Code is already properly formatted" From e733b7ecf99a2d3f255bc775d0f1df213c0db2fe Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Thu, 27 Nov 2025 17:15:02 +0200 Subject: [PATCH 008/577] Update `libc` to 0.2.177 --- Cargo.lock | 303 +++++++++++++++++++++++++---------------------------- Cargo.toml | 2 +- 2 files changed, 144 insertions(+), 161 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 718631a8d6..f96b527dfe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,9 +40,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -100,22 +100,22 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.10" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -231,9 +231,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-fips-sys" -version = "0.13.9" +version = "0.13.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede71ad84efb06d748d9af3bc500b14957a96282a69a6833b1420dcacb411cc3" +checksum = "57900537c00a0565a35b63c4c281b372edfc9744b072fd4a3b414350a8f5ed48" dependencies = [ "bindgen 0.72.1", "cc", @@ -245,9 +245,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.14.1" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879b6c89592deb404ba4dc0ae6b58ffd1795c78991cbb5b8bc441c48a070440d" +checksum = "6b5ce75405893cd713f9ab8e297d8e438f624dde7d706108285f7e17a25a180f" dependencies = [ "aws-lc-fips-sys", "aws-lc-sys", @@ -257,11 +257,10 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.32.3" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "107a4e9d9cab9963e04e84bb8dee0e25f2a987f9a8bad5ed054abd439caa8f8c" +checksum = "179c3777a8b5e70e90ea426114ffc565b2c1a9f82f6c4a0c5a34aa6ef5e781b6" dependencies = [ - "bindgen 0.72.1", "cc", "cmake", "dunce", @@ -286,7 +285,7 @@ version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cexpr", "clang-sys", "itertools 0.13.0", @@ -306,7 +305,7 @@ version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cexpr", "clang-sys", "itertools 0.13.0", @@ -328,9 +327,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "blake2" @@ -361,9 +360,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" dependencies = [ "memchr", "regex-automata", @@ -435,9 +434,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.41" +version = "1.2.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" +checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" dependencies = [ "find-msvc-tools", "jobserver", @@ -535,18 +534,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.49" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.49" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" dependencies = [ "anstyle", "clap_lex", @@ -926,9 +925,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -1052,9 +1051,9 @@ dependencies = [ [[package]] name = "dns-lookup" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853d5bcf0b73bd5e6d945b976288621825c7166e9f06c5a035ae1aaf42d1b64f" +checksum = "6e39034cee21a2f5bbb66ba0e3689819c4bb5d00382a282006e802a7ffa6c41d" dependencies = [ "cfg-if", "libc", @@ -1174,9 +1173,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" [[package]] name = "flagset" @@ -1222,9 +1221,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", "libz-rs-sys", @@ -1260,9 +1259,9 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "generic-array" -version = "0.14.9" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -1270,9 +1269,9 @@ dependencies = [ [[package]] name = "get-size-derive2" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3814abc7da8ab18d2fd820f5b540b5e39b6af0a32de1bdd7c47576693074843" +checksum = "ff47daa61505c85af126e9dd64af6a342a33dc0cccfe1be74ceadc7d352e6efd" dependencies = [ "attribute-derive", "quote", @@ -1281,13 +1280,13 @@ dependencies = [ [[package]] name = "get-size2" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfe2cec5b5ce8fb94dcdb16a1708baa4d0609cc3ce305ca5d3f6f2ffb59baed" +checksum = "ac7bb8710e1f09672102be7ddf39f764d8440ae74a9f4e30aaa4820dcdffa4af" dependencies = [ "compact_str", "get-size-derive2", - "hashbrown 0.16.0", + "hashbrown 0.16.1", "smallvec", ] @@ -1374,9 +1373,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "heck" @@ -1413,11 +1412,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1446,19 +1445,22 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown 0.16.0", + "hashbrown 0.16.1", ] [[package]] name = "indoc" -version = "2.0.6" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] [[package]] name = "inout" @@ -1472,9 +1474,9 @@ dependencies = [ [[package]] name = "insta" -version = "1.43.2" +version = "1.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fdb647ebde000f43b5b53f773c30cf9b0cb4300453208713fa38b2c70935a0" +checksum = "dfd3461e1f00283105bdf97c3a1aca2b3f8456eb809a96938d2b190cd4dbc6d2" dependencies = [ "console", "once_cell", @@ -1501,9 +1503,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" @@ -1531,22 +1533,22 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" dependencies = [ "jiff-static", "log", "portable-atomic", "portable-atomic-util", - "serde", + "serde_core", ] [[package]] name = "jiff-static" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" dependencies = [ "proc-macro2", "quote", @@ -1587,9 +1589,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -1710,7 +1712,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "libc", ] @@ -1951,7 +1953,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cfg-if", "cfg_aliases", "libc", @@ -1964,7 +1966,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cfg-if", "cfg_aliases", "libc", @@ -2036,9 +2038,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -2046,9 +2048,9 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro2", "quote", @@ -2072,9 +2074,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "oorandom" @@ -2084,11 +2086,11 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "openssl" -version = "0.10.74" +version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ad14dd45412269e1a30f52ad8f0664f0f4f4a89ee8fe28c3b3527021ebb654" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cfg-if", "foreign-types", "libc", @@ -2116,18 +2118,18 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-src" -version = "300.5.3+3.5.4" +version = "300.5.4+3.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6bad8cd0233b63971e232cc9c5e83039375b8586d2312f31fda85db8f888c2" +checksum = "a507b3792995dae9b0df8a1c1e3771e8418b7c2d9f0baeba32e6fe8b06c7cb72" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.110" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a9f0075ba3c21b09f8e8b2026584b1d18d49388648f2fbbf3c97ea8deced8e2" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" dependencies = [ "cc", "libc", @@ -2419,9 +2421,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -2498,9 +2500,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -2643,7 +2645,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", ] [[package]] @@ -2753,7 +2755,7 @@ version = "0.0.0" source = "git+https://github.com/astral-sh/ruff.git?tag=0.14.1#2bffef59665ce7d2630dfd72ee99846663660db8" dependencies = [ "aho-corasick", - "bitflags 2.9.4", + "bitflags 2.10.0", "compact_str", "get-size2", "is-macro", @@ -2771,7 +2773,7 @@ name = "ruff_python_parser" version = "0.0.0" source = "git+https://github.com/astral-sh/ruff.git?tag=0.14.1#2bffef59665ce7d2630dfd72ee99846663660db8" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "bstr", "compact_str", "get-size2", @@ -2835,7 +2837,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys", @@ -2953,7 +2955,7 @@ name = "rustpython-codegen" version = "0.4.0" dependencies = [ "ahash", - "bitflags 2.9.4", + "bitflags 2.10.0", "indexmap", "insta", "itertools 0.14.0", @@ -2977,7 +2979,7 @@ name = "rustpython-common" version = "0.4.0" dependencies = [ "ascii", - "bitflags 2.9.4", + "bitflags 2.10.0", "cfg-if", "getrandom 0.3.4", "itertools 0.14.0", @@ -3016,7 +3018,7 @@ dependencies = [ name = "rustpython-compiler-core" version = "0.4.0" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "itertools 0.14.0", "lz4_flex", "malachite-bigint", @@ -3105,7 +3107,7 @@ dependencies = [ name = "rustpython-sre_engine" version = "0.4.0" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "criterion", "num_enum", "optional", @@ -3208,7 +3210,7 @@ version = "0.4.0" dependencies = [ "ahash", "ascii", - "bitflags 2.9.4", + "bitflags 2.10.0", "bstr", "caseless", "cfg-if", @@ -3319,7 +3321,7 @@ version = "17.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e902948a25149d50edc1a8e0141aad50f54e22ba83ff988cf8f7c9ef07f50564" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cfg-if", "clipboard-win", "fd-lock", @@ -3406,7 +3408,7 @@ version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -3479,11 +3481,11 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.9" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -3634,9 +3636,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.107" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -3671,7 +3673,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -3870,44 +3872,42 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.23" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ - "serde", + "indexmap", + "serde_core", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_parser", + "toml_writer", + "winnow", ] [[package]] name = "toml_datetime" -version = "0.6.11" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ - "serde", + "serde_core", ] [[package]] -name = "toml_edit" -version = "0.22.27" +name = "toml_parser" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "toml_write", "winnow", ] [[package]] -name = "toml_write" -version = "0.1.2" +name = "toml_writer" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" [[package]] name = "twox-hash" @@ -4055,15 +4055,15 @@ checksum = "061dbb8cc7f108532b6087a0065eff575e892a4bcb503dc57323a197457cc202" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] @@ -4196,9 +4196,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", @@ -4207,25 +4207,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.54" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ "cfg-if", "js-sys", @@ -4236,9 +4222,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4246,22 +4232,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] @@ -4280,9 +4266,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -4684,12 +4670,9 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" -dependencies = [ - "memchr", -] +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" [[package]] name = "winreg" @@ -4703,9 +4686,9 @@ dependencies = [ [[package]] name = "winresource" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edcacf11b6f48dd21b9ba002f991bdd5de29b2da8cc2800412f4b80f677e4957" +checksum = "f1ef04dd590e94ff7431a8eda99d5ca659e688d60e930bd0a330062acea4608f" dependencies = [ "toml", "version_check", @@ -4771,18 +4754,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.27" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.27" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 53d1eb6ea2..8993ce145f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -175,7 +175,7 @@ insta = "1.42" itertools = "0.14.0" is-macro = "0.3.7" junction = "1.3.0" -libc = "0.2.169" +libc = "0.2.177" libffi = "4.1" log = "0.4.28" nix = { version = "0.30", features = ["fs", "user", "process", "term", "time", "signal", "ioctl", "socket", "sched", "zerocopy", "dir", "hostname", "net", "poll"] } From 081a8f0451317f776388c5160d67db51fd2fa1bd Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Thu, 27 Nov 2025 17:16:42 +0200 Subject: [PATCH 009/577] Regenerate libc constatnts --- crates/vm/src/stdlib/posix.rs | 6 +++--- scripts/libc_posix.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/vm/src/stdlib/posix.rs b/crates/vm/src/stdlib/posix.rs index e8a01d0e68..071f93d7ee 100644 --- a/crates/vm/src/stdlib/posix.rs +++ b/crates/vm/src/stdlib/posix.rs @@ -202,8 +202,7 @@ pub mod module { #[pyattr] use libc::{ CLD_CONTINUED, CLD_DUMPED, CLD_EXITED, CLD_KILLED, CLD_STOPPED, CLD_TRAPPED, F_LOCK, - F_TEST, F_TLOCK, F_ULOCK, O_NDELAY, O_NOCTTY, O_SYNC, P_ALL, P_PGID, P_PID, SCHED_FIFO, - SCHED_RR, + F_TEST, F_TLOCK, F_ULOCK, O_SYNC, P_ALL, P_PGID, P_PID, SCHED_FIFO, SCHED_RR, }; #[cfg(any( @@ -217,7 +216,8 @@ pub mod module { target_os = "redox" ))] #[pyattr] - use libc::{O_ASYNC, WEXITED, WNOWAIT, WSTOPPED}; + use libc::{O_ASYNC, O_NDELAY, O_NOCTTY, WEXITED, WNOWAIT, WSTOPPED}; + #[pyattr] const EX_OK: i8 = exitcode::OK as i8; diff --git a/scripts/libc_posix.py b/scripts/libc_posix.py index 9ed6890e70..73f082a065 100644 --- a/scripts/libc_posix.py +++ b/scripts/libc_posix.py @@ -13,7 +13,7 @@ ) # TODO: Exclude matches if they have `(` after (those are functions) -LIBC_VERSION = "0.2.175" +LIBC_VERSION = "0.2.177" EXCLUDE = frozenset( { From 1b3261a090b4331cfcc60e8bad2ced92f0f8fb28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Nov 2025 08:39:46 +0900 Subject: [PATCH 010/577] Bump node-forge from 1.3.1 to 1.3.2 in /wasm/demo (#6297) Bumps [node-forge](https://github.com/digitalbazaar/forge) from 1.3.1 to 1.3.2. - [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md) - [Commits](https://github.com/digitalbazaar/forge/compare/v1.3.1...v1.3.2) --- updated-dependencies: - dependency-name: node-forge dependency-version: 1.3.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- wasm/demo/package-lock.json | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/wasm/demo/package-lock.json b/wasm/demo/package-lock.json index e3cf79298a..3acc105e3c 100644 --- a/wasm/demo/package-lock.json +++ b/wasm/demo/package-lock.json @@ -775,7 +775,8 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz", "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", @@ -831,6 +832,7 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -1149,6 +1151,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -3495,9 +3498,9 @@ } }, "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.2.tgz", + "integrity": "sha512-6xKiQ+cph9KImrRh0VsjH2d8/GXA4FIMlgU4B757iI1ApvcyA9VlouP0yZJha01V+huImO+kKMU7ih+2+E14fw==", "dev": true, "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { @@ -3824,6 +3827,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", @@ -5082,7 +5086,8 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, - "license": "0BSD" + "license": "0BSD", + "peer": true }, "node_modules/type-fest": { "version": "2.19.0", @@ -5266,6 +5271,7 @@ "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", @@ -5313,6 +5319,7 @@ "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@discoveryjs/json-ext": "^0.6.1", "@webpack-cli/configtest": "^3.0.1", From 0e6e256f8e1448411d7c86d5fa23ec3fe72f4296 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Fri, 28 Nov 2025 06:41:22 +0700 Subject: [PATCH 011/577] Fix redox compilation in stdlib (#6298) --- crates/stdlib/src/posixsubprocess.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/stdlib/src/posixsubprocess.rs b/crates/stdlib/src/posixsubprocess.rs index 7f418c8993..4da6a6858d 100644 --- a/crates/stdlib/src/posixsubprocess.rs +++ b/crates/stdlib/src/posixsubprocess.rs @@ -441,15 +441,14 @@ fn close_dir_fds(keep: KeepFds<'_>) -> nix::Result<()> { fn close_filetable_fds(keep: KeepFds<'_>) -> nix::Result<()> { use nix::fcntl; use std::os::fd::{FromRawFd, OwnedFd}; - let fd = fcntl::open( + let filetable = fcntl::open( c"/scheme/thisproc/current/filetable", fcntl::OFlag::O_RDONLY, nix::sys::stat::Mode::empty(), )?; - let filetable = unsafe { OwnedFd::from_raw_fd(fd) }; let read_one = || -> nix::Result<_> { let mut byte = 0; - let n = nix::unistd::read(filetable.as_raw_fd(), std::slice::from_mut(&mut byte))?; + let n = nix::unistd::read(&filetable, std::slice::from_mut(&mut byte))?; Ok((n > 0).then_some(byte)) }; while let Some(c) = read_one()? { From f37ea525650d975a8a87fa8052e1785612684ab1 Mon Sep 17 00:00:00 2001 From: Ashwin Naren Date: Mon, 31 Mar 2025 21:42:54 -0700 Subject: [PATCH 012/577] Ctypes more pointer implementation fix import add more classes ctypes overhall updates fix build fix warnings, pass test fix panic on improper library load test on macos formatting tmp minor updates --- crates/vm/src/stdlib/ctypes.rs | 11 +- crates/vm/src/stdlib/ctypes/array.rs | 1 + crates/vm/src/stdlib/ctypes/base.rs | 22 +- crates/vm/src/stdlib/ctypes/field.rs | 134 ++++++++ crates/vm/src/stdlib/ctypes/function.rs | 386 +++++++++++++++--------- crates/vm/src/stdlib/ctypes/pointer.rs | 41 ++- crates/vm/src/stdlib/ctypes/thunk.rs | 22 ++ crates/vm/src/stdlib/ctypes/util.rs | 24 ++ extra_tests/snippets/stdlib_ctypes.py | 11 +- 9 files changed, 491 insertions(+), 161 deletions(-) create mode 100644 crates/vm/src/stdlib/ctypes/field.rs create mode 100644 crates/vm/src/stdlib/ctypes/thunk.rs create mode 100644 crates/vm/src/stdlib/ctypes/util.rs diff --git a/crates/vm/src/stdlib/ctypes.rs b/crates/vm/src/stdlib/ctypes.rs index 8ea4dd165e..ac74418354 100644 --- a/crates/vm/src/stdlib/ctypes.rs +++ b/crates/vm/src/stdlib/ctypes.rs @@ -2,11 +2,14 @@ pub(crate) mod array; pub(crate) mod base; +pub(crate) mod field; pub(crate) mod function; pub(crate) mod library; pub(crate) mod pointer; pub(crate) mod structure; +pub(crate) mod thunk; pub(crate) mod union; +pub(crate) mod util; use crate::builtins::PyModule; use crate::class::PyClassImpl; @@ -17,14 +20,18 @@ pub fn extend_module_nodes(vm: &VirtualMachine, module: &Py) { let ctx = &vm.ctx; PyCSimpleType::make_class(ctx); array::PyCArrayType::make_class(ctx); + field::PyCFieldType::make_class(ctx); + pointer::PyCPointerType::make_class(ctx); extend_module!(vm, module, { "_CData" => PyCData::make_class(ctx), "_SimpleCData" => PyCSimple::make_class(ctx), "Array" => array::PyCArray::make_class(ctx), + "CField" => field::PyCField::make_class(ctx), "CFuncPtr" => function::PyCFuncPtr::make_class(ctx), "_Pointer" => pointer::PyCPointer::make_class(ctx), "_pointer_type_cache" => ctx.new_dict(), "Structure" => structure::PyCStructure::make_class(ctx), + "CThunkObject" => thunk::PyCThunk::make_class(ctx), "Union" => union::PyCUnion::make_class(ctx), }) } @@ -207,7 +214,9 @@ pub(crate) mod _ctypes { // TODO: load_flags let cache = library::libcache(); let mut cache_write = cache.write(); - let (id, _) = cache_write.get_or_insert_lib(&name, vm).unwrap(); + let (id, _) = cache_write + .get_or_insert_lib(&name, vm) + .map_err(|e| vm.new_os_error(e.to_string()))?; Ok(id) } diff --git a/crates/vm/src/stdlib/ctypes/array.rs b/crates/vm/src/stdlib/ctypes/array.rs index 5290ec42f3..a1adf847a9 100644 --- a/crates/vm/src/stdlib/ctypes/array.rs +++ b/crates/vm/src/stdlib/ctypes/array.rs @@ -106,6 +106,7 @@ impl PyCArray { } impl PyCArray { + #[allow(unused)] pub fn to_arg(&self, _vm: &VirtualMachine) -> PyResult { let value = self.value.read(); let py_bytes = value.downcast_ref::().unwrap(); diff --git a/crates/vm/src/stdlib/ctypes/base.rs b/crates/vm/src/stdlib/ctypes/base.rs index 23cb505ada..f5a25ad740 100644 --- a/crates/vm/src/stdlib/ctypes/base.rs +++ b/crates/vm/src/stdlib/ctypes/base.rs @@ -276,25 +276,25 @@ impl PyCSimple { let value = unsafe { (*self.value.as_ptr()).clone() }; if let Ok(i) = value.try_int(vm) { let i = i.as_bigint(); - if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::u8().as_raw_ptr()) { - return i.to_u8().map(|r: u8| libffi::middle::Arg::new(&r)); + return if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::u8().as_raw_ptr()) { + i.to_u8().map(|r: u8| libffi::middle::Arg::new(&r)) } else if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::i8().as_raw_ptr()) { - return i.to_i8().map(|r: i8| libffi::middle::Arg::new(&r)); + i.to_i8().map(|r: i8| libffi::middle::Arg::new(&r)) } else if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::u16().as_raw_ptr()) { - return i.to_u16().map(|r: u16| libffi::middle::Arg::new(&r)); + i.to_u16().map(|r: u16| libffi::middle::Arg::new(&r)) } else if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::i16().as_raw_ptr()) { - return i.to_i16().map(|r: i16| libffi::middle::Arg::new(&r)); + i.to_i16().map(|r: i16| libffi::middle::Arg::new(&r)) } else if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::u32().as_raw_ptr()) { - return i.to_u32().map(|r: u32| libffi::middle::Arg::new(&r)); + i.to_u32().map(|r: u32| libffi::middle::Arg::new(&r)) } else if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::i32().as_raw_ptr()) { - return i.to_i32().map(|r: i32| libffi::middle::Arg::new(&r)); + i.to_i32().map(|r: i32| libffi::middle::Arg::new(&r)) } else if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::u64().as_raw_ptr()) { - return i.to_u64().map(|r: u64| libffi::middle::Arg::new(&r)); + i.to_u64().map(|r: u64| libffi::middle::Arg::new(&r)) } else if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::i64().as_raw_ptr()) { - return i.to_i64().map(|r: i64| libffi::middle::Arg::new(&r)); + i.to_i64().map(|r: i64| libffi::middle::Arg::new(&r)) } else { - return None; - } + None + }; } if let Ok(_f) = value.try_float(vm) { todo!(); diff --git a/crates/vm/src/stdlib/ctypes/field.rs b/crates/vm/src/stdlib/ctypes/field.rs new file mode 100644 index 0000000000..b50b8b54ac --- /dev/null +++ b/crates/vm/src/stdlib/ctypes/field.rs @@ -0,0 +1,134 @@ +use crate::builtins::PyType; +use crate::builtins::PyTypeRef; +use crate::stdlib::ctypes::PyCData; +use crate::types::Constructor; +use crate::types::Representable; +use crate::{Py, PyResult, VirtualMachine}; + +#[pyclass(name = "PyCFieldType", base = PyType, module = "_ctypes")] +#[derive(PyPayload, Debug)] +pub struct PyCFieldType { + pub(super) inner: PyCField, +} + +#[pyclass] +impl PyCFieldType {} + +#[pyclass( + name = "CField", + base = PyCData, + metaclass = "PyCFieldType", + module = "_ctypes" +)] +#[derive(Debug, PyPayload)] +pub struct PyCField { + byte_offset: usize, + byte_size: usize, + #[allow(unused)] + index: usize, + proto: PyTypeRef, + anonymous: bool, + bitfield_size: bool, + bit_offset: u8, + name: String, +} + +impl Representable for PyCField { + fn repr_str(zelf: &Py, _vm: &VirtualMachine) -> PyResult { + let tp_name = zelf.proto.name().to_string(); + if zelf.bitfield_size != false { + Ok(format!( + "<{} type={}, ofs={byte_offset}, bit_size={bitfield_size}, bit_offset={bit_offset}", + zelf.name, + tp_name, + byte_offset = zelf.byte_offset, + bitfield_size = zelf.bitfield_size, + bit_offset = zelf.bit_offset + )) + } else { + Ok(format!( + "<{} type={tp_name}, ofs={}, size={}", + zelf.name, zelf.byte_offset, zelf.byte_size + )) + } + } +} + +#[derive(Debug, FromArgs)] +pub struct PyCFieldConstructorArgs { + // PyObject *name, PyObject *proto, + // Py_ssize_t byte_size, Py_ssize_t byte_offset, + // Py_ssize_t index, int _internal_use, + // PyObject *bit_size_obj, PyObject *bit_offset_obj +} + +impl Constructor for PyCField { + type Args = PyCFieldConstructorArgs; + + fn py_new(_cls: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult { + Err(vm.new_type_error("Cannot instantiate a PyCField".to_string())) + } +} + +#[pyclass(flags(BASETYPE, IMMUTABLETYPE), with(Constructor, Representable))] +impl PyCField { + #[pygetset] + fn size(&self) -> usize { + self.byte_size + } + + #[pygetset] + fn bit_size(&self) -> bool { + self.bitfield_size + } + + #[pygetset] + fn is_bitfield(&self) -> bool { + self.bitfield_size + } + + #[pygetset] + fn is_anonymous(&self) -> bool { + self.anonymous + } + + #[pygetset] + fn name(&self) -> String { + self.name.clone() + } + + #[pygetset(name = "type")] + fn type_(&self) -> PyTypeRef { + self.proto.clone() + } + + #[pygetset] + fn offset(&self) -> usize { + self.byte_offset + } + + #[pygetset] + fn byte_offset(&self) -> usize { + self.byte_offset + } + + #[pygetset] + fn byte_size(&self) -> usize { + self.byte_size + } + + #[pygetset] + fn bit_offset(&self) -> u8 { + self.bit_offset + } +} + +#[inline(always)] +pub const fn low_bit(offset: usize) -> usize { + offset & 0xFFFF +} + +#[inline(always)] +pub const fn high_bit(offset: usize) -> usize { + offset >> 16 +} diff --git a/crates/vm/src/stdlib/ctypes/function.rs b/crates/vm/src/stdlib/ctypes/function.rs index 6703dcc0f5..88d0fbb35e 100644 --- a/crates/vm/src/stdlib/ctypes/function.rs +++ b/crates/vm/src/stdlib/ctypes/function.rs @@ -1,142 +1,117 @@ // spell-checker:disable -use crate::builtins::{PyStr, PyTupleRef, PyTypeRef}; +use crate::builtins::{PyNone, PyStr, PyTuple, PyTupleRef, PyType, PyTypeRef}; use crate::convert::ToPyObject; use crate::function::FuncArgs; use crate::stdlib::ctypes::PyCData; -use crate::stdlib::ctypes::array::PyCArray; use crate::stdlib::ctypes::base::{PyCSimple, ffi_type_from_str}; +use crate::types::Representable; use crate::types::{Callable, Constructor}; -use crate::{Py, PyObjectRef, PyResult, VirtualMachine}; +use crate::{AsObject, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine}; use crossbeam_utils::atomic::AtomicCell; use libffi::middle::{Arg, Cif, CodePtr, Type}; use libloading::Symbol; use num_traits::ToPrimitive; use rustpython_common::lock::PyRwLock; -use std::ffi::CString; +use std::ffi::{self, CString, c_void}; use std::fmt::Debug; -// https://github.com/python/cpython/blob/4f8bb3947cfbc20f970ff9d9531e1132a9e95396/Modules/_ctypes/callproc.c#L15 +// See also: https://github.com/python/cpython/blob/4f8bb3947cfbc20f970ff9d9531e1132a9e95396/Modules/_ctypes/callproc.c#L15 -#[derive(Debug)] -pub struct Function { - args: Vec, - // TODO: no protection from use-after-free - pointer: CodePtr, - cif: Cif, +type FP = unsafe extern "C" fn(); + +pub trait ArgumentType { + fn to_ffi_type(&self, vm: &VirtualMachine) -> PyResult; + fn convert_object(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult; } -unsafe impl Send for Function {} -unsafe impl Sync for Function {} +impl ArgumentType for PyTypeRef { + fn to_ffi_type(&self, vm: &VirtualMachine) -> PyResult { + let typ = self + .get_class_attr(vm.ctx.intern_str("_type_")) + .ok_or(vm.new_type_error("Unsupported argument type".to_string()))?; + let typ = typ + .downcast_ref::() + .ok_or(vm.new_type_error("Unsupported argument type".to_string()))?; + let typ = typ.to_string(); + let typ = typ.as_str(); + let converted_typ = ffi_type_from_str(typ); + if let Some(typ) = converted_typ { + Ok(typ) + } else { + Err(vm.new_type_error(format!("Unsupported argument type: {}", typ))) + } + } -type FP = unsafe extern "C" fn(); + fn convert_object(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult { + // if self.fast_isinstance::(vm) { + // let array = value.downcast::()?; + // return Ok(Arg::from(array.as_ptr())); + // } + if let Ok(simple) = value.downcast::() { + let typ = ArgumentType::to_ffi_type(self, vm)?; + let arg = simple + .to_arg(typ, vm) + .ok_or(vm.new_type_error("Unsupported argument type".to_string()))?; + return Ok(arg); + } + Err(vm.new_type_error("Unsupported argument type".to_string())) + } +} -impl Function { - pub unsafe fn load( - library: &libloading::Library, - function: &str, - args: &[PyObjectRef], - ret_type: &Option, +pub trait ReturnType { + fn to_ffi_type(&self) -> Option; + fn from_ffi_type( + &self, + value: *mut ffi::c_void, vm: &VirtualMachine, - ) -> PyResult { - // map each arg to a PyCSimple - let args = args - .iter() - .map(|arg| { - if let Some(arg) = arg.downcast_ref::() { - let converted = ffi_type_from_str(&arg._type_); - return match converted { - Some(t) => Ok(t), - None => Err(vm.new_type_error("Invalid type")), // TODO: add type name - }; - } - if let Some(arg) = arg.downcast_ref::() { - let t = arg.typ.read(); - let ty_attributes = t.attributes.read(); - let ty_pystr = ty_attributes - .get(vm.ctx.intern_str("_type_")) - .ok_or_else(|| vm.new_type_error("Expected a ctypes simple type"))?; - let ty_str = ty_pystr - .downcast_ref::() - .ok_or_else(|| vm.new_type_error("Expected a ctypes simple type"))? - .to_string(); - let converted = ffi_type_from_str(&ty_str); - match converted { - Some(_t) => { - // TODO: Use - Ok(Type::void()) - } - None => Err(vm.new_type_error("Invalid type")), // TODO: add type name - } - } else { - Err(vm.new_type_error("Expected a ctypes simple type")) - } - }) - .collect::>>()?; - let c_function_name = CString::new(function) - .map_err(|_| vm.new_value_error("Function name contains null bytes"))?; - let pointer: Symbol<'_, FP> = unsafe { - library - .get(c_function_name.as_bytes()) - .map_err(|err| err.to_string()) - .map_err(|err| vm.new_attribute_error(err))? - }; - let code_ptr = CodePtr(*pointer as *mut _); - let return_type = match ret_type { - // TODO: Fix this - Some(_t) => { - return Err(vm.new_not_implemented_error("Return type not implemented")); - } - None => Type::c_int(), - }; - let cif = Cif::new(args.clone(), return_type); - Ok(Function { - args, - cif, - pointer: code_ptr, - }) + ) -> PyResult>; +} + +impl ReturnType for PyTypeRef { + fn to_ffi_type(&self) -> Option { + ffi_type_from_str(self.name().to_string().as_str()) } - pub unsafe fn call( + fn from_ffi_type( &self, - args: Vec, - vm: &VirtualMachine, - ) -> PyResult { - let args = args - .into_iter() - .enumerate() - .map(|(count, arg)| { - // none type check - if let Some(d) = arg.downcast_ref::() { - return Ok(d.to_arg(self.args[count].clone(), vm).unwrap()); - } - if let Some(d) = arg.downcast_ref::() { - return Ok(d.to_arg(vm).unwrap()); - } - Err(vm.new_type_error("Expected a ctypes simple type")) - }) - .collect::>>()?; - // TODO: FIX return - let result: i32 = unsafe { self.cif.call(self.pointer, &args) }; - Ok(vm.ctx.new_int(result).into()) + _value: *mut ffi::c_void, + _vm: &VirtualMachine, + ) -> PyResult> { + todo!() + } +} + +impl ReturnType for PyNone { + fn to_ffi_type(&self) -> Option { + ffi_type_from_str("void") + } + + fn from_ffi_type( + &self, + _value: *mut ffi::c_void, + _vm: &VirtualMachine, + ) -> PyResult> { + Ok(None) } } #[pyclass(module = "_ctypes", name = "CFuncPtr", base = PyCData)] #[derive(PyPayload)] pub struct PyCFuncPtr { - pub name: PyRwLock, - pub _flags_: AtomicCell, - // FIXME(arihant2math): This shouldn't be an option, setting the default as the none type should work - // This is a workaround for now and I'll fix it later - pub _restype_: PyRwLock>, + pub name: PyRwLock>, + pub ptr: PyRwLock>, + pub needs_free: AtomicCell, + pub arg_types: PyRwLock>>, + pub res_type: PyRwLock>, + pub _flags_: AtomicCell, pub handler: PyObjectRef, } impl Debug for PyCFuncPtr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("PyCFuncPtr") - .field("name", &self.name) + .field("flags", &self._flags_) .finish() } } @@ -156,10 +131,43 @@ impl Constructor for PyCFuncPtr { .nth(1) .ok_or(vm.new_type_error("Expected a tuple with at least 2 elements"))? .clone(); + let handle = handler.try_int(vm); + let handle = match handle { + Ok(handle) => handle.as_bigint().clone(), + Err(_) => handler + .get_attr("_handle", vm)? + .try_int(vm)? + .as_bigint() + .clone(), + }; + let library_cache = crate::stdlib::ctypes::library::libcache().read(); + let library = library_cache + .get_lib( + handle + .to_usize() + .ok_or(vm.new_value_error("Invalid handle".to_string()))?, + ) + .ok_or_else(|| vm.new_value_error("Library not found".to_string()))?; + let inner_lib = library.lib.lock(); + + let terminated = format!("{}\0", &name); + let code_ptr = if let Some(lib) = &*inner_lib { + let pointer: Symbol<'_, FP> = unsafe { + lib.get(terminated.as_bytes()) + .map_err(|err| err.to_string()) + .map_err(|err| vm.new_attribute_error(err))? + }; + Some(CodePtr(*pointer as *mut _)) + } else { + None + }; Ok(Self { + ptr: PyRwLock::new(code_ptr), + needs_free: AtomicCell::new(false), + arg_types: PyRwLock::new(None), _flags_: AtomicCell::new(0), - name: PyRwLock::new(name), - _restype_: PyRwLock::new(None), + res_type: PyRwLock::new(None), + name: PyRwLock::new(Some(name)), handler, } .to_pyobject(vm)) @@ -169,53 +177,145 @@ impl Constructor for PyCFuncPtr { impl Callable for PyCFuncPtr { type Args = FuncArgs; fn call(zelf: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { - unsafe { - let handle = zelf.handler.get_attr("_handle", vm)?; - let handle = handle.try_int(vm)?.as_bigint().clone(); - let library_cache = crate::stdlib::ctypes::library::libcache().read(); - let library = library_cache - .get_lib( - handle - .to_usize() - .ok_or(vm.new_value_error("Invalid handle"))?, - ) - .ok_or_else(|| vm.new_value_error("Library not found"))?; - let inner_lib = library.lib.lock(); - let name = zelf.name.read(); - let res_type = zelf._restype_.read(); - let func = Function::load( - inner_lib - .as_ref() - .ok_or_else(|| vm.new_value_error("Library not found"))?, - &name, - &args.args, - &res_type, - vm, - )?; - func.call(args.args, vm) + // This is completely seperate from the C python implementation + + // Cif init + let arg_types: Vec<_> = match zelf.arg_types.read().clone() { + Some(tys) => tys, + None => args + .args + .clone() + .into_iter() + .map(|a| a.class().as_object().to_pyobject(vm).downcast().unwrap()) + .collect(), + }; + let ffi_arg_types = arg_types + .clone() + .iter() + .map(|t| ArgumentType::to_ffi_type(t, vm)) + .collect::>>()?; + let return_type = zelf.res_type.read(); + let ffi_return_type = return_type + .as_ref() + .map(|t| ReturnType::to_ffi_type(&t.clone().downcast::().unwrap())) + .flatten() + .unwrap_or_else(|| Type::i32()); + let cif = Cif::new(ffi_arg_types, ffi_return_type); + + // Call the function + let ffi_args = args + .args + .into_iter() + .enumerate() + .map(|(n, arg)| { + let arg_type = arg_types + .get(n) + .ok_or_else(|| vm.new_type_error("argument amount mismatch".to_string()))?; + arg_type.convert_object(arg, vm) + }) + .collect::, _>>()?; + let pointer = zelf.ptr.read(); + let code_ptr = pointer + .as_ref() + .ok_or_else(|| vm.new_type_error("Function pointer not set".to_string()))?; + let mut output: c_void = unsafe { cif.call(*code_ptr, &ffi_args) }; + let return_type = return_type + .as_ref() + .map(|f| { + f.clone() + .downcast::() + .unwrap() + .from_ffi_type(&mut output, vm) + .ok() + .flatten() + }) + .unwrap_or_else(|| Some(vm.ctx.new_int(output as i32).as_object().to_pyobject(vm))); + if let Some(return_type) = return_type { + Ok(return_type) + } else { + Ok(vm.ctx.none()) } } } -#[pyclass(flags(BASETYPE), with(Callable, Constructor))] -impl PyCFuncPtr { - #[pygetset] - fn __name__(&self) -> String { - self.name.read().clone() +impl Representable for PyCFuncPtr { + fn repr_str(zelf: &Py, _vm: &VirtualMachine) -> PyResult { + let index = zelf.ptr.read(); + let index = index.map(|ptr| ptr.0 as usize).unwrap_or(0); + let type_name = zelf.class().name(); + #[cfg(windows)] + { + let index = index - 0x1000; + return Ok(format!("")); + } + Ok(format!("<{type_name} object at {index:#x}>")) } +} - #[pygetset(setter)] - fn set___name__(&self, name: String) { - *self.name.write() = name; - } +// TODO: fix +unsafe impl Send for PyCFuncPtr {} +unsafe impl Sync for PyCFuncPtr {} +#[pyclass(flags(BASETYPE), with(Callable, Constructor, Representable))] +impl PyCFuncPtr { #[pygetset(name = "_restype_")] - fn restype(&self) -> Option { - self._restype_.read().as_ref().cloned() + fn restype(&self) -> Option { + self.res_type.read().as_ref().cloned() } #[pygetset(name = "_restype_", setter)] - fn set_restype(&self, restype: PyTypeRef) { - *self._restype_.write() = Some(restype); + fn set_restype(&self, restype: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { + // has to be type, callable, or none + // TODO: Callable support + if vm.is_none(&restype) || restype.downcast_ref::().is_some() { + *self.res_type.write() = Some(restype); + Ok(()) + } else { + Err(vm.new_type_error("restype must be a type, a callable, or None".to_string())) + } + } + + #[pygetset(name = "argtypes")] + fn argtypes(&self, vm: &VirtualMachine) -> PyTupleRef { + PyTuple::new_ref( + self.arg_types + .read() + .clone() + .unwrap_or_default() + .into_iter() + .map(|t| t.to_pyobject(vm)) + .collect(), + &vm.ctx, + ) + } + + #[pygetset(name = "argtypes", setter)] + fn set_argtypes(&self, argtypes: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { + let none = vm.is_none(&argtypes); + if none { + *self.arg_types.write() = None; + Ok(()) + } else { + let tuple = argtypes.downcast::().unwrap(); + *self.arg_types.write() = Some( + tuple + .iter() + .map(|obj| obj.clone().downcast::().unwrap()) + .collect::>(), + ); + Ok(()) + } + } + + #[pygetset] + fn __name__(&self) -> Option { + self.name.read().clone() + } + + #[pygetset(setter)] + fn set___name__(&self, name: String) -> PyResult<()> { + *self.name.write() = Some(name); + // TODO: update handle and stuff + Ok(()) } } diff --git a/crates/vm/src/stdlib/ctypes/pointer.rs b/crates/vm/src/stdlib/ctypes/pointer.rs index d1360f9862..e072312562 100644 --- a/crates/vm/src/stdlib/ctypes/pointer.rs +++ b/crates/vm/src/stdlib/ctypes/pointer.rs @@ -1,5 +1,40 @@ -#[pyclass(name = "Pointer", module = "_ctypes")] -pub struct PyCPointer {} +use rustpython_common::lock::PyRwLock; + +use crate::builtins::PyType; +use crate::stdlib::ctypes::PyCData; +use crate::{PyObjectRef, PyResult}; + +#[pyclass(name = "PyCPointerType", base = PyType, module = "_ctypes")] +#[derive(PyPayload, Debug)] +pub struct PyCPointerType { + pub inner: PyCPointer, +} + +#[pyclass] +impl PyCPointerType {} + +#[pyclass( + name = "_Pointer", + base = PyCData, + metaclass = "PyCPointerType", + module = "_ctypes" +)] +#[derive(Debug, PyPayload)] +pub struct PyCPointer { + contents: PyRwLock, +} #[pyclass(flags(BASETYPE, IMMUTABLETYPE))] -impl PyCPointer {} +impl PyCPointer { + // TODO: not correct + #[pygetset] + fn contents(&self) -> PyResult { + let contents = self.contents.read().clone(); + Ok(contents) + } + #[pygetset(setter)] + fn set_contents(&self, contents: PyObjectRef) -> PyResult<()> { + *self.contents.write() = contents; + Ok(()) + } +} diff --git a/crates/vm/src/stdlib/ctypes/thunk.rs b/crates/vm/src/stdlib/ctypes/thunk.rs new file mode 100644 index 0000000000..a65b04684b --- /dev/null +++ b/crates/vm/src/stdlib/ctypes/thunk.rs @@ -0,0 +1,22 @@ +//! Yes, really, this is not a typo. + +// typedef struct { +// PyObject_VAR_HEAD +// ffi_closure *pcl_write; /* the C callable, writeable */ +// void *pcl_exec; /* the C callable, executable */ +// ffi_cif cif; +// int flags; +// PyObject *converters; +// PyObject *callable; +// PyObject *restype; +// SETFUNC setfunc; +// ffi_type *ffi_restype; +// ffi_type *atypes[1]; +// } CThunkObject; + +#[pyclass(name = "CThunkObject", module = "_ctypes")] +#[derive(Debug, PyPayload)] +pub struct PyCThunk {} + +#[pyclass] +impl PyCThunk {} diff --git a/crates/vm/src/stdlib/ctypes/util.rs b/crates/vm/src/stdlib/ctypes/util.rs new file mode 100644 index 0000000000..df5d318668 --- /dev/null +++ b/crates/vm/src/stdlib/ctypes/util.rs @@ -0,0 +1,24 @@ +use crate::PyObjectRef; + +#[pyclass(name, module = "_ctypes")] +#[derive(Debug, PyPayload)] +pub struct StgInfo { + pub initialized: i32, + pub size: usize, // number of bytes + pub align: usize, // alignment requirements + pub length: usize, // number of fields + // ffi_type_pointer: ffi::ffi_type, + pub proto: PyObjectRef, // Only for Pointer/ArrayObject + pub setfunc: Option, // Only for simple objects + pub getfunc: Option, // Only for simple objects + pub paramfunc: Option, + + /* Following fields only used by PyCFuncPtrType_Type instances */ + pub argtypes: Option, // tuple of CDataObjects + pub converters: Option, // tuple([t.from_param for t in argtypes]) + pub restype: Option, // CDataObject or NULL + pub checker: Option, + pub module: Option, + pub flags: i32, // calling convention and such + pub dict_final: u8, +} diff --git a/extra_tests/snippets/stdlib_ctypes.py b/extra_tests/snippets/stdlib_ctypes.py index 32ed17d19f..3ef6df689f 100644 --- a/extra_tests/snippets/stdlib_ctypes.py +++ b/extra_tests/snippets/stdlib_ctypes.py @@ -40,7 +40,6 @@ def create_string_buffer(init, size=None): size = len(init) + 1 _sys.audit("ctypes.create_string_buffer", init, size) buftype = c_char.__mul__(size) - print(type(c_char.__mul__(size))) # buftype = c_char * size buf = buftype() buf.value = init @@ -334,8 +333,14 @@ def LoadLibrary(self, name): test_byte_array = create_string_buffer(b"Hello, World!\n") assert test_byte_array._length_ == 15 -if _os.name == "posix" or _sys.platform == "darwin": - pass +if _os.name == "posix": + if _sys.platform == "darwin": + libc = cdll.LoadLibrary("libc.dylib") + libc.rand() + i = c_int(1) + print("start srand") + print(libc.srand(i)) + print(test_byte_array) else: import os From 14cf4e32d04b234549fae3ae0dddb0b34a09f76a Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 28 Nov 2025 23:41:42 +0900 Subject: [PATCH 013/577] Fix PyCSimple --- crates/vm/src/stdlib/ctypes/base.rs | 5 +++-- crates/vm/src/stdlib/ctypes/field.rs | 2 +- crates/vm/src/stdlib/ctypes/function.rs | 16 ++++++++-------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/crates/vm/src/stdlib/ctypes/base.rs b/crates/vm/src/stdlib/ctypes/base.rs index f5a25ad740..1b07d73f8d 100644 --- a/crates/vm/src/stdlib/ctypes/base.rs +++ b/crates/vm/src/stdlib/ctypes/base.rs @@ -218,11 +218,12 @@ impl Constructor for PyCSimple { _ => vm.ctx.none(), // "z" | "Z" | "P" } }; - Ok(PyCSimple { + PyCSimple { _type_, value: AtomicCell::new(value), } - .to_pyobject(vm)) + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/crates/vm/src/stdlib/ctypes/field.rs b/crates/vm/src/stdlib/ctypes/field.rs index b50b8b54ac..20aded85a7 100644 --- a/crates/vm/src/stdlib/ctypes/field.rs +++ b/crates/vm/src/stdlib/ctypes/field.rs @@ -36,7 +36,7 @@ pub struct PyCField { impl Representable for PyCField { fn repr_str(zelf: &Py, _vm: &VirtualMachine) -> PyResult { let tp_name = zelf.proto.name().to_string(); - if zelf.bitfield_size != false { + if zelf.bitfield_size { Ok(format!( "<{} type={}, ofs={byte_offset}, bit_size={bitfield_size}, bit_offset={bit_offset}", zelf.name, diff --git a/crates/vm/src/stdlib/ctypes/function.rs b/crates/vm/src/stdlib/ctypes/function.rs index 88d0fbb35e..bb4cc65212 100644 --- a/crates/vm/src/stdlib/ctypes/function.rs +++ b/crates/vm/src/stdlib/ctypes/function.rs @@ -13,7 +13,7 @@ use libffi::middle::{Arg, Cif, CodePtr, Type}; use libloading::Symbol; use num_traits::ToPrimitive; use rustpython_common::lock::PyRwLock; -use std::ffi::{self, CString, c_void}; +use std::ffi::{self, c_void}; use std::fmt::Debug; // See also: https://github.com/python/cpython/blob/4f8bb3947cfbc20f970ff9d9531e1132a9e95396/Modules/_ctypes/callproc.c#L15 @@ -61,6 +61,7 @@ impl ArgumentType for PyTypeRef { pub trait ReturnType { fn to_ffi_type(&self) -> Option; + #[allow(clippy::wrong_self_convention)] fn from_ffi_type( &self, value: *mut ffi::c_void, @@ -197,9 +198,8 @@ impl Callable for PyCFuncPtr { let return_type = zelf.res_type.read(); let ffi_return_type = return_type .as_ref() - .map(|t| ReturnType::to_ffi_type(&t.clone().downcast::().unwrap())) - .flatten() - .unwrap_or_else(|| Type::i32()); + .and_then(|t| ReturnType::to_ffi_type(&t.clone().downcast::().unwrap())) + .unwrap_or_else(Type::i32); let cif = Cif::new(ffi_arg_types, ffi_return_type); // Call the function @@ -243,12 +243,12 @@ impl Representable for PyCFuncPtr { let index = zelf.ptr.read(); let index = index.map(|ptr| ptr.0 as usize).unwrap_or(0); let type_name = zelf.class().name(); - #[cfg(windows)] - { + if cfg!(windows) { let index = index - 0x1000; - return Ok(format!("")); + Ok(format!("")) + } else { + Ok(format!("<{type_name} object at {index:#x}>")) } - Ok(format!("<{type_name} object at {index:#x}>")) } } From 8af105fc4ff5f5eb8e9a534b826b27ec47a6a576 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 28 Nov 2025 23:46:14 +0900 Subject: [PATCH 014/577] Make mergeable --- crates/vm/src/stdlib/ctypes.rs | 1 - crates/vm/src/stdlib/ctypes/field.rs | 11 +---------- crates/vm/src/stdlib/ctypes/function.rs | 2 ++ crates/vm/src/stdlib/ctypes/pointer.rs | 3 ++- crates/vm/src/stdlib/ctypes/util.rs | 24 ------------------------ extra_tests/snippets/stdlib_ctypes.py | 12 ++++++------ 6 files changed, 11 insertions(+), 42 deletions(-) delete mode 100644 crates/vm/src/stdlib/ctypes/util.rs diff --git a/crates/vm/src/stdlib/ctypes.rs b/crates/vm/src/stdlib/ctypes.rs index ac74418354..92629dcadb 100644 --- a/crates/vm/src/stdlib/ctypes.rs +++ b/crates/vm/src/stdlib/ctypes.rs @@ -9,7 +9,6 @@ pub(crate) mod pointer; pub(crate) mod structure; pub(crate) mod thunk; pub(crate) mod union; -pub(crate) mod util; use crate::builtins::PyModule; use crate::class::PyClassImpl; diff --git a/crates/vm/src/stdlib/ctypes/field.rs b/crates/vm/src/stdlib/ctypes/field.rs index 20aded85a7..e4e3bd6a09 100644 --- a/crates/vm/src/stdlib/ctypes/field.rs +++ b/crates/vm/src/stdlib/ctypes/field.rs @@ -8,6 +8,7 @@ use crate::{Py, PyResult, VirtualMachine}; #[pyclass(name = "PyCFieldType", base = PyType, module = "_ctypes")] #[derive(PyPayload, Debug)] pub struct PyCFieldType { + #[allow(dead_code)] pub(super) inner: PyCField, } @@ -122,13 +123,3 @@ impl PyCField { self.bit_offset } } - -#[inline(always)] -pub const fn low_bit(offset: usize) -> usize { - offset & 0xFFFF -} - -#[inline(always)] -pub const fn high_bit(offset: usize) -> usize { - offset >> 16 -} diff --git a/crates/vm/src/stdlib/ctypes/function.rs b/crates/vm/src/stdlib/ctypes/function.rs index bb4cc65212..64a230ad56 100644 --- a/crates/vm/src/stdlib/ctypes/function.rs +++ b/crates/vm/src/stdlib/ctypes/function.rs @@ -102,10 +102,12 @@ impl ReturnType for PyNone { pub struct PyCFuncPtr { pub name: PyRwLock>, pub ptr: PyRwLock>, + #[allow(dead_code)] pub needs_free: AtomicCell, pub arg_types: PyRwLock>>, pub res_type: PyRwLock>, pub _flags_: AtomicCell, + #[allow(dead_code)] pub handler: PyObjectRef, } diff --git a/crates/vm/src/stdlib/ctypes/pointer.rs b/crates/vm/src/stdlib/ctypes/pointer.rs index e072312562..b60280c73c 100644 --- a/crates/vm/src/stdlib/ctypes/pointer.rs +++ b/crates/vm/src/stdlib/ctypes/pointer.rs @@ -7,7 +7,8 @@ use crate::{PyObjectRef, PyResult}; #[pyclass(name = "PyCPointerType", base = PyType, module = "_ctypes")] #[derive(PyPayload, Debug)] pub struct PyCPointerType { - pub inner: PyCPointer, + #[allow(dead_code)] + pub(crate) inner: PyCPointer, } #[pyclass] diff --git a/crates/vm/src/stdlib/ctypes/util.rs b/crates/vm/src/stdlib/ctypes/util.rs deleted file mode 100644 index df5d318668..0000000000 --- a/crates/vm/src/stdlib/ctypes/util.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::PyObjectRef; - -#[pyclass(name, module = "_ctypes")] -#[derive(Debug, PyPayload)] -pub struct StgInfo { - pub initialized: i32, - pub size: usize, // number of bytes - pub align: usize, // alignment requirements - pub length: usize, // number of fields - // ffi_type_pointer: ffi::ffi_type, - pub proto: PyObjectRef, // Only for Pointer/ArrayObject - pub setfunc: Option, // Only for simple objects - pub getfunc: Option, // Only for simple objects - pub paramfunc: Option, - - /* Following fields only used by PyCFuncPtrType_Type instances */ - pub argtypes: Option, // tuple of CDataObjects - pub converters: Option, // tuple([t.from_param for t in argtypes]) - pub restype: Option, // CDataObject or NULL - pub checker: Option, - pub module: Option, - pub flags: i32, // calling convention and such - pub dict_final: u8, -} diff --git a/extra_tests/snippets/stdlib_ctypes.py b/extra_tests/snippets/stdlib_ctypes.py index 3ef6df689f..b4bc05dcb4 100644 --- a/extra_tests/snippets/stdlib_ctypes.py +++ b/extra_tests/snippets/stdlib_ctypes.py @@ -338,9 +338,9 @@ def LoadLibrary(self, name): libc = cdll.LoadLibrary("libc.dylib") libc.rand() i = c_int(1) - print("start srand") - print(libc.srand(i)) - print(test_byte_array) + # print("start srand") + # print(libc.srand(i)) + # print(test_byte_array) else: import os @@ -348,9 +348,9 @@ def LoadLibrary(self, name): libc.rand() i = c_int(1) print("start srand") - print(libc.srand(i)) - print(test_byte_array) - print(test_byte_array._type_) + # print(libc.srand(i)) + # print(test_byte_array) + # print(test_byte_array._type_) # print("start printf") # libc.printf(test_byte_array) From fef9de22c4d31eb062073ba4752aa5a8ed18ad45 Mon Sep 17 00:00:00 2001 From: Shahar Naveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 28 Nov 2025 17:46:27 +0200 Subject: [PATCH 015/577] Remove `Rotate*` & `Duplicate*` instructions (#6303) * Remove `Instruction::Duplicate2?` * Remove `Instruction::Rotate*` instructions * Fix jit * Update snapshot --- crates/codegen/src/compile.rs | 38 +++++++++-------- ...pile__tests__nested_double_async_with.snap | 2 +- crates/compiler-core/src/bytecode.rs | 11 ----- crates/jit/tests/common.rs | 12 ------ crates/vm/src/frame.rs | 41 ++++--------------- 5 files changed, 30 insertions(+), 74 deletions(-) diff --git a/crates/codegen/src/compile.rs b/crates/codegen/src/compile.rs index 5f8caebf27..b2dc10cda6 100644 --- a/crates/codegen/src/compile.rs +++ b/crates/codegen/src/compile.rs @@ -1063,7 +1063,7 @@ impl Compiler { if let Stmt::Expr(StmtExpr { value, .. }) = &last { self.compile_expression(value)?; - emit!(self, Instruction::Duplicate); + emit!(self, Instruction::CopyItem { index: 1_u32 }); emit!(self, Instruction::PrintExpr); } else { self.compile_statement(last)?; @@ -1094,7 +1094,7 @@ impl Compiler { Stmt::FunctionDef(_) | Stmt::ClassDef(_) => { let pop_instructions = self.current_block().instructions.pop(); let store_inst = compiler_unwrap_option(self, pop_instructions); // pop Instruction::Store - emit!(self, Instruction::Duplicate); + emit!(self, Instruction::CopyItem { index: 1_u32 }); self.current_block().instructions.push(store_inst); } _ => self.emit_load_const(ConstantData::None), @@ -1656,7 +1656,7 @@ impl Compiler { for (i, target) in targets.iter().enumerate() { if i + 1 != targets.len() { - emit!(self, Instruction::Duplicate); + emit!(self, Instruction::CopyItem { index: 1_u32 }); } self.compile_store(target)?; } @@ -1917,7 +1917,7 @@ impl Compiler { ); } - emit!(self, Instruction::Duplicate); + emit!(self, Instruction::CopyItem { index: 1_u32 }); self.store_name(name.as_ref())?; } TypeParam::ParamSpec(TypeParamParamSpec { name, default, .. }) => { @@ -1943,7 +1943,7 @@ impl Compiler { ); } - emit!(self, Instruction::Duplicate); + emit!(self, Instruction::CopyItem { index: 1_u32 }); self.store_name(name.as_ref())?; } TypeParam::TypeVarTuple(TypeParamTypeVarTuple { name, default, .. }) => { @@ -1970,7 +1970,7 @@ impl Compiler { ); } - emit!(self, Instruction::Duplicate); + emit!(self, Instruction::CopyItem { index: 1_u32 }); self.store_name(name.as_ref())?; } }; @@ -2030,7 +2030,7 @@ impl Compiler { // check if this handler can handle the exception: if let Some(exc_type) = type_ { // Duplicate exception for test: - emit!(self, Instruction::Duplicate); + emit!(self, Instruction::CopyItem { index: 1_u32 }); // Check exception type: self.compile_expression(exc_type)?; @@ -2251,11 +2251,11 @@ impl Compiler { // Handle docstring if present if let Some(doc) = doc_str { - emit!(self, Instruction::Duplicate); + emit!(self, Instruction::CopyItem { index: 1_u32 }); self.emit_load_const(ConstantData::Str { value: doc.to_string().into(), }); - emit!(self, Instruction::Rotate2); + emit!(self, Instruction::Swap { index: 2 }); let doc_attr = self.name("__doc__"); emit!(self, Instruction::StoreAttr { idx: doc_attr }); } @@ -2726,7 +2726,7 @@ impl Compiler { if let Some(classcell_idx) = classcell_idx { emit!(self, Instruction::LoadClosure(classcell_idx.to_u32())); - emit!(self, Instruction::Duplicate); + emit!(self, Instruction::CopyItem { index: 1_u32 }); let classcell = self.name("__classcell__"); emit!(self, Instruction::StoreLocal(classcell)); } else { @@ -4121,8 +4121,8 @@ impl Compiler { for (op, val) in mid_ops.iter().zip(mid_exprs) { self.compile_expression(val)?; // store rhs for the next comparison in chain - emit!(self, Instruction::Duplicate); - emit!(self, Instruction::Rotate3); + emit!(self, Instruction::Swap { index: 2 }); + emit!(self, Instruction::CopyItem { index: 2_u32 }); compile_cmpop(self, op); @@ -4151,7 +4151,7 @@ impl Compiler { // early exit left us with stack: `rhs, comparison_result`. We need to clean up rhs. self.switch_to_block(break_block); - emit!(self, Instruction::Rotate2); + emit!(self, Instruction::Swap { index: 2 }); emit!(self, Instruction::Pop); self.switch_to_block(after_block); @@ -4322,7 +4322,8 @@ impl Compiler { // But we can't use compile_subscript directly because we need DUP_TOP2 self.compile_expression(value)?; self.compile_expression(slice)?; - emit!(self, Instruction::Duplicate2); + emit!(self, Instruction::CopyItem { index: 2_u32 }); + emit!(self, Instruction::CopyItem { index: 2_u32 }); emit!(self, Instruction::Subscript); AugAssignKind::Subscript } @@ -4330,7 +4331,7 @@ impl Compiler { let attr = attr.as_str(); self.check_forbidden_name(attr, NameUsage::Store)?; self.compile_expression(value)?; - emit!(self, Instruction::Duplicate); + emit!(self, Instruction::CopyItem { index: 1_u32 }); let idx = self.name(attr); emit!(self, Instruction::LoadAttr { idx }); AugAssignKind::Attr { idx } @@ -4350,12 +4351,13 @@ impl Compiler { } AugAssignKind::Subscript => { // stack: CONTAINER SLICE RESULT - emit!(self, Instruction::Rotate3); + emit!(self, Instruction::Swap { index: 3 }); + emit!(self, Instruction::Swap { index: 2 }); emit!(self, Instruction::StoreSubscript); } AugAssignKind::Attr { idx } => { // stack: CONTAINER RESULT - emit!(self, Instruction::Rotate2); + emit!(self, Instruction::Swap { index: 2 }); emit!(self, Instruction::StoreAttr { idx }); } } @@ -4896,7 +4898,7 @@ impl Compiler { range: _, }) => { self.compile_expression(value)?; - emit!(self, Instruction::Duplicate); + emit!(self, Instruction::CopyItem { index: 1_u32 }); self.compile_store(target)?; } Expr::FString(fstring) => { diff --git a/crates/codegen/src/snapshots/rustpython_codegen__compile__tests__nested_double_async_with.snap b/crates/codegen/src/snapshots/rustpython_codegen__compile__tests__nested_double_async_with.snap index 82c02d5ea3..dc624c7b6a 100644 --- a/crates/codegen/src/snapshots/rustpython_codegen__compile__tests__nested_double_async_with.snap +++ b/crates/codegen/src/snapshots/rustpython_codegen__compile__tests__nested_double_async_with.snap @@ -49,7 +49,7 @@ expression: "compile_exec(\"\\\nfor stop_exc in (StopIteration('spam'), StopAsyn 39 WithCleanupFinish 40 PopBlock 41 Jump (59) - >> 42 Duplicate + >> 42 CopyItem (1) 6 43 LoadNameAny (7, Exception) 44 TestOperation (ExceptionMatch) diff --git a/crates/compiler-core/src/bytecode.rs b/crates/compiler-core/src/bytecode.rs index 2cfb70e278..fe28517cda 100644 --- a/crates/compiler-core/src/bytecode.rs +++ b/crates/compiler-core/src/bytecode.rs @@ -614,10 +614,6 @@ pub enum Instruction { index: Arg, }, ToBool, - Rotate2, - Rotate3, - Duplicate, - Duplicate2, GetIter, GetLen, CallIntrinsic1 { @@ -1475,9 +1471,6 @@ impl Instruction { Pop => -1, Swap { .. } => 0, ToBool => 0, - Rotate2 | Rotate3 => 0, - Duplicate => 1, - Duplicate2 => 2, GetIter => 0, GetLen => 1, CallIntrinsic1 { .. } => 0, // Takes 1, pushes 1 @@ -1678,10 +1671,6 @@ impl Instruction { Pop => w!(Pop), Swap { index } => w!(Swap, index), ToBool => w!(ToBool), - Rotate2 => w!(Rotate2), - Rotate3 => w!(Rotate3), - Duplicate => w!(Duplicate), - Duplicate2 => w!(Duplicate2), GetIter => w!(GetIter), // GET_LEN GetLen => w!(GetLen), diff --git a/crates/jit/tests/common.rs b/crates/jit/tests/common.rs index a88d3207f2..5dafeaeb80 100644 --- a/crates/jit/tests/common.rs +++ b/crates/jit/tests/common.rs @@ -164,18 +164,6 @@ impl StackMachine { self.stack.push(StackValue::Function(func)); } } - Instruction::Duplicate => { - let value = self.stack.last().unwrap().clone(); - self.stack.push(value); - } - Instruction::Rotate2 => { - let i = self.stack.len() - 2; - self.stack[i..].rotate_right(1); - } - Instruction::Rotate3 => { - let i = self.stack.len() - 3; - self.stack[i..].rotate_right(1); - } Instruction::ReturnConst { idx } => { let idx = idx.get(arg); self.stack.push(constants[idx as usize].clone().into()); diff --git a/crates/vm/src/frame.rs b/crates/vm/src/frame.rs index ab90f52b2d..8deaada082 100644 --- a/crates/vm/src/frame.rs +++ b/crates/vm/src/frame.rs @@ -719,32 +719,16 @@ impl ExecutingFrame<'_> { self.state.stack.swap(i, j); Ok(None) } - // bytecode::Instruction::ToBool => { - // dbg!("Shouldn't be called outside of match statements for now") - // let value = self.pop_value(); - // // call __bool__ - // let result = value.try_to_bool(vm)?; - // self.push_value(vm.ctx.new_bool(result).into()); - // Ok(None) - // } - bytecode::Instruction::Duplicate => { - // Duplicate top of stack - let value = self.top_value(); - self.push_value(value.to_owned()); - Ok(None) - } - bytecode::Instruction::Duplicate2 => { - // Duplicate top 2 of stack - let len = self.state.stack.len(); - self.push_value(self.state.stack[len - 2].clone()); - self.push_value(self.state.stack[len - 1].clone()); - Ok(None) + /* + bytecode::Instruction::ToBool => { + dbg!("Shouldn't be called outside of match statements for now") + let value = self.pop_value(); + // call __bool__ + let result = value.try_to_bool(vm)?; + self.push_value(vm.ctx.new_bool(result).into()); + Ok(None) } - // splitting the instructions like this offloads the cost of "dynamic" dispatch (on the - // amount to rotate) to the opcode dispatcher, and generates optimized code for the - // concrete cases we actually have - bytecode::Instruction::Rotate2 => self.execute_rotate(2), - bytecode::Instruction::Rotate3 => self.execute_rotate(3), + */ bytecode::Instruction::BuildString { size } => { let s = self .pop_multiple(size.get(arg) as usize) @@ -1685,13 +1669,6 @@ impl ExecutingFrame<'_> { } } - #[inline(always)] - fn execute_rotate(&mut self, amount: usize) -> FrameResult { - let i = self.state.stack.len() - amount; - self.state.stack[i..].rotate_right(1); - Ok(None) - } - fn execute_subscript(&mut self, vm: &VirtualMachine) -> FrameResult { let b_ref = self.pop_value(); let a_ref = self.pop_value(); From 23ec5a55adc7053a105235cd2dfe6ee078c9e712 Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" <69878+youknowone@users.noreply.github.com> Date: Sat, 29 Nov 2025 01:32:52 +0900 Subject: [PATCH 016/577] Fix import ctypes and Lib/ctypes/__init__.py from cpython3.13.9 (#6304) * Fix ctypes import blockers * Update Lib/ctypes/__init__.py from cpython3.13.9 --- Lib/ctypes/__init__.py | 39 ++++--- crates/vm/src/stdlib/ctypes.rs | 79 +++++++++++-- crates/vm/src/stdlib/ctypes/array.rs | 7 +- crates/vm/src/stdlib/ctypes/base.rs | 15 +++ crates/vm/src/stdlib/ctypes/function.rs | 148 ++++++++++++++++-------- 5 files changed, 211 insertions(+), 77 deletions(-) diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py index a5d27daff0..3599e13ed2 100644 --- a/Lib/ctypes/__init__.py +++ b/Lib/ctypes/__init__.py @@ -347,6 +347,19 @@ def __init__(self, name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None): + if name: + name = _os.fspath(name) + + # If the filename that has been provided is an iOS/tvOS/watchOS + # .fwork file, dereference the location to the true origin of the + # binary. + if name.endswith(".fwork"): + with open(name) as f: + name = _os.path.join( + _os.path.dirname(_sys.executable), + f.read().strip() + ) + self._name = name flags = self._func_flags_ if use_errno: @@ -467,6 +480,8 @@ def LoadLibrary(self, name): if _os.name == "nt": pythonapi = PyDLL("python dll", None, _sys.dllhandle) +elif _sys.platform == "android": + pythonapi = PyDLL("libpython%d.%d.so" % _sys.version_info[:2]) elif _sys.platform == "cygwin": pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2]) else: @@ -498,15 +513,14 @@ def WinError(code=None, descr=None): c_ssize_t = c_longlong # functions + from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, _cast_addr ## void *memmove(void *, const void *, size_t); -# XXX: RUSTPYTHON -# memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr) +memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr) ## void *memset(void *, int, size_t) -# XXX: RUSTPYTHON -# memset = CFUNCTYPE(c_void_p, c_void_p, c_int, c_size_t)(_memset_addr) +memset = CFUNCTYPE(c_void_p, c_void_p, c_int, c_size_t)(_memset_addr) def PYFUNCTYPE(restype, *argtypes): class CFunctionType(_CFuncPtr): @@ -515,17 +529,15 @@ class CFunctionType(_CFuncPtr): _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI return CFunctionType -# XXX: RUSTPYTHON -# _cast = PYFUNCTYPE(py_object, c_void_p, py_object, py_object)(_cast_addr) +_cast = PYFUNCTYPE(py_object, c_void_p, py_object, py_object)(_cast_addr) def cast(obj, typ): return _cast(obj, obj, typ) -# XXX: RUSTPYTHON -# _string_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr) +_string_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr) def string_at(ptr, size=-1): - """string_at(addr[, size]) -> string + """string_at(ptr[, size]) -> string - Return the string at addr.""" + Return the byte string at void *ptr.""" return _string_at(ptr, size) try: @@ -533,12 +545,11 @@ def string_at(ptr, size=-1): except ImportError: pass else: - # XXX: RUSTPYTHON - # _wstring_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_wstring_at_addr) + _wstring_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_wstring_at_addr) def wstring_at(ptr, size=-1): - """wstring_at(addr[, size]) -> string + """wstring_at(ptr[, size]) -> string - Return the string at addr.""" + Return the wide-character string at void *ptr.""" return _wstring_at(ptr, size) diff --git a/crates/vm/src/stdlib/ctypes.rs b/crates/vm/src/stdlib/ctypes.rs index 92629dcadb..500ddbfb06 100644 --- a/crates/vm/src/stdlib/ctypes.rs +++ b/crates/vm/src/stdlib/ctypes.rs @@ -189,6 +189,7 @@ pub(crate) mod _ctypes { } } + #[cfg(windows)] #[pyfunction(name = "LoadLibrary")] fn load_library_windows( name: String, @@ -203,20 +204,33 @@ pub(crate) mod _ctypes { Ok(id) } + #[cfg(not(windows))] #[pyfunction(name = "dlopen")] fn load_library_unix( - name: String, + name: Option, _load_flags: OptionalArg, vm: &VirtualMachine, ) -> PyResult { // TODO: audit functions first // TODO: load_flags - let cache = library::libcache(); - let mut cache_write = cache.write(); - let (id, _) = cache_write - .get_or_insert_lib(&name, vm) - .map_err(|e| vm.new_os_error(e.to_string()))?; - Ok(id) + match name { + Some(name) => { + let cache = library::libcache(); + let mut cache_write = cache.write(); + let (id, _) = cache_write + .get_or_insert_lib(&name, vm) + .map_err(|e| vm.new_os_error(e.to_string()))?; + Ok(id) + } + None => { + // If None, call libc::dlopen(null, mode) to get the current process handle + let handle = unsafe { libc::dlopen(std::ptr::null(), libc::RTLD_NOW) }; + if handle.is_null() { + return Err(vm.new_os_error("dlopen() error")); + } + Ok(handle as usize) + } + } } #[pyfunction(name = "FreeLibrary")] @@ -228,10 +242,57 @@ pub(crate) mod _ctypes { } #[pyfunction(name = "POINTER")] - pub fn pointer(_cls: PyTypeRef) {} + pub fn create_pointer_type(cls: PyObjectRef, vm: &VirtualMachine) -> PyResult { + // Get the _pointer_type_cache + let ctypes_module = vm.import("_ctypes", 0)?; + let cache = ctypes_module.get_attr("_pointer_type_cache", vm)?; + + // Check if already in cache using __getitem__ + if let Ok(cached) = vm.call_method(&cache, "__getitem__", (cls.clone(),)) + && !vm.is_none(&cached) + { + return Ok(cached); + } + + // Get the _Pointer base class + let pointer_base = ctypes_module.get_attr("_Pointer", vm)?; + + // Create the name for the pointer type + let name = if let Ok(type_obj) = cls.get_attr("__name__", vm) { + format!("LP_{}", type_obj.str(vm)?) + } else if let Ok(s) = cls.str(vm) { + format!("LP_{}", s) + } else { + "LP_unknown".to_string() + }; + + // Create a new type that inherits from _Pointer + let type_type = &vm.ctx.types.type_type; + let bases = vm.ctx.new_tuple(vec![pointer_base]); + let dict = vm.ctx.new_dict(); + dict.set_item("_type_", cls.clone(), vm)?; + + let new_type = type_type + .as_object() + .call((vm.ctx.new_str(name), bases, dict), vm)?; + + // Store in cache using __setitem__ + vm.call_method(&cache, "__setitem__", (cls, new_type.clone()))?; + + Ok(new_type) + } #[pyfunction(name = "pointer")] - pub fn pointer_fn(_inst: PyObjectRef) {} + pub fn create_pointer_inst(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { + // Get the type of the object + let obj_type = obj.class().to_owned(); + + // Create pointer type for this object's type + let ptr_type = create_pointer_type(obj_type.into(), vm)?; + + // Create an instance of the pointer type with the object + ptr_type.call((obj,), vm) + } #[pyfunction] fn _pointer_type_cache() -> PyObjectRef { diff --git a/crates/vm/src/stdlib/ctypes/array.rs b/crates/vm/src/stdlib/ctypes/array.rs index a1adf847a9..a46322460a 100644 --- a/crates/vm/src/stdlib/ctypes/array.rs +++ b/crates/vm/src/stdlib/ctypes/array.rs @@ -72,13 +72,14 @@ impl std::fmt::Debug for PyCArray { impl Constructor for PyCArray { type Args = (PyTypeRef, usize); - fn py_new(_cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { - Ok(Self { + fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + Self { typ: PyRwLock::new(args.0), length: AtomicCell::new(args.1), value: PyRwLock::new(vm.ctx.none()), } - .into_pyobject(vm)) + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/crates/vm/src/stdlib/ctypes/base.rs b/crates/vm/src/stdlib/ctypes/base.rs index 1b07d73f8d..29f3b9da2a 100644 --- a/crates/vm/src/stdlib/ctypes/base.rs +++ b/crates/vm/src/stdlib/ctypes/base.rs @@ -171,6 +171,21 @@ impl PyCSimpleType { .clone(), )) } + + #[pyclassmethod] + fn from_param(cls: PyTypeRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult { + // If the value is already an instance of the requested type, return it + if value.fast_isinstance(&cls) { + return Ok(value); + } + + // Check for _as_parameter_ attribute + let Ok(as_parameter) = value.get_attr("_as_parameter_", vm) else { + return Err(vm.new_type_error("wrong type")); + }; + + PyCSimpleType::from_param(cls, as_parameter, vm) + } } #[pyclass( diff --git a/crates/vm/src/stdlib/ctypes/function.rs b/crates/vm/src/stdlib/ctypes/function.rs index 64a230ad56..c1db4d58f8 100644 --- a/crates/vm/src/stdlib/ctypes/function.rs +++ b/crates/vm/src/stdlib/ctypes/function.rs @@ -120,60 +120,106 @@ impl Debug for PyCFuncPtr { } impl Constructor for PyCFuncPtr { - type Args = (PyTupleRef, FuncArgs); + type Args = FuncArgs; - fn py_new(_cls: PyTypeRef, (tuple, _args): Self::Args, vm: &VirtualMachine) -> PyResult { - let name = tuple - .first() - .ok_or(vm.new_type_error("Expected a tuple with at least 2 elements"))? - .downcast_ref::() - .ok_or(vm.new_type_error("Expected a string"))? - .to_string(); - let handler = tuple - .into_iter() - .nth(1) - .ok_or(vm.new_type_error("Expected a tuple with at least 2 elements"))? - .clone(); - let handle = handler.try_int(vm); - let handle = match handle { - Ok(handle) => handle.as_bigint().clone(), - Err(_) => handler - .get_attr("_handle", vm)? - .try_int(vm)? - .as_bigint() - .clone(), - }; - let library_cache = crate::stdlib::ctypes::library::libcache().read(); - let library = library_cache - .get_lib( - handle - .to_usize() - .ok_or(vm.new_value_error("Invalid handle".to_string()))?, - ) - .ok_or_else(|| vm.new_value_error("Library not found".to_string()))?; - let inner_lib = library.lib.lock(); - - let terminated = format!("{}\0", &name); - let code_ptr = if let Some(lib) = &*inner_lib { - let pointer: Symbol<'_, FP> = unsafe { - lib.get(terminated.as_bytes()) - .map_err(|err| err.to_string()) - .map_err(|err| vm.new_attribute_error(err))? + fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + // Handle different argument forms like CPython: + // 1. Empty args: create uninitialized + // 2. One integer argument: function address + // 3. Tuple argument: (name, dll) form + + if args.args.is_empty() { + return Self { + ptr: PyRwLock::new(None), + needs_free: AtomicCell::new(false), + arg_types: PyRwLock::new(None), + _flags_: AtomicCell::new(0), + res_type: PyRwLock::new(None), + name: PyRwLock::new(None), + handler: vm.ctx.none(), + } + .into_ref_with_type(vm, cls) + .map(Into::into); + } + + let first_arg = &args.args[0]; + + // Check if first argument is an integer (function address) + if let Ok(addr) = first_arg.try_int(vm) { + let ptr_val = addr.as_bigint().to_usize().unwrap_or(0); + return Self { + ptr: PyRwLock::new(Some(CodePtr(ptr_val as *mut _))), + needs_free: AtomicCell::new(false), + arg_types: PyRwLock::new(None), + _flags_: AtomicCell::new(0), + res_type: PyRwLock::new(None), + name: PyRwLock::new(Some(format!("CFuncPtr@{:#x}", ptr_val))), + handler: vm.ctx.new_int(ptr_val).into(), + } + .into_ref_with_type(vm, cls) + .map(Into::into); + } + + // Check if first argument is a tuple (name, dll) form + if let Some(tuple) = first_arg.downcast_ref::() { + let name = tuple + .first() + .ok_or(vm.new_type_error("Expected a tuple with at least 2 elements"))? + .downcast_ref::() + .ok_or(vm.new_type_error("Expected a string"))? + .to_string(); + let handler = tuple + .iter() + .nth(1) + .ok_or(vm.new_type_error("Expected a tuple with at least 2 elements"))? + .clone(); + + // Get library handle and load function + let handle = handler.try_int(vm); + let handle = match handle { + Ok(handle) => handle.as_bigint().clone(), + Err(_) => handler + .get_attr("_handle", vm)? + .try_int(vm)? + .as_bigint() + .clone(), }; - Some(CodePtr(*pointer as *mut _)) - } else { - None - }; - Ok(Self { - ptr: PyRwLock::new(code_ptr), - needs_free: AtomicCell::new(false), - arg_types: PyRwLock::new(None), - _flags_: AtomicCell::new(0), - res_type: PyRwLock::new(None), - name: PyRwLock::new(Some(name)), - handler, + let library_cache = crate::stdlib::ctypes::library::libcache().read(); + let library = library_cache + .get_lib( + handle + .to_usize() + .ok_or(vm.new_value_error("Invalid handle".to_string()))?, + ) + .ok_or_else(|| vm.new_value_error("Library not found".to_string()))?; + let inner_lib = library.lib.lock(); + + let terminated = format!("{}\0", &name); + let code_ptr = if let Some(lib) = &*inner_lib { + let pointer: Symbol<'_, FP> = unsafe { + lib.get(terminated.as_bytes()) + .map_err(|err| err.to_string()) + .map_err(|err| vm.new_attribute_error(err))? + }; + Some(CodePtr(*pointer as *mut _)) + } else { + None + }; + + return Self { + ptr: PyRwLock::new(code_ptr), + needs_free: AtomicCell::new(false), + arg_types: PyRwLock::new(None), + _flags_: AtomicCell::new(0), + res_type: PyRwLock::new(None), + name: PyRwLock::new(Some(name)), + handler, + } + .into_ref_with_type(vm, cls) + .map(Into::into); } - .to_pyobject(vm)) + + Err(vm.new_type_error("Expected an integer address or a tuple")) } } From a81912857d6151689ff8cb62dd7fec320cf33212 Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" <69878+youknowone@users.noreply.github.com> Date: Sat, 29 Nov 2025 02:15:25 +0900 Subject: [PATCH 017/577] Ctypes __mul__ (#6305) --- crates/vm/src/stdlib/ctypes/base.rs | 52 +++++++++++++++++++++----- crates/vm/src/stdlib/ctypes/pointer.rs | 49 ++++++++++++++++++++++-- 2 files changed, 88 insertions(+), 13 deletions(-) diff --git a/crates/vm/src/stdlib/ctypes/base.rs b/crates/vm/src/stdlib/ctypes/base.rs index 29f3b9da2a..6fdb79e11e 100644 --- a/crates/vm/src/stdlib/ctypes/base.rs +++ b/crates/vm/src/stdlib/ctypes/base.rs @@ -3,8 +3,9 @@ use crate::builtins::PyType; use crate::builtins::{PyBytes, PyFloat, PyInt, PyNone, PyStr, PyTypeRef}; use crate::convert::ToPyObject; use crate::function::{Either, OptionalArg}; +use crate::protocol::PyNumberMethods; use crate::stdlib::ctypes::_ctypes::new_simple_type; -use crate::types::Constructor; +use crate::types::{AsNumber, Constructor}; use crate::{AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine}; use crossbeam_utils::atomic::AtomicCell; use num_traits::ToPrimitive; @@ -158,9 +159,10 @@ pub struct PyCData { impl PyCData {} #[pyclass(module = "_ctypes", name = "PyCSimpleType", base = PyType)] +#[derive(Debug, PyPayload)] pub struct PyCSimpleType {} -#[pyclass(flags(BASETYPE))] +#[pyclass(flags(BASETYPE), with(AsNumber))] impl PyCSimpleType { #[allow(clippy::new_ret_no_self)] #[pymethod] @@ -186,6 +188,33 @@ impl PyCSimpleType { PyCSimpleType::from_param(cls, as_parameter, vm) } + + #[pymethod] + fn __mul__(cls: PyTypeRef, n: isize, vm: &VirtualMachine) -> PyResult { + PyCSimple::repeat(cls, n, vm) + } +} + +impl AsNumber for PyCSimpleType { + fn as_number() -> &'static PyNumberMethods { + static AS_NUMBER: PyNumberMethods = PyNumberMethods { + multiply: Some(|a, b, vm| { + // a is a PyCSimpleType instance (type object like c_char) + // b is int (array size) + let cls = a + .downcast_ref::() + .ok_or_else(|| vm.new_type_error("expected type".to_owned()))?; + let n = b + .try_index(vm)? + .as_bigint() + .to_isize() + .ok_or_else(|| vm.new_overflow_error("array size too large".to_owned()))?; + PyCSimple::repeat(cls.to_owned(), n, vm) + }), + ..PyNumberMethods::NOT_IMPLEMENTED + }; + &AS_NUMBER + } } #[pyclass( @@ -215,8 +244,18 @@ impl Constructor for PyCSimple { let attributes = cls.get_attributes(); let _type_ = attributes .iter() - .find(|(k, _)| k.to_object().str(vm).unwrap().to_string() == *"_type_") - .unwrap() + .find(|(k, _)| { + k.to_object() + .str(vm) + .map(|s| s.to_string() == "_type_") + .unwrap_or(false) + }) + .ok_or_else(|| { + vm.new_type_error(format!( + "cannot create '{}' instances: no _type_ attribute", + cls.name() + )) + })? .1 .str(vm)? .to_string(); @@ -276,11 +315,6 @@ impl PyCSimple { } .to_pyobject(vm)) } - - #[pyclassmethod] - fn __mul__(cls: PyTypeRef, n: isize, vm: &VirtualMachine) -> PyResult { - PyCSimple::repeat(cls, n, vm) - } } impl PyCSimple { diff --git a/crates/vm/src/stdlib/ctypes/pointer.rs b/crates/vm/src/stdlib/ctypes/pointer.rs index b60280c73c..3eb6f68e6d 100644 --- a/crates/vm/src/stdlib/ctypes/pointer.rs +++ b/crates/vm/src/stdlib/ctypes/pointer.rs @@ -1,8 +1,13 @@ +use crossbeam_utils::atomic::AtomicCell; +use num_traits::ToPrimitive; use rustpython_common::lock::PyRwLock; -use crate::builtins::PyType; +use crate::builtins::{PyType, PyTypeRef}; +use crate::convert::ToPyObject; +use crate::protocol::PyNumberMethods; use crate::stdlib::ctypes::PyCData; -use crate::{PyObjectRef, PyResult}; +use crate::types::AsNumber; +use crate::{PyObjectRef, PyResult, VirtualMachine}; #[pyclass(name = "PyCPointerType", base = PyType, module = "_ctypes")] #[derive(PyPayload, Debug)] @@ -11,8 +16,44 @@ pub struct PyCPointerType { pub(crate) inner: PyCPointer, } -#[pyclass] -impl PyCPointerType {} +#[pyclass(flags(IMMUTABLETYPE), with(AsNumber))] +impl PyCPointerType { + #[pymethod] + fn __mul__(cls: PyTypeRef, n: isize, vm: &VirtualMachine) -> PyResult { + use super::array::{PyCArray, PyCArrayType}; + if n < 0 { + return Err(vm.new_value_error(format!("Array length must be >= 0, not {n}"))); + } + Ok(PyCArrayType { + inner: PyCArray { + typ: PyRwLock::new(cls), + length: AtomicCell::new(n as usize), + value: PyRwLock::new(vm.ctx.none()), + }, + } + .to_pyobject(vm)) + } +} + +impl AsNumber for PyCPointerType { + fn as_number() -> &'static PyNumberMethods { + static AS_NUMBER: PyNumberMethods = PyNumberMethods { + multiply: Some(|a, b, vm| { + let cls = a + .downcast_ref::() + .ok_or_else(|| vm.new_type_error("expected type".to_owned()))?; + let n = b + .try_index(vm)? + .as_bigint() + .to_isize() + .ok_or_else(|| vm.new_overflow_error("array size too large".to_owned()))?; + PyCPointerType::__mul__(cls.to_owned(), n, vm) + }), + ..PyNumberMethods::NOT_IMPLEMENTED + }; + &AS_NUMBER + } +} #[pyclass( name = "_Pointer", From 7d8f0b989c542ee856615ee7e569898081312479 Mon Sep 17 00:00:00 2001 From: Shahar Naveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 29 Nov 2025 02:02:52 +0200 Subject: [PATCH 018/577] Split `TestOperator` instruction (#6306) * Split `TestOperator` inatruction * Update snapshot * Set as have label --- crates/codegen/src/compile.rs | 48 +++-------- ...pile__tests__nested_double_async_with.snap | 69 ++++++++-------- crates/compiler-core/src/bytecode.rs | 54 ++++++++----- crates/vm/src/frame.rs | 81 +++++++++++-------- 4 files changed, 123 insertions(+), 129 deletions(-) diff --git a/crates/codegen/src/compile.rs b/crates/codegen/src/compile.rs index b2dc10cda6..4a4f17edcf 100644 --- a/crates/codegen/src/compile.rs +++ b/crates/codegen/src/compile.rs @@ -36,7 +36,7 @@ use rustpython_compiler_core::{ Mode, OneIndexed, PositionEncoding, SourceFile, SourceLocation, bytecode::{ self, Arg as OpArgMarker, BinaryOperator, CodeObject, ComparisonOperator, ConstantData, - Instruction, OpArg, OpArgType, UnpackExArgs, + Instruction, Invert, OpArg, OpArgType, UnpackExArgs, }, }; use rustpython_wtf8::Wtf8Buf; @@ -2034,20 +2034,7 @@ impl Compiler { // Check exception type: self.compile_expression(exc_type)?; - emit!( - self, - Instruction::TestOperation { - op: bytecode::TestOperator::ExceptionMatch, - } - ); - - // We cannot handle this exception type: - emit!( - self, - Instruction::PopJumpIfFalse { - target: next_handler, - } - ); + emit!(self, Instruction::JumpIfNotExcMatch(next_handler)); // We have a match, store in name (except x as y) if let Some(alias) = name { @@ -3477,12 +3464,7 @@ impl Compiler { // 4. Load None. self.emit_load_const(ConstantData::None); // 5. Compare with IS_OP 1. - emit!( - self, - Instruction::TestOperation { - op: bytecode::TestOperator::IsNot - } - ); + emit!(self, Instruction::IsOp(Invert::Yes)); // At this point the TOS is a tuple of (nargs + n_attrs) attributes (or None). pc.on_top += 1; @@ -3648,12 +3630,8 @@ impl Compiler { // Check if copy is None (consumes the copy like POP_JUMP_IF_NONE) self.emit_load_const(ConstantData::None); - emit!( - self, - Instruction::TestOperation { - op: bytecode::TestOperator::IsNot - } - ); + emit!(self, Instruction::IsOp(Invert::Yes)); + // Stack: [subject, keys_tuple, values_tuple, bool] self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?; // Stack: [subject, keys_tuple, values_tuple] @@ -3948,12 +3926,7 @@ impl Compiler { Singleton::True => ConstantData::Boolean { value: true }, }); // Compare using the "Is" operator. - emit!( - self, - Instruction::TestOperation { - op: bytecode::TestOperator::Is - } - ); + emit!(self, Instruction::IsOp(Invert::No)); // Jump to the failure label if the comparison is false. self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?; Ok(()) @@ -4082,7 +4055,6 @@ impl Compiler { let (last_val, mid_exprs) = exprs.split_last().unwrap(); use bytecode::ComparisonOperator::*; - use bytecode::TestOperator::*; let compile_cmpop = |c: &mut Self, op: &CmpOp| match op { CmpOp::Eq => emit!(c, Instruction::CompareOperation { op: Equal }), CmpOp::NotEq => emit!(c, Instruction::CompareOperation { op: NotEqual }), @@ -4092,10 +4064,10 @@ impl Compiler { CmpOp::GtE => { emit!(c, Instruction::CompareOperation { op: GreaterOrEqual }) } - CmpOp::In => emit!(c, Instruction::TestOperation { op: In }), - CmpOp::NotIn => emit!(c, Instruction::TestOperation { op: NotIn }), - CmpOp::Is => emit!(c, Instruction::TestOperation { op: Is }), - CmpOp::IsNot => emit!(c, Instruction::TestOperation { op: IsNot }), + CmpOp::In => emit!(c, Instruction::ContainsOp(Invert::No)), + CmpOp::NotIn => emit!(c, Instruction::ContainsOp(Invert::Yes)), + CmpOp::Is => emit!(c, Instruction::IsOp(Invert::No)), + CmpOp::IsNot => emit!(c, Instruction::IsOp(Invert::Yes)), }; // a == b == c == d diff --git a/crates/codegen/src/snapshots/rustpython_codegen__compile__tests__nested_double_async_with.snap b/crates/codegen/src/snapshots/rustpython_codegen__compile__tests__nested_double_async_with.snap index dc624c7b6a..3042e35f17 100644 --- a/crates/codegen/src/snapshots/rustpython_codegen__compile__tests__nested_double_async_with.snap +++ b/crates/codegen/src/snapshots/rustpython_codegen__compile__tests__nested_double_async_with.snap @@ -1,5 +1,5 @@ --- -source: compiler/codegen/src/compile.rs +source: crates/codegen/src/compile.rs expression: "compile_exec(\"\\\nfor stop_exc in (StopIteration('spam'), StopAsyncIteration('ham')):\n with self.subTest(type=type(stop_exc)):\n try:\n async with egg():\n raise stop_exc\n except Exception as ex:\n self.assertIs(ex, stop_exc)\n else:\n self.fail(f'{stop_exc} was suppressed')\n\")" --- 1 0 SetupLoop @@ -11,7 +11,7 @@ expression: "compile_exec(\"\\\nfor stop_exc in (StopIteration('spam'), StopAsyn 6 CallFunctionPositional(1) 7 BuildTuple (2) 8 GetIter - >> 9 ForIter (73) + >> 9 ForIter (72) 10 StoreLocal (2, stop_exc) 2 11 LoadNameAny (3, self) @@ -21,7 +21,7 @@ expression: "compile_exec(\"\\\nfor stop_exc in (StopIteration('spam'), StopAsyn 15 CallFunctionPositional(1) 16 LoadConst (("type")) 17 CallMethodKeyword (1) - 18 SetupWith (70) + 18 SetupWith (69) 19 Pop 3 20 SetupExcept (42) @@ -48,41 +48,40 @@ expression: "compile_exec(\"\\\nfor stop_exc in (StopIteration('spam'), StopAsyn 38 Resume (3) 39 WithCleanupFinish 40 PopBlock - 41 Jump (59) + 41 Jump (58) >> 42 CopyItem (1) 6 43 LoadNameAny (7, Exception) - 44 TestOperation (ExceptionMatch) - 45 PopJumpIfFalse (58) - 46 StoreLocal (8, ex) + 44 JUMP_IF_NOT_EXC_MATCH(57) + 45 StoreLocal (8, ex) - 7 47 LoadNameAny (3, self) - 48 LoadMethod (9, assertIs) - 49 LoadNameAny (8, ex) - 50 LoadNameAny (2, stop_exc) - 51 CallMethodPositional (2) - 52 Pop - 53 PopException - 54 LoadConst (None) - 55 StoreLocal (8, ex) - 56 DeleteLocal (8, ex) - 57 Jump (68) - >> 58 Raise (Reraise) + 7 46 LoadNameAny (3, self) + 47 LoadMethod (9, assertIs) + 48 LoadNameAny (8, ex) + 49 LoadNameAny (2, stop_exc) + 50 CallMethodPositional (2) + 51 Pop + 52 PopException + 53 LoadConst (None) + 54 StoreLocal (8, ex) + 55 DeleteLocal (8, ex) + 56 Jump (67) + >> 57 Raise (Reraise) - 9 >> 59 LoadNameAny (3, self) - 60 LoadMethod (10, fail) - 61 LoadConst ("") - 62 LoadNameAny (2, stop_exc) - 63 FormatValue (None) - 64 LoadConst (" was suppressed") - 65 BuildString (2) - 66 CallMethodPositional (1) - 67 Pop + 9 >> 58 LoadNameAny (3, self) + 59 LoadMethod (10, fail) + 60 LoadConst ("") + 61 LoadNameAny (2, stop_exc) + 62 FormatValue (None) + 63 LoadConst (" was suppressed") + 64 BuildString (2) + 65 CallMethodPositional (1) + 66 Pop - 2 >> 68 PopBlock - 69 EnterFinally - >> 70 WithCleanupStart - 71 WithCleanupFinish - 72 Jump (9) - >> 73 PopBlock - 74 ReturnConst (None) + 2 >> 67 PopBlock + 68 EnterFinally + >> 69 WithCleanupStart + 70 WithCleanupFinish + 71 Jump (9) + >> 72 PopBlock + 73 ReturnConst (None) diff --git a/crates/compiler-core/src/bytecode.rs b/crates/compiler-core/src/bytecode.rs index fe28517cda..144054860e 100644 --- a/crates/compiler-core/src/bytecode.rs +++ b/crates/compiler-core/src/bytecode.rs @@ -577,6 +577,10 @@ pub enum Instruction { Subscript, StoreSubscript, DeleteSubscript, + /// Performs `is` comparison, or `is not` if `invert` is 1. + IsOp(Arg), + /// Performs `in` comparison, or `not in` if `invert` is 1. + ContainsOp(Arg), StoreAttr { idx: Arg, }, @@ -600,9 +604,6 @@ pub enum Instruction { LoadAttr { idx: Arg, }, - TestOperation { - op: Arg, - }, CompareOperation { op: Arg, }, @@ -628,6 +629,10 @@ pub enum Instruction { Break { target: Arg