Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

Why do deep paths in \usepackage cause texmex to crash (segmentation violation)?

Asked by Joseph on 31 Oct 2012

Short version:

I call texmex.mexw64 on a tex file, like this:

[dvi,loginfo,err] = texmex(tstr, texpath, 1, logical(0));

The string tstr is essentially the entire tex file. In it, I specify what packages to use and the path to them ('\usepackage{...}'). If that path is too deep, matlab crashes. Why, and is there a workaround (other than moving my files around, creating junctions, etc.)? [Actually, the problem appears to be the length of the pathname/filename, not the path depth; see update at bottom.]

Long version:

Matlab provides a mex file called texmex.mexw64 (in matlabroot/toolbox/matlab/graphics/private) for generating LaTeX (for plot titles, etc.); in particular, it generates dvi output from tex inputs. Normally, it's invoked by tex.m (one directory up), but I'd like to use packages that aren't included in tex.m. (In fact, I first generated this error when running a modified version of tex.m, but I can regenerate it more simply by invoking texmex directly from the command line.) The original c code that generated texmex.mexw64 isn't available, so I can't hunt down the bug any further.

Here's a minimal working/non-working example:

clear; clc; close all;
% get access to private texmex files
%%% This is *not* the problem!
privateDir = [matlabroot,'\toolbox\matlab\graphics\private'];
texmexPrvt = get_private_fcn(privateDir,'texmex');
mlinitexPrvt = get_private_fcn(privateDir,'mlinitex');
% set tex path
%%% This is also not the problem, just part of the MWE. 
texpath{1} = fullfile(matlabroot,'sys','fonts','type1','cm',filesep);
texpath{end+1} = fullfile(matlabroot,'sys','tex',filesep);
texpath{end+1} = fullfile(matlabroot,'sys','tex','latex','base',filesep);
texpath{end+1} = fullfile(matlabroot,'sys','tex','tfm',filesep);
[c,maxsize,endian] = computer;
if strncmp(endian,'B',1)
    texpath{end+1} =...
        fullfile(matlabroot,'sys','tex','format','bigendian',filesep);
else
    texpath{end+1} =...
        fullfile(matlabroot,'sys','tex','format','smallendian',filesep);
end
setappdata(0,'TeXPath',texpath);
% test
%%% this version works
strint = '%&latex \nofiles \documentclass{mwarticle} ';
strpkge = '\usepackage{C:/stys/two/three/four/five/six/foo} ';
strbgn = '\begin{document}\setbox0=\hbox{$\foofoo$}';
strend = '\copy0\special{bounds: \the\wd0 \the\ht0 \the\dp0} \end{document}';
sstr = [strint,strpkge,strbgn,strend];
[dvi,loginfo,err]=texmexPrvt(sstr, texpath, 1, logical(0));
pause();
%%% this version does not work
strpkge = '\usepackage{C:/stys/two/three/four/five/six/seven/foo} ';
sstr = [strint,strpkge,strbgn,strend];
[dvi,loginfo,err]=texmexPrvt(sstr, texpath, 1, logical(0));

The sty file foo.sty lives in both directories, C:/stys/two/three/four/five/six/ and C:/stys/two/three/four/five/six/seven, but somehow the latter is one too deep (apparently) for matlab to find it. (The style file itself is not the problem; it consists of a single macro, \newcommand{\foofoo}{\bf s}.) Running the last three lines above yields a segmentation violation. I doubt the register values at crash time or etc. will help. I also suspect that this directory issue is one of several in texmex. What I'd really like is to get the original c file, but short of that I'd like to know why this is happening and how to work around it. I don't want to move my style files around to different directories.

Thanks.

[UPDATE] In fact, it appears that the problem isn't the path depth, but the length of the pathname/filename. I don't want to keep crashing matlab to find out, but it looks like the limit is 32 characters.

4 Comments

Honglei Chen on 31 Oct 2012

Never knew this exists

Joseph on 31 Oct 2012

Here's hoping someone from the mathworks will get back to me; but meantime, one (suboptimal) workaround on Windows is to make junctions:

http://technet.microsoft.com/en-us/sysinternals/bb896768.aspx

