Bug 13339 – Address of parameter wrong in out contract

Status
RESOLVED
Resolution
DUPLICATE
Severity
normal
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Linux
Creation time
2014-08-20T11:15:00Z
Last change time
2015-07-01T07:44:35Z
Keywords
contracts
Assigned to
nobody
Creator
tim.dlang

Comments

Comment #0 by tim.dlang — 2014-08-20T11:15:20Z
The following code results in a segmentation fault at runtime when compiled with DMD 2.066 on Arch Linux x86_64: import std.stdio; class A { int x; } class B { void test(size_t i, A a) out { writeln("after: ", &a); auto x = a.x; // Segmentation fault writeln(a.x); } body { void delegate() dg = {size_t s = i;}; writeln("before: ", &a); } } void main() { B b = new B; b.test(1234, new A); } The output shows, that the address of a is different in body and out constract: before: 7FFFC53B81A0 after: 7FA64F4BBFE8 When compiled with LDC 0.14 there is no segmentation fault, but the addresses are still different and the value of a.x is wrong. With GDC 4.9.1 the code does not compile with the following error message: ebnftests.d: In member function '__ensure': ebnftests.d:12: internal compiler error: in expand_expr_real_1, at expr.c:9454 Please submit a full bug report, with preprocessed source if appropriate. See <https://bugs.archlinux.org/> for instructions.
Comment #1 by ibuclaw — 2014-08-20T12:03:36Z
This is a closure-style bug. To fix, either: 1) Taking the address of 'a' should trigger VarDeclaration::checkNestedReference to add it to closureVars. void test(B this, size_t i, A a) { test.closure.a = a; test.closure.this = this; // body... test.out(test.closure); } void test.out(void *this) { // Takes address of &(this.a) ... } or 2) When calling in/out contracts, the parameters of the body function should be passed directly. void test(B this, size_t i, A a) { // body... test.out(this, i, a); } void test.out(void *this, size_t i, A a) { // Takes address of &a ... }
Comment #2 by tim.dlang — 2014-08-20T12:10:22Z
The bug is not caused by taking the address of a. If the writeln calls are removed there is still a segmentation fault.
Comment #3 by ibuclaw — 2014-08-20T13:00:46Z
(In reply to Tim from comment #2) > The bug is not caused by taking the address of a. If the writeln calls are > removed > there is still a segmentation fault. 'a' is dereferenced, so an address of it is still taken.
Comment #4 by tim.dlang — 2014-08-20T14:16:18Z
(In reply to Tim from comment #0) > When compiled with LDC 0.14 there is no segmentation fault, but the > addresses are still different and the value of a.x is wrong. That was wrong. It prints the correct value for a.x with LDC.
Comment #5 by tim.dlang — 2014-08-20T14:21:27Z
(In reply to Iain Buclaw from comment #1) > 2) When calling in/out contracts, the parameters of the body function should > be passed directly. > > void test(B this, size_t i, A a) > { > // body... > test.out(this, i, a); > } > > void test.out(void *this, size_t i, A a) > { > // Takes address of &a ... > } This would probably not work, if i is changed in the delegate: void test(size_t i, A a) out { writeln(i); } body { void delegate() dg = {i++;}; dg(); }
Comment #6 by k.hara.pg — 2015-07-01T07:44:35Z
*** This issue has been marked as a duplicate of issue 9383 ***