ocaml-community / ocaml-mariadb

OCaml bindings to MariaDB, supporting the nonblocking API
55 stars 18 forks source link

Round-trip integer conversion fails on Alpine Linux #57

Closed paurkedal closed 2 months ago

paurkedal commented 2 months ago

I encountered this while setting up GitLab Actions (#56). This seems different from #31, but may possibly be addressed by the same fix. Considering the hexadecimal representation of the integers involved, 0xF4BB4D1 becomes 0x7972000F4BB4D1, it looks like it's getting data from uninitialized memory.

The errors cited below is from https://github.com/paurkedal/ocaml-mariadb/actions/runs/10774054160/job/29875219295 which uses the opam:alpine-ocaml-5.0 container and the same occurs for opam:alpine-ocaml-4.07.

Run sudo -u opam --preserve-env=OCAML_MARIADB_HOST,OCAML_MARIADB_PORT,OCAML_MARIADB_USER,OCAML_MARIADB_PASS,OCAML_MARIADB_DB,OCAML_MARIADB_QUERY opam exec -- dune runtest
#rows: 1
---
       'hello ' || ? 0
done
#rows: 1
---
       'hello ' || ? 0
File "examples/select/dune", line 4, characters 4-34:
4 |     nonblocking_select_stress_test)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Parameter (256619729 : int) came back as (34183816764175569 : int).
>>> 1
#rows: 1
---
       'hello ' || ? 0
File "examples/lwt/dune", line 4, characters 4-31:
4 |     nonblocking_lwt_stress_test)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Parameter (879053180 : int) came back as (28538924689607036 : int).
#rows: 1
---
       'hello ' || ? 0
File "examples/async/dune", line 4, characters 4-33:
4 |     nonblocking_async_stress_test)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Parameter (879053180 : int) came back as (28556516875651452 : int).
Error: Process completed with exit code 1.
paurkedal commented 2 months ago

I now also reproduced the issue manually in an ocaml/opam:alpine-ocaml-4.14 container, with the opam switch updated, to make sure I didn't introduce the bug when converting to dune.

ee0339a621d9:~/ocaml-mariadb$ ./nonblocking_select_stress_test.native 
Parameter (609520357 : int) came back as (30521343884954341 : int).
ee0339a621d9:~/ocaml-mariadb$ git show-ref HEAD
f2689853417c4586bb03e2c04daaa748fbf5dd22 refs/remotes/origin/HEAD
ee0339a621d9:~/ocaml-mariadb$ cat /etc/alpine-release 
3.20.3
ee0339a621d9:~/ocaml-mariadb$ ocamlc --version
4.14.2
paurkedal commented 2 months ago

I tried this again rebasing #48 on the current master, and it looks like it fixes this issue as well.

paurkedal commented 2 months ago

The error happens on encoding the parameter, rather than the return as can be verify by changing

diff --git a/examples/nonblocking/nonblocking_stress_test.ml b/examples/nonblocking/nonblocking_stress_te
st.ml
index 8ba5807..3bf0c0a 100644
--- a/examples/nonblocking/nonblocking_stress_test.ml
+++ b/examples/nonblocking/nonblocking_stress_test.ml
@@ -23,7 +23,7 @@ module Make (W : Mariadb.Nonblocking.Wait) = struct
     if n = 0 then return () else f () >>= fun () -> repeat (n - 1) f

   let string_of_param_type = function
-    | `Int -> "integer"
+    | `Int -> "varchar(20)"
     | `Float -> "double"
     | `String | `Bytes -> "char"
     | `Time -> "datetime"

which gives

d9db68a253ad:~/ocaml-mariadb$ ./nonblocking_select_stress_test.native 
Parameter (609520357 : int) came back as ("30521343884954341" : string).

So, it looks like even though we pass our parameter size to MariaDB, it prefers to read the corresponding data as a full long long.

paurkedal commented 2 months ago

Fixed by #48.