Jump to page: 1 2
Thread overview
segfault
Nov 10, 2010
spir
Nov 11, 2010
Daniel Murphy
Nov 11, 2010
spir
Nov 11, 2010
spir
Nov 11, 2010
spir
Nov 11, 2010
spir
Nov 11, 2010
Pelle Månsson
Nov 12, 2010
spir
Nov 13, 2010
spir
Nov 14, 2010
Pelle Månsson
November 10, 2010
Hello D programmers,


I'm blocked by a mysterious segfault I seem to be unable to diagnose. There is probably some point of D I have not yet understood. Below relevant piece of code; "***" marks debug instructions.

The constructor works fine, assertions pass, and writeln writes:
    ([0-9]+ ("+" [0-9]+)*)
But when I call the method 'check', writeln writes
    (null null)
Which means that this.pattern's sub-patterns have disappeared. See line constructing this.pattern in constructor to have an idea (I even tried to replace sep & element by this.sep & this.element, but this does not help).

When matching with this.pattern later in check(), I get a segfault because the code tries to recursively match its sub-patterns (the null items).


Denis


class List : Pattern {
    // ...
    Pattern element;
    Pattern sep;
    Tuple pattern;
    uint min;

    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))
            );
        assert ((this.element !is null) && (this.sep !is null));    // ***
        assert (this.pattern !is null);                             // ***
        writeln(this.pattern);                                      // ***
    }

    override Result check (Source source) {
        assert (this.pattern !is null);                             // ***
        writeln(this.pattern);                                      // ***
        // ...

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

spir.wikidot.com

November 11, 2010
What happens if you make pattern const?


November 11, 2010
On Wed, 10 Nov 2010 07:13:21 -0500, spir <denis.spir@gmail.com> wrote:

> Hello D programmers,
>
>
> I'm blocked by a mysterious segfault I seem to be unable to diagnose. There is probably some point of D I have not yet understood. Below relevant piece of code; "***" marks debug instructions.

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
November 11, 2010
On Thu, 11 Nov 2010 07:47:01 -0500
"Steven Schveighoffer" <schveiguy@yahoo.com> wrote:

> On Wed, 10 Nov 2010 07:13:21 -0500, spir <denis.spir@gmail.com> wrote:
> 
> > Hello D programmers,
> >
> >
> > I'm blocked by a mysterious segfault I seem to be unable to diagnose. There is probably some point of D I have not yet understood. Below relevant piece of code; "***" marks debug instructions.
> 
> 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

All right, I'll try to do that. It'll be difficult, but I need to progress anyway.

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

spir.wikidot.com

November 11, 2010
On Thu, 11 Nov 2010 07:47:01 -0500
"Steven Schveighoffer" <schveiguy@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.

This is a PEG matching lib. Patterns and whole grammars are written in plain D, eg:
    DOT = new Character('.');
    digits = new String(new Klass("0-9"));
    integer = new Tuple(digits, DOT, digits);
There are about 15 little test suites running fine for all bases (Node types, Exceptions, Pattern), utilities, and every Pattern type, including 3 other helpers like List.

List is a helper for matching lists of separated items -- a very common & annoying case. It does not only build the actual pattern, but also extracts the elements out of the mess for you (see embedded doc).

Its actual pattern is constructed in this(), as a Tuple formed of a sub-pattern matching the first element, and a ZeroOrMore repetition matching more (sep pattern) Tuples (see this()). The test case is as follows:
    auto number = new String(new Klass("0-9"));
    auto PLUS = new Literal("+");
    auto addition = new List(number, PLUS);
Writing out the constructed pattern attribute at the end of this() correctly gives:
    pattern: ([0-9]+ ("+" [0-9]+)*)

(Since a List's actual pattern is an instance of Tuple, what is shown here is the result of Tuple's toString(), which itself uses a tool func listText() --> code below after the class and test case.)

Using a List instance (here 'addition') is calling an operational method, of which only 'match' is implemented yet (in Pattern). Match does little stuff more that delegating to check(source) (specialised in List). If I then write out the pattern from check(), I read:
    pattern: (null null)
Thus, no surprise that I get a segfault when matching, since the top pattern will delegate to null subpatterns.

But strangely enough, I also get a segfault by simply typing "writeln(addition.pattern)" in the test func.

I can also post the whole module somewhere online if needed.

PS: Last minute! I just retried to write out the pattern from inside check(). This time, instead of "(null null)", I get "(DeeMatch.List DeeMatch.Source)". ???
(DeeMatch is the temp. module name, so it's 2 class names.)


Thank you,
Denis


==================== test func ======================
void testList2 () {
    writeln("=== List ========================");
    auto number = new String(new Klass("0-9"));
    auto PLUS = new Literal("+");
    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);

    // If I run a test as is, I get a segfault when
    // accessing one of addition's patterns subpattern.
    // Trick to make code execute w/o segfault:
    // redefine addition.pattern by hand
    addition.pattern = new Tuple(
        number,
        new ZeroOrMore(new Tuple(PLUS,number))
    );

    // Then, I can use addition:
    auto node = addition.match("1+23+456");
    assert (node.toString() == `["1" "23" "456"]`);
    // instead of: `("1" [("+" "23") ("+" "456")])`
}

==================== List class =====================
class List : Pattern {
    /**  pattern type matching a list of separated elements
        Example:
            moreElements = ZeroOrMore(Tuple(sep, element));
            list = Tuple(element, moreElements);
            --> (e1 ((s e2) (s e3)))
        Using List instead works as follows:
            list = List(element, sep);
            --> (e1 e2 e3)
        Parameter min defines minimal number of elements
        (typically 0 1 or 2). */

    static string typename = "List";
    static string errorMessageForm =
        "Cannot find at least %s elements for List pattern %s.";

    Pattern element;
    Pattern sep;
    uint min;
    Tuple pattern;

    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))
        );
        writeln(this.pattern);
    }

    // operational
    override Result check (Source source) {
        /**  Match text and form a list of elements. */
        // Try & match pattern.
        // Note: match mail fail if min==0
        Result result;
        TupleNode node;
        try {
            result = this.pattern.check(source);
            node = cast(TupleNode)(result.node);
        } catch (MatchError e) {
            if (this.min == 0) {
                auto zeroNode = new ListNode(this, []);
                return new Result(zeroNode, source);
            }
            else
                throw e;
        }

        // Extract element nodes.
        // First, get & record first element.
        writeln("*** ", node);
        Node firstElement = node.nodes[0];      // first element node
        Node[] listNodes = [firstElement];      // actual result!

        // Then, get to list of additional elements.
        auto nodeOfPairs = cast(ListNode)(node.nodes[1]);
        TupleNode[] pairNodes = cast(TupleNode[])(nodeOfPairs.nodes);

        // Extract additional elements
        if (pairNodes.length > 0) {
            foreach (TupleNode pairNode ; pairNodes)    // (sep,element) pairs
                listNodes ~= pairNode.nodes[1];
        }

        // Check number of elements.
        if (listNodes.length < this.min) {
            string message = format(this.errorMessageForm, this.min, this);
            throw new MatchFailure(this, source, message);
        }

        // Construct result node.
        auto listNode = new ListNode(this, listNodes);
        return new Result(listNode, source);
    }

    // feedback
    override string toString () {
        /** "List(element, sep, min)" */
        return format("List(%s, %s, %s)", this.element,this.sep,this.min);
    }
}

