segfault

Steven Schveighoffer schveiguy at yahoo.com
Thu Nov 11 12:11:34 PST 2010


On Thu, 11 Nov 2010 14:50:10 -0500, spir <denis.spir at 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


More information about the Digitalmars-d-learn mailing list