[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Tinycc-devel] Segmentation fault compiling jslong.c

From: Rob Landley
Subject: Re: [Tinycc-devel] Segmentation fault compiling jslong.c
Date: Thu, 20 Sep 2007 04:01:48 -0500
User-agent: KMail/1.9.6

On Tuesday 18 September 2007 2:25:20 pm Rob Landley wrote:
> On Tuesday 18 September 2007 11:17:17 am Sanghyeon Seo wrote:
> > Hi,
> >
> > I'm trying to get Spidermonkey built on TCC, which didn't go well.
> >
> > How to reproduce:
> >
> > wget http://ftp.mozilla.org/pub/mozilla.org/js/js-1.60.tar.gz
> > tar zxf js-1.60.tar.gz
> > cd js/src
> > make -f Makefile.ref CC=tcc
> Specifically, the segfaulting line is:
> tcc -o Linux_All_DBG.OBJ/jslong.o -c -Wall -Wno-format -g -DXP_UNIX -DSVR4
> -DDEBUG -DDEBUG_landley -DEDITLINE -ILinux_All_DBG.OBJ  jslong.c
> Hmmm...  -E preprocesses it without a segfault, but then compiling the
> resulting .c segfaults.  Let's try commenting out the second half of that
> file...  Second 1/4,  second 1/8...  Ok, the bit that segfaults is right at
> the end, and it can be narrowed down to...
> typedef long long JSInt64 ;
> static JSInt64 ll_zero = ( ( 0x00000000LL << 32 ) + 0x00000000LL ) ;
> Compiling those two lines segfaults.
> I'll try to track it down this evening.  Thanks for the bug report.
> Rob

Status report on your bug:

What's happening is that in tcc.c, gen_opl() is getting called with TOK_SHL, 
to generate a 64 bit (long long) shift left on the top two arguments of the 
stack (vtop and vtop[-1]).  This is calling lexpand() (to split the long long 
into two ints), which calls gv(RC_INT), and that calls load(vtop) which gets 
us into i386/gen-i386.c to actually generate some code.

load() takes the else case of the first big if statement (it's not an LVAL), 
notices it wants a VT_CONST, and now it knows what bytecodes to emit so it 
calls o(0xb8+r) to output the actual machine language.  (Note that r is 0 
here, so it's trying to output 0xb8 to the current code section.)

o() calls g() in a loop to output a byte at a time (yeah, non-optimal but it's 
a tight loop running in L1 cache), and g() looks like this:

void g(int c)
    int ind1;
    ind1 = ind + 1;
    if (ind1 > cur_text_section->data_allocated)
        section_realloc(cur_text_section, ind1);
    cur_text_section->data[ind] = c;
    ind = ind1;

So the first thing that does is check cur_text_section->data_allocated to see 
if it has to allocate more data into the current text section.  And _that_ is 
where the segfault happens, because cur_text_section is NULL, because we're 
not _in_ a text section yet.

It's trying to output global initialization code, and doesn't seem to know 
where to put it.

There's two problems here:

1) The constness of long long shifts is getting lost, so it's winding up 
trying to generate code when it shouldn't.

2) Attempts to generate code before the first function declaration segfault 
the compiler, which is very wrong.

To see what's going on:  If you compile this example instead of the one shown 

int main(int argc,char *argv[])
  return 0;
typedef long long JSInt64 ;
static JSInt64 ll_zero = ( ( 0x00000000LL << 32 ) + 0x00000000LL ) ;

You get the error "initializer element is not constant".  (The code it tried 
to generate got appended to the text segment for main(), and right after 
doing so it realized it that this wasn't a context in which running that code 
would work, and errored out.)

Now insert "int thingy=printf("ook\n");"  of that example, and we're back to 
segfaulting during the compile again.

The attempt to generate code segfaults when no text section has been 
initialized yet, because it follows a null pointer to see if it needs to 
allocate more space to the nonexistent text section.  But it shouldn't be 
attempting to generate code here anyway, because (long long << int) should 
result in a constant evaluated at compile time.

Yes, _two_bugs_ for the price of one testcase!

The constant propagation thing is relatively straightforward, the "int 
thingy=printf();" thing I'm not 100% sure about, is that allowed in c99?  I 
know c++ has constructors that run before main() does, can you do something 
equivalent in C?

I note that gcc complains "initializer is not constant" for the attempt to 
initialize a global with "int thingy=printf("");", so I'm guessing it's _not_ 
allowed.  But I'd appreciate somebody more familiar with the expected 
behavior here to pipe up, if they can...

Anyway, that's as far as I go on this tonight, it's coming up on 4am, bang on 
it some more later...


P.S.  I note that cur_text_section seems to be initialized on line 8412-8414 
of tcc.c.  This chunk of code can only be reached if you're defining a 
function, so there doesn't seem to be anywhere to put code before or after 
main(), yet we presumably support atexit()...?
"One of my most productive days was throwing away 1000 lines of code."
  - Ken Thompson.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]