==================== Tuple toString() =======================
    override string toString () {
        /** "(p1 p2 ...)" */
        return listText!Pattern(this.patterns, " " ,"(",")");
    }
=== using tool func
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);
}



November 11, 2010
On Thu, 11 Nov 2010 10:34:41 -0500, spir <denis.spir@gmail.com> wrote:

> On Thu, 11 Nov 2010 07:47:01 -0500
> "Steven Schveighoffer" <schveiguy@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.

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.  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.

Try this: inside the constructor do:

writeln(this.pattern);
writeln(this);
writeln(this.pattern);

And see if that fails.  If that fails, then we know it's one of those three lines thats messing things up.

Comment out writeln(this), and see if it still fails.  If it does, then it's something being printed in your Tuple class that is causing it to corrupt something so it can't be printed again.  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.

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.

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.

If you have a debugger, it might help even more than these little tricks.

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

> On Thu, 11 Nov 2010 10:34:41 -0500, spir <denis.spir@gmail.com> wrote:
> 
> > On Thu, 11 Nov 2010 07:47:01 -0500
> > "Steven Schveighoffer" <schveiguy@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

November 11, 2010
On Thu, 11 Nov 2010 14:50:10 -0500, spir <denis.spir@gmail.com> wrote:

> 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.

You're welcome, and there are other ways to have issues with pointers.  The most common is not deleting something from the heap, but rather returning stack memory from a function.

