Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Initialize CodeQL
uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
uses: github/codeql-action/init@cee97f86b972a3ded3c58d04148362b193ddc518 # v4.38.3
with:
languages: ${{ matrix.language }}
# Neither language needs a compiled build for CodeQL to extract it.
build-mode: none
queries: security-extended

- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
uses: github/codeql-action/analyze@cee97f86b972a3ded3c58d04148362b193ddc518 # v4.38.3
with:
category: "/language:${{ matrix.language }}"
2 changes: 1 addition & 1 deletion .github/workflows/release-drafter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ jobs:
contents: write # create/update release draft
pull-requests: read # read PR titles and labels to generate the notes
steps:
- uses: release-drafter/release-drafter@72967cdc98ddd3160f1fc3dff619de365e137dd0 # v7
- uses: release-drafter/release-drafter@978bb0b30c5ee8cdd332ced253758157150d43f0 # v7.10.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ jobs:
cat release_body.md

- name: Create GitHub Release
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3
uses: softprops/action-gh-release@e598afbe1493e6b1bafb1f389cabb956eab91231 # v3.0.3
with:
name: ${{ github.ref_name }}
body_path: release_body.md
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
sudo apt-get update
sudo apt-get install -y gcc-multilib g++-multilib

- uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
- uses: Swatinem/rust-cache@63fed3e2fecf6f7b51dc6f043341b79ef82a9ae7 # v2.9.2

- name: Build
run: cargo build --target i686-unknown-linux-gnu --verbose
Expand Down Expand Up @@ -129,18 +129,18 @@ jobs:
sudo apt-get update
sudo apt-get install -y gcc-multilib g++-multilib

- uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
- uses: Swatinem/rust-cache@63fed3e2fecf6f7b51dc6f043341b79ef82a9ae7 # v2.9.2

- name: Install cargo-llvm-cov
uses: taiki-e/install-action@83ac0ad63c0167e6f06796fab0fce28db1bf3db0 # v2.87.22
uses: taiki-e/install-action@ab6895351a88b908e96a4697860d4ffea5e57dbe # v2.87.27
with:
tool: cargo-llvm-cov

- name: Generate LCOV report
run: cargo llvm-cov --target i686-unknown-linux-gnu --lcov --output-path lcov.info

- name: Upload coverage artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: coverage-lcov
path: lcov.info
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ jobs:
persist-credentials: false

- name: Run analysis
uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
uses: ossf/scorecard-action@55891bbd73f2425e97637d96e306fc9d491d0b21 # v2.4.4
with:
results_file: results.sarif
results_format: sarif
publish_results: true

- name: Upload to code-scanning
uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
uses: github/codeql-action/upload-sarif@cee97f86b972a3ded3c58d04148362b193ddc518 # v4.38.3
with:
sarif_file: results.sarif
33 changes: 24 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ All notable changes to this project are documented in this file.

Format inspired by [Keep a Changelog](https://keepachangelog.com/). Versioning follows [Semantic Versioning](https://semver.org/). Older entries live under [`changelog/`](changelog/).

## [1.4.0] — 2026/10/04
## [1.4.0] — 2026/10/11

Built on rust-samp v3.5.0, now from crates.io. Additive on the Pawn side: four natives and one constant are new, nothing was removed or renamed, so 1.3.0 gamemodes compile unchanged. **One behaviour did change** — `OnQueryError` used to hand its arguments over in the wrong order, and now hands them over as the forward declares. Read the first entry under Fixed before upgrading if you handle that forward.
Built on rust-samp v3.6.0, now from crates.io. Additive on the Pawn side: four natives and one constant are new, nothing was removed or renamed, so 1.3.0 gamemodes compile unchanged. **One behaviour did change** — `OnQueryError` used to hand its arguments over in the wrong order, and now hands them over as the forward declares. Read the first entry under Fixed before upgrading if you handle that forward.

### Added

Expand Down Expand Up @@ -35,6 +35,14 @@ Built on rust-samp v3.5.0, now from crates.io. Additive on the Pawn side: four n

### Fixed

- **A burst of queries could kill the server, and could stall the FIFO queue for good.** Submitting 2000 queries in one tick aborted the process with `memory allocation of 4194304 bytes failed`, and the cause is specific to this architecture: a worker thread per query, with the default 8 MiB stack, inside a **32-bit** server. A few hundred live workers exhaust the address space, and the allocation that fails next takes the process with it.

Two things were wrong, and both are fixed. Workers now get a **256 KiB stack** — a worker opens a connection, runs one statement and builds a cache, it does not recurse — which moved the ceiling from roughly 1700 workers to past 9000 measured. And a refused thread is no longer a panic: `thread::spawn` panics when the OS says no, which the native wrapper caught and turned into a lost submission — lost *including its sequence number*, so every ordered callback queued behind it would have waited forever. The failure is now an ordinary failed result: the sequence is accounted for, `OnQueryError` fires, and the native returns `false`.

The submission natives also report that refusal honestly now. `mysql_query`, `mysql_pquery`, `mysql_query_file`, `mysql_stmt_execute`, `mysql_stmt_pexecute`, `mysql_transaction_execute` and the ORM CRUD natives returned `true` whenever the connection id was valid; they return what the submission actually did.

Measured after the fix: 9000 queries submitted in one tick, 9000 callbacks delivered, submission order intact, nothing left in flight.

- **`OnQueryError` delivered its five arguments in reverse.** The forward is declared `OnQueryError(errorid, error[], callback[], query[], connId)`, and a gamemode received the connection id as `errorid`, the query text as `error`, the error message as `query`, and the MySQL code as `connId`. The cause was in the dispatch: `exec_public!` pushes its arguments in reverse — the AMX stack convention — so the order listed in the call is the order the public receives, and the code listed them backwards as if it had to invert them by hand. Present since 1.0.0. **Anyone handling this forward was reading the wrong fields and should check their handler.** (#56)

- **Requesting TLS on a loopback host ran in plaintext.** `MYSQL_OPT_SSL = 1` against `127.0.0.1` reported success while `Ssl_cipher` came back empty. The driver's `prefer_socket` defaults to true and, after the handshake, moves a *loopback* connection onto the server's unix socket — where it secures nothing. The two conditions met on the most ordinary local setup there is. Asking for TLS now switches that optimisation off; without TLS it stays, which is where it helps. Verified against MariaDB 11.8: `TLS_AES_256_GCM_SHA384` where there used to be an empty string.
Expand All @@ -47,10 +55,18 @@ Built on rust-samp v3.5.0, now from crates.io. Additive on the Pawn side: four n

### Changed

- **rust-samp moves from a git tag to crates.io** (`version = "3.5.0"`). This also clears a long-standing oddity: the `v3.5.0` tag declared `version = "3.4.0"` in its own manifest, so the lockfile recorded 3.4.0 pointing at the v3.5.0 tag. The SDK's new `mainthread` module is **not** adopted yet: its `post` takes a closure with no parameters and there is no route to plugin state from a worker thread, so the plugin's own `mpsc` channel stays until `post_with` / `post_with_amx` land.
- **rust-samp moves from a git tag to crates.io, and on to `3.6.0`** — whose `mainthread` queue now carries results back from the worker threads. The move to the registry also clears a long-standing oddity: the `v3.5.0` tag declared `version = "3.4.0"` in its own manifest, so the lockfile recorded 3.4.0 pointing at the v3.5.0 tag.

**The plugin's own result channels are gone.** A finished query, or a finished Argon2id hash, posts a job that hands the result to the plugin; the SDK drains that queue immediately before `on_tick`, so the dispatch still happens in `on_tick` and nothing arrives a tick later than it used to. The ordering stays ours: jobs run in completion order, so the FIFO sequence buffer is still what puts `mysql_query` callbacks back in submission order.

- **`mysql` 28.0.0 → 28.0.2**, plus a large round of transitive updates. (#38, #45, and the Dependabot group)
- Routine dependency and action bumps: the `github-actions` group in three rounds, `pymdown-extensions` in the docs requirements, and the cargo group — `lru`, `sha1`, `num-bigint`, `wasip2`, `windows-sys` and `derive_utils` among them. (#39, #40, #44–#54)
Handing over and dispatching had to be separate steps, not a matter of taste. `post_with` documents that calling into Pawn from inside the job is not allowed, and the reason applies here exactly: a `public` re-entering one of these natives would take a second `&mut` to the same plugin, since `#[native]` resolves the plugin with `plugin::get` rather than the guarded `plugin::with_instance`. `post_with_amx` splits the two, but hands the script its reply only after the plugin borrow has ended — too late to hold a result cache across the call. Buffering in the job and dispatching in the tick satisfies both.

- **`mysql` 28.0.0 → 28.0.3**, plus a large round of transitive updates. The 28.0.3 bump is the one that matters: it requires `lru` 0.18, which is how **RUSTSEC-2026-0253 stopped applying** — the fix had been merged upstream since 2026/09/21 and no `cargo update` could reach it while the driver still asked for `0.16`. The lockfile now carries `lru` 0.18.5. (#38, #45, #62, #64)
- Routine dependency and action bumps: the `github-actions` group in five rounds, `pymdown-extensions` and `urllib3` in the docs requirements, and the cargo group — `lru`, `sha1`, `num-bigint`, `wasip2`, `windows-sys`, `derive_utils` and `io-enum` among them. (#39, #40, #44–#54, #61–#66)

- **A closing sweep over the lockfile and the workflows**, so the release does not ship pins that were already stale when it was tagged. `cargo update` moved ten transitive crates — `cc`, `generic-array`, `powerfmt`, `serde` and its two companions, `twox-hash`, `uuid` and `zeroize`; seven pinned actions were re-pinned to their current releases (`upload-artifact` v7.0.2, `codeql-action` v4.38.3, `scorecard-action` v2.4.4, `install-action` v2.87.27, `action-gh-release` v3.0.3, `rust-cache` v2.9.2, `release-drafter` v7.10.0), SHA and `# vX.Y.Z` comment together, since a comment that drifts from its SHA is worse than no comment.

- **`argon2` stays on 0.5, deliberately.** 0.6.0 is out and it is a breaking change in exactly the place that must not break quietly: the `std` feature is gone, `SaltString` and `OsRng` moved, `hash_password` changed signature and `PasswordHash` is deprecated. Hashes already written by `mysql_hash_password` have to keep verifying across the bump, and proving that belongs in a pull request of its own rather than riding along with a release.

### CI / tooling

Expand Down Expand Up @@ -80,12 +96,11 @@ Built on rust-samp v3.5.0, now from crates.io. Additive on the Pawn side: four n

- **IPv6 is supported, in brackets.** `[::1]` is parsed and validated as an address; without brackets it is taken as a host name, which usually still connects but validates nothing. (#42)

### Known advisories
### Known advisory

Both are informational, neither is resolvable here, and both are pinned behind the `mysql` crate:
One is left, it is informational, and it is not resolvable here:

- **RUSTSEC-2025-0134** — `rustls-pemfile` is unmaintained. The code that runs is the maintained `rustls-pki-types`; upstream still depends on the wrapper, so there is not even an unreleased fix to wait for.
- **RUSTSEC-2026-0253** — `lru` is unsound in `LruCache::pop` if a key's `Drop` panics. The cache keys here are strings and integers, whose `Drop` does not panic. Upstream merged the bump to `lru` 0.18.2 on 2026/09/21 but has not released it; `mysql` still requires `0.16`, which a `cargo update` cannot cross.
- **RUSTSEC-2025-0134** — `rustls-pemfile` is unmaintained. The code that actually runs is the maintained `rustls-pki-types`; the flagged crate is a thin wrapper over it. The `mysql` crate still depends on the wrapper, including on its own master, so there is not even an unreleased fix to wait for. Dropping it here would mean giving up TLS or forking the driver.

## [1.3.0] — 2026/09/07

Expand Down
54 changes: 27 additions & 27 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ crate-type = ["cdylib", "lib"]
[dependencies]
# `compression` gzips rotated log archives. It pulls in flate2, which the mysql
# crate already brings in via `minimal-rust` — so this costs no new dependency.
samp = { package = "rust-samp", version = "3.5.0", features = ["compression"] }
samp = { package = "rust-samp", version = "3.6.0", features = ["compression"] }
# `rustls-tls-ring` is what actually compiles a TLS backend in. Without it the
# crate's `make_secure` is a `panic!` stub, so MYSQL_OPT_SSL would abort the
# connection instead of encrypting it. `ring` rather than the default
Expand Down
2 changes: 1 addition & 1 deletion docs/queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ native bool:mysql_query(connId, const query[], const callback[] = "", const form
| `format` | string | One char per variadic parameter (`d`/`i` = int, `f` = float, `s` = string) |
| `...` | variadic | Values forwarded to the callback in the order they appear |

**Returns:** `true` if the query was queued, `false` if `connId` is unknown.
**Returns:** `true` if the query was queued, `false` if `connId` is unknown or the submission itself failed — the server refusing a new worker thread, which only happens under a burst of thousands in a single tick. A refused submission fires `OnQueryError` with `errorid` `0`, so a FIFO chain never waits on a callback that is not coming.

**Ordering guarantee — read this one carefully.** What is ordered is the **delivery of callbacks**, in submission order, even when the underlying queries finish out of order. A slow query holds back the dispatch of later callbacks until it completes.

Expand Down
3 changes: 1 addition & 2 deletions src/natives/orm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,7 @@ impl MysqlPlugin {
callback_info,
conn_id,
self.connections.get_auto_reconnect(conn_id),
);
true
)
}

/// orm_apply_cache(orm_id, row = 0)
Expand Down
Loading
Loading