segfault

spir denis.spir at gmail.com
Thu Nov 11 11:50:10 PST 2010


On Thu, 11 Nov 2010 10:52:50 -0500
"Steven Schveighoffer" <schveiguy at yahoo.com> wrote:

> On Thu, 11 Nov 2010 10:34:41 -0500, spir <denis.spir at gmail.com> wrote:
> 
> > On Thu, 11 Nov 2010 07:47:01 -0500
> > "Steven Schveighoffer" <schveiguy at yahoo.com> wrote:
> >
> >> This is not enough code to understand the problem.  For instance,
> >> writefln(pattern) prints a class, but we don't see Pattern's toString
> >> function.  We don't see the code that creates the object and then calls
> >> check.  Maybe something happens between calls?
> >>
> >> It's impossible to diagnose something like this without a working  
> >> example,
> >> so you need to trim it down to something that still compiles and fails,
> >> and then share that entire code.
> >>
> >> -Steve
> >
> > Hello,
> >
> > I tried to build a example mini-app to show the issue more simply, but  
> > couldn't. The point is the bug only shows when using the most  
> > complicated element of my code (class List), built on top of ~ 1000  
> > lines. I guess the best is to try to explain the case and provide  
> > example test. See code of the class and test case below.

Thank you very much for your help, Steve. I think now the bug is not in my code. An evidence is I never play with memory: every element is a class instance (many should later become structs or even simpler thingies, but I first chose this design for simplicity); there is no malloc or such, not even a single pointer; and indeed, I do not deallocate anything manually, and assign nothing to null. So, how come a segfault? See also below.

> This gives a little more information.  From your code, it appears that the  
> constructor has this line:
> 
> writeln(this.pattern);
> 
> Which succeeds.  Then your test code looks like this:
> 
> 
>       auto addition = new List(number, PLUS);
>      // This check works fine:
>       writeln(addition);          // --> List([0-9]+, "+", 2)
>      // But if I uncomment the following: segfault
>       // writeln(addition.pattern);
> 
> Which means between constructor (first line in test code), you printed the  
> item itself, then print the item's pattern field.
> 
> What it looks like to me is that between printing it in the constructor,  
> and printing it outside the constructor, something bad happened.

Exactly. But as you can see above, there is no code running in between. The construtor does only what you've read in the piece of code posted in last message (& the superclass has no this(), it's used for "genericity" and some interface methods to the user).
The pattern (([0-9]+ ("+" [0-9]+)*)) becomes (null null), or other meaningless thing, when the constructor returns. This expression means actually a Tuple of 2 sub-patterns. these sub-patterns exist inside this, and are correct, but then disppear.

>  There  
> are several pieces of code running that I don't have the source for, so I  
> can assume either you have a compiler bug, or it's in one of those pieces.

Nothing else happens.The constructor records data, builds the pattern and returns.

> Try this: inside the constructor do:
> 
> writeln(this.pattern);
> writeln(this);
> writeln(this.pattern);

Runs fine, see also below. I'm sure now that:
* the pattern is ok as long as we remain inside this()
* the pattern is corrupted as soon as we quit this()
(Actually, its contents are corrupted, precisely its field 'pattern', an array that holds its subpatterns.)

> [...]
> If not, then it's  
> something being printed in your List class.  I don't have the code that  
> converts your Pattern class to a string, etc. so I can't say whether they  
> are an issue.

I printed it in last post (but was at the end). It's just a call to a tool func listText that wrap join()Here it is again:

class Tuple : Pattern {
    // ........
    override string toString () {
        /** "(p1 p2 ...)" */
        return listText!Pattern(this.patterns, " " ,"(",")");
    }
}

string listText(Element) (Element[] elements,
        string sep, string lDelim,string rDelim) {
    /** textual representation of elements held in a plain array */
    string[] elementTexts = new string[elements.length];
    foreach (uint i, Element element ; elements)
        elementTexts[i] = to!string(element);
    string content = join(elementTexts, sep);
    return format("%s%s%s", lDelim, content, rDelim);
}

> If those three lines work in the constructor, I'd say there is a possible  
> compiler error, because there is no difference between calling that code  
>  from in the constructor or in the test code.

I agree with your reasoning. (But would not dare concluding there is a bug in dmd :-)

> If that's the case, create a function that prints out all the addresses of  
> things (you can print out the address of a class by simply casting the  
> class reference to a void *).  Print that out between each line and see  
> what changes, then focus there.  Again, without more code, I can't say for  
> certain what's going on.

Here it is: I added some debug code to the constructor and the test func. Below code and output. The segfault happens here on call to match. I added not only the address of the pattern, but also of its .patterns field, and of its 2 sub-patterns.

============== List.this ======================
    this (Pattern element, Pattern sep, uint min=2) {
        this.min = min;
        // for output
        this.element = element;
        this.sep = sep;
        // Construct pattern.
        this.pattern = new Tuple(
            element, 
            new ZeroOrMore(new Tuple(sep,element))
        );
        // checking
        writeln("--- in List.this ---");
        writeln(this.pattern);
        writeln(this);
        writeln(this.pattern);
        writeln(cast(void*)(this));
        writeln(cast(void*)(this.pattern));
        writeln(cast(void*)(this.pattern.patterns));    // array
        writeln(cast(void*)(this.pattern.patterns[0]));
        writeln(cast(void*)(this.pattern.patterns[1]));
    }
============== testList2 ======================
void testList2 () {
    writeln("=== List ========================");
    auto number = new String(new Klass("0-9"));
    auto PLUS = new Literal("+");
    auto addition = new List(number, PLUS);
    
    writeln("--- in testList2 ---");
    writeln(addition);
    writeln(cast(void*)(addition));
    writeln(cast(void*)(addition.pattern));
    writeln(cast(void*)(addition.pattern.patterns));    // array
    writeln(cast(void*)(addition.pattern.patterns[0]));
    writeln(cast(void*)(addition.pattern.patterns[1]));
    
    // use
    auto node = addition.match("1+23+456");
    assert (node.toString() == `["1" "23" "456"]`);
}
============== output ======================
--- in List.this ---
([0-9]+ ("+" [0-9]+)*)
List([0-9]+, "+", 2)
([0-9]+ ("+" [0-9]+)*)
46DF40
46ECA0
BFA107E0
46ECE0
46EC80
--- in testList2 ---
List([0-9]+, "+", 2)
46DF40
46ECA0
BFA107E0
BFA1070A
38C4E0
Segmentation fault


As you see, the addresses of the 2 sub-patterns have changed (but the array that holds them hasn't moved -- and I just checked that cast(void*)array actually returns the ptr). Don't know what to conclude.


Denis
-- -- -- -- -- -- --
vit esse estrany ☣

spir.wikidot.com



More information about the Digitalmars-d-learn mailing list