daqana/tikzDevice

"pointer being freed was not allocated" in TikZ_Close (tikzInfo->outColorFileName?)

p00ya opened this issue · 6 comments

p00ya commented

Environment

macOS 10.15.1, tikzDevice 0.12.3
platform x86_64-apple-darwin18.7.0
arch x86_64
os darwin18.7.0
system x86_64, darwin18.7.0
status
major 3
minor 6.1
year 2019
month 07
day 05
svn rev 76782
language R
version.string R version 3.6.1 (2019-07-05)
nickname Action of the Toes

Repro

tikz(
    foo,
    onefile = FALSE,
    timestamp = FALSE
  )
print(bar)
dev.off()

Sorry I don't have a minimal bar for you to repro - I can't tickle the crash consistently. However, I think the fix is obvious even without a repro ;)

Observed behaviour

Creating temporary TikZ metrics dictionary at:
	/Volumes/ramdisk/Rtmpb9zShw/tikzMetricsDictionary
Using TikZ metrics dictionary at:
	/Volumes/ramdisk/Rtmpb9zShw/tikzMetricsDictionary
Measuring dimensions of: \char77
Running command: '/Library/TeX/texbin/pdflatex' -interaction=batchmode -halt-on-error -output-directory '/Volumes/ramdisk/Rtmpb9zShw/tikzDevice10e765bc781c1' 'tikzStringWidthCalc.tex'
[... snip ...]
R(69238,0x116b9edc0) malloc: *** error for object 0x7fed65c638b0: pointer being freed was not allocated
R(69238,0x116b9edc0) malloc: *** set a breakpoint in malloc_error_break to debug

Notes

I'm pretty sure it's

  free(tikzInfo->originalColorFileName);

from https://github.com/daqana/tikzDevice/blob/master/src/tikzDevice.c#L702

I compiled tikzDevice with CFLAGS = -O1 -arch x86_64 -g to help with debugging.
Then after triggering the crash I attached lldb and disassembled the frame:

di -f -m
tikzDevice.so`TikZ_Close:
    0x116959bc0 <+0>:   pushq  %rbp
    0x116959bc1 <+1>:   movq   %rsp, %rbp
    0x116959bc4 <+4>:   pushq  %rbx
    0x116959bc5 <+5>:   pushq  %rax
    0x116959bc6 <+6>:   movq   0xb0(%rdi), %rbx
    0x116959bcd <+13>:  cmpl   $-0x1, 0x88(%rbx)
    0x116959bd4 <+20>:  je     0x116959c0b               ; <+75>
    0x116959bd6 <+22>:  cmpl   $0x1, 0x50(%rbx)
    0x116959bda <+26>:  je     0x116959c2c               ; <+108>
    0x116959bdc <+28>:  cmpl   $-0x1, 0x8c(%rbx)
    0x116959be3 <+35>:  jne    0x116959c2c               ; <+108>
    0x116959be5 <+37>:  leaq   0x2922(%rip), %rsi        ; "\end{tikzpicture}\n"
    0x116959bec <+44>:  movq   %rbx, %rdi
    0x116959bef <+47>:  xorl   %eax, %eax
    0x116959bf1 <+49>:  callq  0x116959750               ; printOutput
    0x116959bf6 <+54>:  movl   $0x0, 0x8c(%rbx)
    0x116959c00 <+64>:  cmpl   $0x1, 0x4c(%rbx)
    0x116959c04 <+68>:  jne    0x116959c32               ; <+114>
    0x116959c06 <+70>:  jmp    0x116959cb0               ; <+240>
    0x116959c0b <+75>:  leaq   0x28ef(%rip), %rsi        ; "\end{scope}\n"
    0x116959c12 <+82>:  movq   %rbx, %rdi
    0x116959c15 <+85>:  xorl   %eax, %eax
    0x116959c17 <+87>:  callq  0x116959750               ; printOutput
    0x116959c1c <+92>:  movl   $0x0, 0x88(%rbx)
    0x116959c26 <+102>: cmpl   $0x1, 0x50(%rbx)
    0x116959c2a <+106>: jne    0x116959bdc               ; <+28>
    0x116959c2c <+108>: cmpl   $0x1, 0x4c(%rbx)
    0x116959c30 <+112>: je     0x116959cb0               ; <+240>
    0x116959c32 <+114>: cmpl   $0x1, 0x48(%rbx)
    0x116959c36 <+118>: je     0x116959cd9               ; <+281>
    0x116959c3c <+124>: cmpl   $0x0, 0x80(%rbx)
    0x116959c43 <+131>: je     0x116959cfa               ; <+314>
    0x116959c49 <+137>: movq   %rbx, %rdi
    0x116959c4c <+140>: callq  0x11695b640               ; TikZ_WriteColorFile
    0x116959c51 <+145>: movq   0x10(%rbx), %rdi
    0x116959c55 <+149>: callq  0x11695c154               ; symbol stub for: free
    0x116959c5a <+154>: cmpl   $0x0, 0x54(%rbx)
    0x116959c5e <+158>: jne    0x116959c69               ; <+169>
    0x116959c60 <+160>: movq   0x18(%rbx), %rdi
    0x116959c64 <+164>: callq  0x11695c154               ; symbol stub for: free
    0x116959c69 <+169>: movq   0x98(%rbx), %rdi
    0x116959c70 <+176>: callq  0x11695c154               ; symbol stub for: free
    0x116959c75 <+181>: movq   0x20(%rbx), %rdi
    0x116959c79 <+185>: callq  0x11695c154               ; symbol stub for: free
->  0x116959c7e <+190>: movq   0x28(%rbx), %rdi
    0x116959c82 <+194>: callq  0x11695c154               ; symbol stub for: free
    0x116959c87 <+199>: movq   0x68(%rbx), %rdi
    0x116959c8b <+203>: callq  0x11695b6c0               ; const_free
    0x116959c90 <+208>: movq   0x70(%rbx), %rdi
    0x116959c94 <+212>: callq  0x11695b6c0               ; const_free
    0x116959c99 <+217>: movq   0x78(%rbx), %rdi
    0x116959c9d <+221>: callq  0x11695b6c0               ; const_free
    0x116959ca2 <+226>: movq   %rbx, %rdi
    0x116959ca5 <+229>: addq   $0x8, %rsp
    0x116959ca9 <+233>: popq   %rbx
    0x116959caa <+234>: popq   %rbp
    0x116959cab <+235>: jmp    0x11695c154               ; symbol stub for: free
    0x116959cb0 <+240>: movq   0x78(%rbx), %rsi
    0x116959cb4 <+244>: movq   %rbx, %rdi
    0x116959cb7 <+247>: xorl   %eax, %eax
    0x116959cb9 <+249>: callq  0x116959750               ; printOutput
    0x116959cbe <+254>: leaq   0x285c(%rip), %rsi        ; "\n\end{document}\n"
    0x116959cc5 <+261>: movq   %rbx, %rdi
    0x116959cc8 <+264>: xorl   %eax, %eax
    0x116959cca <+266>: callq  0x116959750               ; printOutput
    0x116959ccf <+271>: cmpl   $0x1, 0x48(%rbx)
    0x116959cd3 <+275>: jne    0x116959c3c               ; <+124>
    0x116959cd9 <+281>: movl   0x60(%rbx), %edx
    0x116959cdc <+284>: leaq   0x284f(%rip), %rsi        ; "%% Calculated string width %d times\n"
    0x116959ce3 <+291>: movq   %rbx, %rdi
    0x116959ce6 <+294>: xorl   %eax, %eax
    0x116959ce8 <+296>: callq  0x116959750               ; printOutput
    0x116959ced <+301>: cmpl   $0x0, 0x80(%rbx)
    0x116959cf4 <+308>: jne    0x116959c49               ; <+137>
    0x116959cfa <+314>: movq   (%rbx), %rdi
    0x116959cfd <+317>: callq  0x11695c148               ; symbol stub for: fclose
    0x116959d02 <+322>: movq   $0x0, (%rbx)
    0x116959d09 <+329>: jmp    0x116959c49               ; <+137>
    0x116959d0e <+334>: nop    
p00ya commented

Er, miscounted the free()s, I think it's actually

  free(tikzInfo->outColorFileName);

from https://github.com/daqana/tikzDevice/blob/master/src/tikzDevice.c#L701

p00ya commented

It's possible the heap corruption is being caused by a different package (what I'm calling to generate bar), though I can't say for sure since it's difficult to repro.

rstub commented

Please try to find a way to reproduce the issue. Looking at the code it seems that both tikzInfo->outColorFileName and tikzInfo->originalColorFileName are allocated when the colorFile parameter is set. This happens by default, but maybe you are explicitly un-setting this argument?

p00ya commented

I'm not doing anything to explicitly un-set colorFile. I'm pretty sure it's heap corruption because sometimes the pointer being freed has suspicious values like 0xf000000000000000.

p00ya commented

I've played around some more with a debugger attached and it looks like in the cases where the error is triggered, TikZ_Setup is called but somehow TikZ_Open is not. This would explain why outColorFileName is uninitialized.

I'm not expert on the GraphicsDevice API, so I don't really know whether this is expected or not. But I think the error can be avoided by initializing the pointers in TikZ_Setup to NULL, then adding guards in TikZ_Close.

My repro code looks like:

tikz(
  foo,
  onefile = FALSE,
  timestamp = FALSE
)
ThingThatGeneratesBar()
dev.off()

Note that it seems sensitive to seemingly innocuous changes (e.g. if I change ThingThatGeneratesBar() to bar <- ThingThatGeneratesBar(); print(bar), I can't repro anymore). That could just be noise, but it's what makes me wonder about corruption since it smells like non-determinism.

p00ya commented

Okay, consistent repro is:
create a file repro.R with the contents:

library(tikzDevice)
tikz("deleteme", onefile = FALSE)
dev.off()

i.e. this opens a TikZ device, doesn't print anything to it, then closes it. Then call source("repro.R").