to the required directories into directories with short names. (Shortcuts on Windows won't work since they're not real links.)

Joseph on 1 Nov 2012

After quite a bit of headache, I've decided that trying to coax matlab's texmex into behaving properly isn't worth it. Instead I've edited the file tex.m to use the latex that's already in the Windows path, i.e. from my copy of the MiKTeX distribution. In case anyone else wants some similar functionality (giving matlab access to one's own style files, to other packages that are available through MiKTeX, etc. etc.), I'm posting my edited version here. It lives in some directory that has higher priority in the path than matlabroot/toolbox/matlab/graphics/, which is where the original tex.m lives. Everything I've edited has been clearly marked. It's possible that this breaks something else---I haven't thoroughly checked---but it works for, e.g., this:

h = text('string','$\overset{*}{X}$','interpreter','latex','pos',[0.2 0.5],'Fontsize',30);

Note that I've also put a copy of mwarticle.cls from matlabroot\sys\tex\ into the directory where the tex files are to be written (for me, C:\Documents and Settings\username\My Documents\#texs\matlab). You can see where I placed the usepackage lines and therefore where to add your own.

[UPDATE: Daniel has alerted me to the fact that this function, being matlab's, is copyrighted. I've pared it down to just my edits and the surrounding code (for context).]

function [dviout,errout,auxout] = tex(str,varargin)
%
% ...omitting help-section commenting...
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%% MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fprintf('USING THE MODIFIED tex.m -- jgm\n');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%...omitting matlab's code...  
%
if isempty(err)
    [tstr] = localDecorateInputString(str,format,width,fragment);
      %%%%%%%%%%%%%%%%%%%%%%%%%%% MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%%%%%%%%
      % [dvi,loginfo,err] = localCallTeXParser(tstr,doinitex,verbose,dofileio);
      % write preamble to .tex file
      cstr = '\nofiles \documentclass{mwarticle} ';
      cstr = [cstr,'\newcommand{\stydir}{../stys} '];
      cstr = [cstr,'\usepackage{amsmath,amssymb,amsfonts,'];
      cstr = [cstr,'graphicx,color,amsthm,versions,nameref,'];
      cstr = [cstr,'\stydir/jgmstd,\stydir/rbmish,\stydir/optimal} '];
      cstr = [cstr,tstr];
      % switch to your own tex/matlab directory, where you keep mwarticle.cls
      texdir = 'C:\Documents and Settings\username\My Documents\#texs\matlab';
      olddir = cd(texdir);
      texID = fopen('matTeX.tex','w');
      fwrite(texID,cstr);
      fclose(texID);
      % run MiKTeX's latex (it's on the path)
      !latex -quiet -src-specials -interaction=nonstopmode matTeX.tex
      % get the contents of the dvi file
      FID = fopen('matTeX.dvi','r');
      dvidbl = fread(FID);
      fclose(FID);
      dvi = uint8(dvidbl);
      err = '';
      loginfo = {};
      % return to the working dir
      cd(olddir)
      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end
%
%...omitting matlab's code...  
%
function [tstr] = localDecorateInputString(str,format,width,fragment)
%
%...omitting matlab's code...  
%
if strcmp(format(3:end),'latex')
      %%%%%%%%%%%%%%%%%%%%%%%%%%% MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%%%%%%%%
      % standardhead =' \nofiles \documentclass{mwarticle} \begin{document}';
      standardhead = ' \begin{document}';
      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      standardtail = ' \end{document}';
  else
      standardhead = ' \relax \nopagenumbers \noindent';
      standardtail = ' \bye';
  end