>> 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.)

This really sounds like an issue where stack data is being returned.

>> [...]
>> 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);
> }

It's the to!string(element) that I don't have the code to -- each object's toString function.  But I'm no longer worried about that.  If it works properly inside the ctor, it should work properly outside.

>> 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 :-)

It's not unheard of :)  But I still would rule out all other possibilities before concluding that.  I've had very strange dmd bugs where things only fail when certain ordering of structures or code affects them.  It does happen.

>> 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.
>

OK, can we see the code for Tuple?  That may be where something fishy is occurring.

-Steve
November 11, 2010
On Thu, 11 Nov 2010 15:11:34 -0500
"Steven Schveighoffer" <schveiguy@yahoo.com> wrote:

> > 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.
> > 
> 
> OK, can we see the code for Tuple?  That may be where something fishy is occurring.

Well, since the pattern is OK _after_ call to Tuple's constructor (which does nothing more than recording its sub-patterns, see below) and only gets wrong when qutting this(), I fail to see how Tuple could be cause of anything. Also, the corruption is visible _before_ calling match() (which here delegates to Tuple's check()).

I understand your note about returning an object actually allocated on the stack -- but here there are only implicitely referenced objects (class instances). This would mean that D creates the 2 sub-patterns on the stack? But why those objects, precisely? (Also note that they are of different classes: one is here a "String", the other a "ZeroOrMore"). They are stored in an array.

What's troubling is that the array elements, meaning the supposed subpattern addresses, have changed. Maybe the patterns themselves are still ok, but the array data only are corrupted?
Oh, I may try to cast to String the memory area pointed inside this()....... Does not seem to work: I recorded the pointer read in this() (as String*) into a global; then in the test func:
    writeln("p: ",p);       	// ok, same address as in this()
    writeln(cast(String)(*p));	// segfault!

Anyway, just in case my reasoning is wrong, here is the whole Tuple class:

====================================================
class Tuple : Pattern {
    /**  pattern type for tuple of given patterns */
    static string typename = "Tuple";
    Pattern[] patterns;
    this (Pattern[] patterns...) {
        this.patterns = patterns;
    }
    // operational
    override Result check (Source source) {
        /**  Check whether text holds successive matches of all patterns. */
        // try & match
        // case success: rest text slice is given by each match result
        // case failure: MatchFailure error is thrown by sub-pattern
        Node[] nodes;
        Result result;
        foreach (Pattern pattern ; patterns) {
            result = pattern.check(source);
            nodes ~= result.node;
            source = result.source;
        }
        auto node = new TupleNode(this, nodes);
        return new Result(node, source);
    }
    // feedback
    override string toString () {
        /** "(p1 p2 ...)" */
        return listText!Pattern(this.patterns, " " ,"(",")");
    }
}


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

spir.wikidot.com

November 11, 2010
On 11/11/2010 10:15 PM, spir wrote:

> Well, since the pattern is OK _after_ call to Tuple's constructor (which does nothing more than recording its sub-patterns, see below) and only gets wrong when qutting this(), I fail to see how Tuple could be cause of anything. Also, the corruption is visible _before_ calling match() (which here delegates to Tuple's check()).
>
> I understand your note about returning an object actually allocated on the stack -- but here there are only implicitely referenced objects (class instances). This would mean that D creates the 2 sub-patterns on the stack? But why those objects, precisely? (Also note that they are of different classes: one is here a "String", the other a "ZeroOrMore"). They are stored in an array.
>
> What's troubling is that the array elements, meaning the supposed subpattern addresses, have changed. Maybe the patterns themselves are still ok, but the array data only are corrupted?
> Oh, I may try to cast to String the memory area pointed inside this()....... Does not seem to work: I recorded the pointer read in this() (as String*) into a global; then in the test func:
>      writeln("p: ",p);       	// ok, same address as in this()
>      writeln(cast(String)(*p));	// segfault!
>
> Anyway, just in case my reasoning is wrong, here is the whole Tuple class:
>
> ====================================================
> class Tuple : Pattern {
>      /**  pattern type for tuple of given patterns */
>      static string typename = "Tuple";
>      Pattern[] patterns;
>      this (Pattern[] patterns...) {
>          this.patterns = patterns;

You need to dup that. Arguments are passed on the stack.
« First   ‹ Prev
1 2