Skip to content

Infinite recursion in macro expansion crashes compiler #1740

@cgay

Description

@cgay

The following macro and macro call cause a segmentation fault in the compiler.

(Also available here: https://play.opendylan.org/shared/e3ade7dbb9f0d071)

define traced macro enum-definer
    { define enum ?enum-name:name () ?clauses:* end }
 => { ?@defconst{ 1 ; ?clauses }
      define constant "$" ## ?enum-name ## "-names" = vector(?@pretty-names{ ?clauses });
      define constant "$" ## ?enum-name ## "-values" = vector(?@constant-names{ ?clauses }); }

 defconst:
    { ?default:expression } => { }

    // Rewrite foo; => foo = default ("foo");
    { ?default:expression ; ?:name ; ?more:* }
 => { ?@defconst{ ?default ; ?name = ?default (?"name") ; ?more } }

    // Rewrite foo = 1; => foo = 1 ("foo");
    { ?default:expression ; ?:name = ?value:expression ; ?more:* }
 => { ?@defconst{ ?default ; ?name = ?value (?"name") ; ?more } }

    // Rewrite foo ("Foo"); => foo = default ("Foo");
    { ?default:expression ; ?:name (?pretty-name:expression) ; ?more:* }
 => { ?@defconst{ ?default ; ?name = ?default (?pretty-name) ; ?more } }

    // Fully specified case
    { ?default:expression ; ?:name = ?value:expression (?pretty-name:expression) ; ?more:* }
 => { define constant ?name :: <int> = ?value;
      ?@defconst{ ?default ; ?more } }

 constant-names:
    { } => {}
    { ?:name ?junk:* ; ...} => { ?name , ... }

 pretty-names:
    { ?:name = ?:expression { ?pretty-name:expression } ; ... } => { ?pretty-name , ... }
    { ?:name { ?pretty-name:expression } ; ... }                => { ?pretty-name , ... }
    { ?:name = ?:expression ; ... }                             => { ?"name" , ... }
    { ?:name ; ... }                                            => { ?"name" , ... }
    {} => {}
end macro;

define enum color ()
  $color-red;                 // defines $color-red   :: <int> = 1 with name "red"
  $color-green = 20;          // defines $color-green :: <int> = 20 with name "green"
  $color-blue {"Blue"};       // defines $color-blue  :: <int> = 21 with name "Blue"
  $color-cyan = 30 {"Cyan"};  // defines $color-cyan  :: <int> = 30 with name "Cyan"
end;

The sharp eye will notice that I hadn't fixed all the template rules to use { } around the color name yet. Finishing that work (as is done here) prevents the crash.

I'm sure this isn't a minimal test case. I'll try to whittle it down a bit when I get a chance.

I don't yet understand why { } work and ( ) don't, but I did note that when using ( ) in the pretty-names aux rule set the clause $color-cyan = 30 ("Cyan"); was matching { ?:name = ?:expression ; ... } for some reason. I assume that's the same reason for the infinite recursion in the defconst rules as well.

Backtrace from segfault:

dylan-bt
  frame #14   list                                                         0x000001089cd433 libdylan.dylib at list.dylan:37
  frame #15   append-sequence                                              0x0000010a20c7b9 libdfmc-reader.dylib at parser-support.dylan:13
  frame #16   call-parser-action                                           0x0000010943916a libparser-run-time.dylib at dispatch.dylan:305
  frame #17   run-parser                                                   0x00000109439108 libparser-run-time.dylib at dispatch.dylan:395
  frame #18   re-read-fragments                                            0x0000010a20eb9f libdfmc-reader.dylib at interface.dylan:65
  frame #19   parse-constraint                                             0x0000010a36f144 libdfmc-macro-expander.dylib at constraint-parsing.dylan:55
  frame #20   match-expression-constraint                                  0x0000010a37354c libdfmc-macro-expander.dylib at pattern-back-end.dylan:333
  frame #21   Kanonymous_of_generate_functionF225I                         0x0000010a38b8ed libdfmc-macro-expander.dylib at pattern-to-function.dylan:415
  frame #22   Kanonymous_of_generate_pattern_element_functionF308I         0x0000010a38be1b libdfmc-macro-expander.dylib at pattern-to-function.dylan:228
  frame #23   Kanonymous_of_generate_pattern_element_functionF308I         0x0000010a38be82 libdfmc-macro-expander.dylib at pattern-to-function.dylan:229
  frame #24   Kanonymous_of_generate_pattern_element_functionF308I         0x0000010a38be82 libdfmc-macro-expander.dylib at pattern-to-function.dylan:229
  frame #25   Kanonymous_of_generate_structure_parts_functionF322I         0x0000010a38bfba libdfmc-macro-expander.dylib at pattern-to-function.dylan:207
  frame #26   Kanonymous_of_generate_structure_parts_functionF322I         0x0000010a38bfea libdfmc-macro-expander.dylib at pattern-to-function.dylan:209
  frame #27   Kanonymous_of_generate_rule_functionF323I                    0x0000010a38a09d libdfmc-macro-expander.dylib at pattern-to-function.dylan:105
  frame #28   call-list-with-collecting                                    0x0000010a389b0c libdfmc-macro-expander.dylib at pattern-to-function.dylan:570
  frame #29   Kanonymous_of_generate_template_functionF60I                 0x0000010a3894a5 libdfmc-macro-expander.dylib at template-function.dylan:24
  frame #30   call-list-with-collecting                                    0x0000010a389b0c libdfmc-macro-expander.dylib at pattern-to-function.dylan:570
  frame #31   Kanonymous_of_generate_template_functionF60I                 0x0000010a3894a5 libdfmc-macro-expander.dylib at template-function.dylan:24
  frame #32   call-list-with-collecting                                    0x0000010a389b0c libdfmc-macro-expander.dylib at pattern-to-function.dylan:570
  frame #33   Kanonymous_of_generate_template_functionF60I                 0x0000010a3894a5 libdfmc-macro-expander.dylib at template-function.dylan:24
  frame #34   call-list-with-collecting                                    0x0000010a389b0c libdfmc-macro-expander.dylib at pattern-to-function.dylan:570
...etc...

[edit: fixed dead playground links]

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions