Repository navigation
mysql2: a text column intermittently reads back as a wrong value (617 for 'hi') with a mysql_native_password user #11341
Description
Activity
This no longer reproduces on current main. Bisected on perrymaster against a live MySQL 8.0.46 with mysql2 3.24.4 and a
mysql_native_passworduser. Every arm carries #11366's patch, because without it mysql2 segfaults at connect.build SELECT 1 + 1 AS two, 'hi' AS smatched Node441d2ab + #11366 patch 0 of 8 runs d97339f + #11366 patch 2 of 10 runs (8 wrong) 3f6eb6c + #11366 patch 10 of 10 runs main 2febf42 + #11366, full probe (connect, query, params, transactions, error code, pool, pool transaction) 25 of 25 runs with the native-password user, 25 of 25 with a caching_sha2 user d97339f + #11366 patch, the same probe 4 of 25 runs The fix lies in the #11297 series ("class captures live in the class environment, not on instances"), in the range cef4301..3f6eb6c. The intermediate commits in that range do not compile on their own, so git bisect cannot narrow it further.
What the wrong value was:
617is exactly whatpacket.parseLengthCodedIntmakes of the byteshi:(0x68-48)*10 + (0x69-48) = 617. So thescolumn was read with the integer reader. The generatedTextRowparser source was correct (result["s"] = packet.readLengthCodedString(fields[1].encoding)), so the wrong method ran at execution time.Before #11297, every class in a CommonJS module body stored its captured outer variables as hidden
__perry_cap_*keys on each instance, and that shifted the instances' layout. That is consistent with a method or slot being resolved to the wrong entry, but I have not proven it.I could not build a package-free regression test:
- Any instrumentation inside mysql2 (logging from
decodeShort, or recording the generated source) makes the bug disappear on the broken build. - A seeded GC schedule also makes it disappear, so it is not a collection-timing bug.
- A hand-written copy of the
Packet/ generated-TextRowshape does not fail on the broken build.
While doing this I found a separate latent bug: under some seeded GC schedules, mysql2 throws
TypeError: value is not a functioninCommand.execute. It is filed as #11400.I suggest closing this issue as fixed by #11297.
- Any instrumentation inside mysql2 (logging from
Correction: this is not fixed. On current main (e6ad5f3) the probe reads
2 617in 4 of 10 runs. The build isPERRY_NO_AUTO_OPTIMIZE=1with amysql_native_passworduser, and #11366 is now on main. The bisect in my previous comment found a window, cef4301..3f6eb6c, in which the bug did not show on this program. That is a change in how often it shows, not a fix. I am continuing to investigate.I found the cause and the fix is up as #11432. The
VTABLE_ICinline cache matched an entry on the method-name address alone. Thenew Functioninterpreter, which runs mysql2's generated row parser, passes each call's method name in a short-lived buffer. When a freedparseLengthCodedIntbuffer was reused at the same address forreadLengthCodedString, the cache ranparseLengthCodedIntin its place. A debug build confirmed this with a backtrace.- added a commit that references this issue
on Sep 26, 2026
Found while validating #11335 on perrymaster (Linux x86_64) against a private MySQL 8.0.46, with mysql2 3.24.4. The oracle is Node 26.5.1.
A string column sometimes comes back as the wrong value.
SELECT 1 + 1 AS two, 'hi' AS sthroughmysql2/promiseconnection.querysometimes prints2 617instead of2 hi.mysql_native_passworduser and 0 of 15 with acaching_sha2_passworduser. Node was correct every time.encodings/utf7.jstable usenew Array(256). With that change, main showed the wrong value in 7 of 10 runs. So this is not caused by the mysql2 segfaults in createConnection on Linux (3.24.4 / 3.23.2, compiled from source) #11335 fix.Pool, and a pool-connection transaction.generate-function/new Function. Perry runs these in the runtime interpreter (runtime: dynamic code evaluation (new Function) for schema-codegen libs (ajv / fast-json-stringify / find-my-way) — blocks kimi-code #6559), so that is the first place I would look.Repro:
The user was created with
CREATE USER 'perry_native'@'%' IDENTIFIED WITH mysql_native_password BY 'perry'. The build wasPERRY_NO_AUTO_OPTIMIZE=1, and the program was run in a loop. I have not reduced it further.