When writing a gnuplot plugin i ran into a weird bug.
I ran the following commands in gnuplot:
import f(x) from "test.so:test"
print f(1.6)
print f(1)
As you should be able to verify, the result of RVAL
is incorrect, because RVAL
does not explicitly cast to int
and rather converts the int64_t
to a double. The int64_t
however still contains data from the previous invocation (at least on my machine, in general the data is probably undefined), leading to confusingly wrong numbers.
This should be easily fixed by using
return (double)(int) v.v.int_val;
instead of
return (double) v.v.int_val;
More precisely the actual size of int
that is used should be provided, i guess.
Here is a transcript of the results on my machine, including the version of gnuplot. I'm running on Debian.
G N U P L O T
Version 5.2 patchlevel 6 last modified 2019-01-01
Copyright (C) 1986-1993, 1998, 2004, 2007-2018
Thomas Williams, Colin Kelley and many others
[...]
gnuplot> import f(x) from "test.so:test"
gnuplot> print f(1.6)
1
type: 2
as int64: 4609884578576439706
as int: -1717986918
as cmplx: 1.600000 + 0.000000i
via RVAL: 1.600000
via IVAL: 1
<undefined>
gnuplot> print f(1)
1
type: 1
as int64: 4609884575999459329
as int: 1
as cmplx: 1.599999 + 0.000000i
via RVAL: 4609884575999459328.000000
via IVAL: 1
<undefined>
The source test.c
is included as attachement.
I'm sorry that I couldn't chekc, whether this bug is maybe already resolved somewhere, but i couldn't find a bug repot relating to plugins in general.
Please tell me if anything is unclear. Thanks a lot for your work.
I cannot reproduce your result with running gnuplot 5.2.6 and building your test case in the demo/plugin source directory for the 5.2.6 distribution. My test machine is x86, gcc version 12.3.0. I get the following output, which looks correct to me, and valgrind does not report any access to uninitialized memory.
However I can reproduce your result in other versions of gnuplot starting with 5.4.0
if the
enum DATA_TYPES
as defined in gnuplot_plugin.h get out of sync with thecorresponding
enum DATA_TYPES
in the main source directory .../src/gp_types.hThis mis-match causes the print statement to chase down the wrong code path. Or, depending on how bad the mis-match is, it may segfault.
So I wonder if it is possible that you are building your plugin from more recent source than the gnuplot 5.2.6 executable you are loading it from? Clearly there should be some version check done by the plugin loading code, but sadly there is not. I will definitely file that as a "must fix" item for the next gnuplot release.
And it is embarrassing that just such a mismatch exists throughout the 5.4 code base and persists in the development branch. So repairing the mis-match also becomes an immediate "must fix".
Work-around
You can hit this mis-match in source files if you are using the plugin demo source distributed with gnuplot versions 5.4.0 throuth 5.4.8. You can repair it by applying the patch below and rebuilding your plugin. You do not need to rebuild gnuplot itself.
Summary:
* I can't reproduce the problem in 5.2.6 . I think the cast from int64_t->double is correct as written.
* The problem as reported definitely does affect version 5.4 because the types in the source file gnuplot_plugin.h provided as an example do not match those in the executable built from 5.4 source. Oops.
* The attached patch will repair the header file provided for the demo plugin in version 5.4
* I will leave this bug open at least until a fix appears in the next gnuplot release.
Last edit: Ethan Merritt 2023-06-22
Thanks a lot for the quick response @sfeam. You are actually right, I did forget that my
gnuplot_plugin.h
was not actually coming from my version of gnuplot but I instead downloaded it from the github-repo (commit 109ab067724012d20b31663bc71664ad462a8eb4). However,gnuplot_plugin.h
did actually not change since 5 years according to commit history, so that alone should not cause the issue.Also, applying your patch does change the printing of the returned value from
<undefined>
toNaN
, but this wasn't my issue. This kind of makes sense though, since the problem is only dealing with theINTGR
andCMPLX
types, of which the values don't change (they are still1
and2
respectively).Another thought: I'm running on x86_64, so maybe the size of
int
is different on my machine compared to yours? Then it would make sense why you can't reproduce the bug, if for you the sizes "accidentally" coincides and for some reason it doesn't for me.Just for fun, I did explicitly check using
sizeof
and I did get:My gcc version is
gcc (Debian 8.3.0-6) 8.3.0
btw. Let me know if there are any more questions and how I can help you reproduce the bug.Finally, in case it helps anybody, I actually don't observe the bug anymore if I apply the attached patch (which is what I described in my OP). For me this implies that there is something weird going on there with the data types, else it wouldn't apparently solve the issue, right?
Last edit: L L 2023-06-22
Gnuplot started using 64-bit integer variables in version 5.4. Your gnuplot executable for 5.2.6 almost certainly uses only 32-bit integers unless someone customized it to match 5.4 (possible, but why do that rather than just switching to 5.4?)
So yeah, part of the header mismatch
src/gp_types.h
anddemo/plugin/gnuplot_plugin.h
both definestruct value
to use 32-bit ints. (Actually the later simply #includes the former).src/gp_types.h
definesstruct value
to use type intgr_t, which is either 32- or 64- bit as detected at program build time by the content of the system header<inttypes.h>
.demo/plugin/gnuplot_plugin.h
explicitly uses int64_t, which is potentially a mis-match with a gnuplot executable built to use 32-bit ints.So the version mismatch problem is actually worse than I thought, at least if you are mixing 32- and 64- bit header definitions for
value.v.int_val
.None of that really explains why you and I see different output when running your test case on 5.2.6 built with the 5.2.6 source. If you built the plugin with a plugin header from 5.4 that might explain it.
By the way "github repo"?? The gnuplot source lives on SourceForge. If you found a repo on github I don't know who put it there or what exactly its provenance is. In the canonical gnuplot git repository there is no commit with the hash you quote.