[Issue 8899] New: Erroneous delegate usage and map template

d-bugmail at puremagic.com d-bugmail at puremagic.com
Fri Oct 26 13:44:52 PDT 2012


http://d.puremagic.com/issues/show_bug.cgi?id=8899

           Summary: Erroneous delegate usage and map template
           Product: D
           Version: unspecified
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody at puremagic.com
        ReportedBy: maxim at maxim-fomin.ru


--- Comment #0 from Maxim Fomin <maxim at maxim-fomin.ru> 2012-10-26 13:44:49 PDT ---
Currently dmd incorrectly treats delegates declared when type of parameter is
omitted:

------------------------
import std.stdio;

void main()
{
    auto x = 0;
    writeln(typeof(a=>x).stringof);
    writeln(typeof((int a)=>x).stringof);
    writeln(typeof(delegate (a) { return x; }).stringof);
    writeln(typeof(delegate (int a) { return x; }).stringof);
}
-------------------------

This is available at dpaste http://dpaste.dzfl.pl/738f7301

The way map template accepts function parameter allows to hide type mismatch
(if a=>c is used in other contexts, dmd will complain about inability to deduct
arguments of type void). 

Exploit example is below:

-----main.d--------------
version (bug)
{
    import std.string;
}

import test;

void main()
{
    testfun();
}
-------test.d-----------
import std.algorithm;
import std.stdio;

void testfun()
{
    int c = 0;
    writeln([0].map!(a=>c)[0]);
}
-------------------------

Depending on whether bug version is set or not, the program may run correctly
or not. The only significant difference in generated code is in lambda
function. In correct version it takes local value from -30(%rdx), in the broken
version from (%rdx). It may seem wired how importing standard module can change
behavior. 

Fixing syntax to delegate(int a) {} or (int a) => helps.

Probably the bug comes from how dmd arranges code generation. If main.d
includes std.string (or other heavily templated module) it is forced to
instantiate templates when it generates code for main module even if they are
irrelevant. However, because main imports test, it instantiates map template
and generates delegate before code of test function is generated. 

Relevant parts of compilation logs of runnable and buggy versions:

----buggy.txt-----
import    object    
import    std.string //imported, forcing instantiation during main codegen
.....
code      main
function  D main
function  std.array.empty!(int).empty
function  std.array.popFront!(int[]).popFront
function  std.array.front!(int).front
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.back
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.popBack
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.this
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.empty
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.popFront
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.front
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.opIndex
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.length
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.opSlice
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.save
....
function  test.testfun.__lambda2!(int).__lambda2 // testfunc isn't yet
generated
....
code      test
function  test.testfun
function  test.testfun.map!(__lambda2).map!(int[]).map
----runnable.txt-------
code      main
function  D main
code      test
function  test.testfun
function  std.array.empty!(int).empty
function  std.array.popFront!(int[]).popFront
function  std.array.front!(int).front
function  test.testfun.map!(__lambda2).map!(int[]).map
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.back
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.popBack
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.this
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.empty
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.popFront
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.front
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.opIndex
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.length
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.opSlice
function  test.testfun.MapResult!(__lambda2,int[]).MapResult.save
.....
function  test.testfun.__lambda2!(int).__lambda2
------------------------
So, probably the problem is in generating delegate before generating function
which local variables are accessed by delegate. 

This issue summarizes information from following issues:
- 8514 : delegate and map leads to segfault, importing standard module affects
behavior
- 8854 : as described above 
- 8832 : similar code which uses map and delegate has different and incorrect
behavior
- 5064 (???): program crashes when using map and delegate
- 7978 : map, take and iota functions with delegates

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------


More information about the Digitalmars-d-bugs mailing list