if isempty(width)
     %
     %...omitting matlab's code...  
     %
      if fragment
          %%%%%%%%%%%%%%%%%%%%%%%%% MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%%%%%%
          % tstr = [ format standardhead '\setbox0=\hbox{' tstr ...
          %   '}\copy0\special{bounds: \the\wd0 \the\ht0 \the\dp0}' ...
          %	standardtail];
          tstr = [standardhead '\setbox0=\hbox{' tstr ...
              '}\copy0\special{bounds: \the\wd0 \the\ht0 \the\dp0}' ...
              standardtail];
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      else
          % For now, let input string define format, this is used when
          % generating format files (i.e. plain.fmt)
          %  tstr = [ format ' ' tstr ];
      end
  else
      if fragment
          %%%%%%%%%%%%%%%%%%%%%%%%% MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%%%%%%
          % tstr = [ format standardhead ' \hsize=' width ' \setbox0=\hbox{' str ...
          %   '}\copy0\special{bounds: \the\wd0 \the\ht0 \the\dp0}' ...
          %	standardtail];
          tstr = [standardhead ' \hsize=' width ' \setbox0=\hbox{' str ...
              '}\copy0\special{bounds: \the\wd0 \the\ht0 \the\dp0}' ...
              standardtail];
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      else
          %%%%%%%%%%%%%%%%%%%%%%%%% MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%%%%%%
          % tstr = [ format ' ' tstr ];
          tstr = [ ' ' tstr ];
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      end
  end
end
%-------------------------------------------------------------------------%
%-------------------------------------------------------------------------%
function [dvi,loginfo,err] =...
    localCallTeXParser(tstr,doinitex,verbose,dofileio)
%%% You no longer need to use this function.  Just in case, though, you've
%%% left in the workaround to get to the private mex files. (JGM)
dvi = [];
loginfo = [];
%err = [];
[texpath,err] = localGetTeXPath;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
privateDir = [matlabroot,'\toolbox\matlab\graphics\private'];
texmexPrvt = get_private_fcn(privateDir,'texmex');
mlinitexPrvt = get_private_fcn(privateDir,'mlinitex');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
try
    if isempty(err)
        % Send output to files
        if dofileio
            if doinitex
                %%%%%%%%%%%%%%%%%%%%%% MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%
                mlinitexPrvt(tstr, texpath, verbose, dofileio);
            else
                texmexPrvt(tstr, texpath, verbose, dofileio);
                %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            end
            % Send output to return variables
        else
            if doinitex
                %%%%%%%%%%%%%%%%%%%%%% MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%
                [dvi,loginfo,err] =...
                    mlinitexPrvt(tstr, texpath, verbose, dofileio);
            else
                [dvi,loginfo,err] =...
                    texmexPrvt(tstr, texpath, verbose, dofileio);
                %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            end
        end
    end
%
%...omitting matlab's code...  
%
function localLoadType1FontsOnWindows(names,paths)
%
%...omitting matlab's code...  
%
while n<length(names)
   %
   %...omitting matlab's code...  
   %  
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MODIFIED BY JGM %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
privateDir = [matlabroot,'\toolbox\matlab\graphics\private'];
loadfontsPrvt = get_private_fcn(privateDir,'loadfonts');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Pass to mexfile for GDI loading
loadfontsPrvt(path_2_pfm_pfb_files);
end
%
%...omitting matlab's code...  
%
Joseph

Products

No products are associated with this question.

1 Answer

Answer by Daniel on 2 Nov 2012
Accepted answer

I can recreate your problem on R2011a Linux. I modified your MWE to be

texpath{end+1} = 'C:/stys/two/three/four/five/six/seven/';
strpkge = '\usepackage{foo} ';

and it works. I would think that the 'addpath' pv of tex.m would do this automatically, but I haven't tested it. I am not sure what your actual use case is but I cannot easily think of a use case where you want to give the path in \usepackage instead of adding it to the search path. That said, I don't know why it crashes. I was hoping to be able to replace the "tex binary" that texmex relies on, but I wasn't able to find it.

1 Comment

Joseph on 2 Nov 2012

Yes, that works! As you say, it still doesn't say why matlab's latex can't use long path names.... But some mysteries are better left unsolved: I recommend to any matlab users seeking to accomplish what I was---using lots of non-default latex style files within matlab---not to use this approach at all, but to modify tex.m along the lines of my (long) comment above. Adding each directory to matlab's texpath (my original approach) will generally be far more work than relying on the directory structure of one's own latex distribution (MiKTeX, etc.).

If you don't like modifying matlab's internal files, though, or if you don't have another dstrb of latex on your machine, take the original approach, w/Daniel's v. helpful solution.

Daniel

Contact us