Closed c3d closed 3 months ago
The problem appears to be really nasty, since it seems like a live garbage collected pointer (obj
) is corrupt and points to a place where it was overwritten by a newly created graphic object. There is no obvious trace of it in the flight recorder.
More specifically:
obj
points to 0x000000010f22ebbc
.(lldb) p obj.safe
(byte *) 0x000000010f22ebbc "\xff\xf9\xff...
lg
is an ID_grob
for a 305x52 bitmap, which uses 2032 bytes as expected:(lldb) p (305+7)/8*8
p (305+7)/8*8
(int) 312
(lldb) p 312*52
p 312*52
(int) 16224
(lldb) p 312*52/8
p 312*52/8
(int) 2028
(lldb) p lg->size()
p lg->size()
(size_t) 2032
(The four bytes overhead is: 1-byte for ID, 2-bytes for 305, one byte for 52)
The problem is that obj
is pointing to a wrong spot, there are only 1850 bytes between obj
and lg
, less than the 2032 in lg
.
(lldb) p obj.safe-lg.safe
p obj.safe-lg.safe
(long) 1850
obj
was containing something that seems valid before, since oid
(which was read from obj->type()
is valid (it contains ID_sub
):lg
is indeed the last object created:
p (byte*)rt.Temporaries-(byte*)lg.safe
(long) 2032
So it's really a matter of obj
pointing to something wrong.
The current oid
is ID_sub
(lldb) p oid
(object::id) ID_sub
One level up, it's ID_TestEQ
:
(lldb) up
frame #5: 0x00000001000a6e24 db48x`expression::graph(grapher&, unsigned int, int&) + 4252 at /Users/ddd/Work/calc/db48x/src/expression.cc:1930
1927 if (oid == ID_pow || oid == ID_xroot ||
1928 oid == ID_comb || oid == ID_perm)
1929 g.reduce_font();
-> 1930 grob_g rg = graph(g, depth, rprec);
^
1931 coord rv = g.voffset;
1932 if (oid != ID_comb && oid != ID_perm)
1933 g.font = fid;
(lldb) p oid
(object::id) ID_TestEQ
This is consistent with expectations. One level up, we are in GRAPH_BODY(expression)
, but expr
is not an expression, it's an equation. That may be part of the problem.
(lldb) d expr
(cstring) 0x000000010f22ec72 "EquationsMenu14"
(lldb) p expr->type()
(object::id) ID_EquationsMenu14
Above that, we are in stack rendering code, so we are rendering an equation as a transient object through draw_object
. This is expected. What we have here is where the problem most likely resides: draw_object
iteratoes on graph = obj->graph(g)
without having a GC pointer for obj
. So that's how we got a stale obj
down the chain.
That theory would explain why we only see that in the solving menu, which is practically the only place with a transient object being drawn.
Running the test suite, occasional crash / assert solving equations:
Breakpoint in
object_error
shows that the problem is in graphic rendering:The object is a bit after the graphic object, and that its content has been overwritten by what looks like bitap data:
The object was valid before the invokation of graphing functoin, so this seems to confirm that there was some kind of drawing outside of bounds.