www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - debugger blues

reply cy <dlang verge.info.tm> writes:
I've been working for 3 days straight on this: the monumental 
task of taking these text files and turning them into HTML. Or 
should I say, FML, because FML. Why is this so hard?

My code is peppered with writelns and sanity checks, none of 
which show anything alarming until long after the document gets a 
self referential cycle in it, and apparantly this is happening by 
"creating a child and appending it to a node." Obviously that's a 
rare and obscure operation, that nobody ever would think of doing.

I can't do any introspection. GDB just goes belly up with DIE 
errors. Trying to get non-broken DWARF information by switching 
to GDC, GDC goes belly up with "internal error, please submit a 
bug report" and the reason for this error is creating a module 
named "cross.iter" and adding a sixth exported symbol to it.

In reflection, what would be really nice is:
* some way to trace function calls, to see the order of calls 
before the program died.
* a backtrace that displays when you hit ^C, instead of just 
silent death
* DWARF debugging symbols that don't scramble the only program on 
earth that actually uses them.
* some way to signal the program to dump the stack frames of its 
threads to a log
* better ways to report program status besides writeln("we got 
here somehow");
* catching null pointer errors earlier, instead of waiting until 
you 1) call the class function and 2) the function accesses a 
member.
* ways to ensure that nothing is being copied, if you 
accidentally write a wrapper that creates an object instead of 
referencing it, or moving it.
* better const support, so can minimize the amount of mutable 
data involved here
* it would be nice to be able to return an iterator whose 
elements are either const or not const, using inout, instead of 
having to write the function twice.
* it would also be nice to be able to return references, instead 
of copying structs every time, or writing wrappers around them 
(which also cannot be used with inout)
* heap allocated structs, stack allocated classes, it would be 
nice to have allocation strategy independent from layout strategy.
* less people writing complex allocating functions as their 
struct init property, and then leaving me wondering how that 
could possibly be invariant.
* a pony
Mar 24 2016
next sibling parent reply Iain Buclaw via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 25 Mar 2016 7:00 am, "cy via Digitalmars-d" <digitalmars-d puremagic.com>
wrote:
 I've been working for 3 days straight on this: the monumental task of
taking these text files and turning them into HTML. Or should I say, FML, because FML. Why is this so hard?
 My code is peppered with writelns and sanity checks, none of which show
anything alarming until long after the document gets a self referential cycle in it, and apparantly this is happening by "creating a child and appending it to a node." Obviously that's a rare and obscure operation, that nobody ever would think of doing.
 I can't do any introspection. GDB just goes belly up with DIE errors.
Trying to get non-broken DWARF information by switching to GDC, GDC goes belly up with "internal error, please submit a bug report" and the reason for this error is creating a module named "cross.iter" and adding a sixth exported symbol to it.

Have you considered raising a bug report as the compiler asks?

http://bugzilla.gdcproject.org/

It will never get noticed or fixed otherwise.

 In reflection, what would be really nice is:
 * some way to trace function calls, to see the order of calls before the
program died. It's called stack trace, uncaught exceptions print this information out.
 * a backtrace that displays when you hit ^C, instead of just silent death
This is something that you can do with signal handlers.
 * DWARF debugging symbols that don't scramble the only program on earth
that actually uses them. There's more than one dwarf reader, but yeah dmd has many small things lacking that mount up as you get more complex.
 * some way to signal the program to dump the stack frames of its threads
to a log Again, use OS signal handlers?
 * better ways to report program status besides writeln("we got here
somehow"); I'm afraid to say that only you can improve your own printf messages.
 * catching null pointer errors earlier, instead of waiting until you 1)
call the class function and 2) the function accesses a member. etc.linux.memoryerror - you can use that for catching SIGSEGV and dumping stacktrace. I'd suggest that you do the same for other signals such as SIGKILL and SIGTERM.
 * ways to ensure that nothing is being copied, if you accidentally write
a wrapper that creates an object instead of referencing it, or moving it. Use disable this(this); in your structs.
 * better const support, so can minimize the amount of mutable data
involved here In the library or in your program? Last time I checked phobos still has some way to go on that front. But granted that const is transitive, you should introduce it in a bottom up fashion. First find all leaf functions and make them const, then work your way up from there.
 * it would be nice to be able to return an iterator whose elements are
either const or not const, using inout, instead of having to write the function twice. This should be very possible, but I wouldn't know where you are going wrong.
 * it would also be nice to be able to return references, instead of
copying structs every time, or writing wrappers around them (which also cannot be used with inout) ref MyStruct() { return s; } I've never tried mixing ref and inout before, so won't attempt it here.
 * heap allocated structs, stack allocated classes, it would be nice to
have allocation strategy independent from layout strategy. Use pointer to structs and scope classes.
 * less people writing complex allocating functions as their struct init
property, and then leaving me wondering how that could possibly be invariant. I can not ask the hundreds of contributors to stop the fantastic work they are doing.
 * a pony
Of all points above, this is one that can actually be arranged. No joke!
Mar 25 2016
next sibling parent reply cy <dlang verge.info.tm> writes:
On Friday, 25 March 2016 at 08:14:15 UTC, Iain Buclaw wrote:
 Have you considered raising a bug report as the compiler asks?

 http://bugzilla.gdcproject.org/
Yes, and that would be yet another gigantic software monstrosity that I have to compile the latest version in, and yet another signup process for their bug tracker, and yet another thing to keep track of. I'll get around to it. The error was with just my distribution's release of GDC, so I'm pretty helpless to say that the bug even still exists. It was just a bug that made me wonder how people would even go and make a mistake like that.
 It's called stack trace, uncaught exceptions print this 
 information out.
No, the stack trace is the hierarchy of functions that are currently calling each other. I meant the functions that had been called previously, even the ones that have returned.
 This is something that you can do with signal handlers.
Ah, yes the wonder of being forced to use nogc, nothrow, and system. In the very accessible and undocumented spot of core.sys.c.signal! And heaven help you if you're trying to signal a process in Microsoft.
 There's more than one dwarf reader
yeah, I was exaggerating.
 Again, use OS signal handlers?
I tried! You can't even allocate a mutex! And then the thread you tried to signal dies anyway, because the signal gets sent to all of them! And then your process both exits and does not exit, and there's a mysterious copy of it in the background, despite you never forking, going at 100% CPU. A nice setup for signal handlers would be really cool. But what D has now is... minimal.
 I'm afraid to say that only you can improve your own printf 
 messages.
Or, write a print function that actually puts spaces between the arguments, or write a function that adds the file and line so you know where the statement was written and don't have to go hunting for it. Or std.experimental.logger or whatever. I'd use std.experimental.logger except it DOESN'T LET YOU PUT SPACES BETWEEN THE ARGUMENTS >:( (can you tell I programmed a lot in python?)
 etc.linux.memoryerror - you can use that for catching SIGSEGV 
 and dumping stacktrace.
Uh... huh. I didn't know about that. Actually I still don't know about that. It's not in phobos that I can see.
 I'd suggest that you do the same for other signals such as 
 SIGKILL
Handling SIGKILL, now that would be an accomplishment! (Friar Tuck... I am under attack! Pray save me!)
 Use  disable this(this); in your structs.
Well, obviously. But I meant a way to specify it in the function I'm writing. Like nocopy or move or something.
 In the library or in your program?  Last time I checked phobos 
 still has some way to go on that front.
In the library... ish. In the language. You can't pass an inout type as a template parameter to save it in a structure, so your structure can be agnostic of whether it's dealing with const or not, but you still have to write two identical member functions to set up and return that structure.
 But granted that const is transitive, you should introduce it 
 in a bottom up fashion.
The real problem is making code that works for both const and non-const, since like 99% of all code is exactly the same, just with "const" slapped on. What would be ideal is that you could label "frikkin everything" as const (except the stuff that actually does mutate) and the compiler would silently upgrade it to a mutable function if called with a mutable object, instead of erroring out and having to copypasta each function, to have a mutable version.
 * it would be nice to be able to return an iterator whose 
 elements are
either const or not const, using inout, instead of having to write the function twice. This should be very possible, but I wouldn't know where you are going wrong.
inout only applies to function parameters, or function local variables. It so happens that a template parameter to a struct is outside of that, so Iterator!(inout(Item)) just flat out won't work. Maybe you could define the structure inside the function, but then two functions couldn't share the same structure. And you can't define the template specialization inside the function, since inout can't be template parameters.
 ref MyStruct() { return s; }
...you can do that? Huh.
 * heap allocated structs, stack allocated classes, it would be 
 nice to
have allocation strategy independent from layout strategy. Use pointer to structs and scope classes.
I know there are ways to do it. It would be nice if those ways weren't so verbosely explicit, just a flag or a switch or something. There's been a lot of work on allocators recently, so I remain hopeful that struct/class usage can become allocation strategy agnostic.
 I can not ask the hundreds of contributors to stop the 
 fantastic work they are doing.
What if I say pretty please?
 * a pony
Of all points above, this is one that can actually be arranged. No joke!
I'll stick with ferrets, thanks.
Mar 25 2016
parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Fri, 25 Mar 2016 09:00:06 +0000
schrieb cy <dlang verge.info.tm>:

 No, the stack trace is the hierarchy of functions that are 
 currently calling each other. I meant the functions that had been 
 called previously, even the ones that have returned.
Is it just me? I've never heard of a programming environment, let alone a system programming language providing that information. While I understand, why the solidity of DWARF debug information is important, this seems to me like a pie in the sky idea similar to the pony. I guess the front-end would have to instrument code for that and the debugger is out of the picture, but you should detail that in a DIP. It does sound like an interesting idea to supplement existing instrumentation for profiling in DMD.
 I'm afraid to say that only you can improve your own printf 
 messages.
Or, write a print function that actually puts spaces between the arguments, or write a function that adds the file and line so you know where the statement was written and don't have to go hunting for it. Or std.experimental.logger or whatever. I'd use std.experimental.logger except it DOESN'T LET YOU PUT SPACES BETWEEN THE ARGUMENTS >:( (can you tell I programmed a lot in python?)
Yes, alright, but you can probably tell that std.logger was modeled after the existing formatting functionality of std.file (e.g. writefln) and that was modeled after printf, so to put spaces between the arguments you just add them to the formatting string. Just use format strings, case solved. Surely we can look at Python style spaces between arguments, but "DOESN'T LET YOU PUT SPACES BETWEEN THE ARGUMENTS" is just silly and factually wrong.
 Use  disable this(this); in your structs.
Well, obviously. But I meant a way to specify it in the function I'm writing. Like nocopy or move or something.
If you ask for a *guarantee* of no copy on struct return, then you are right. In praxis, the memory for the return value is allocated on the caller's stack and the callee writes directly into it. No copy or copy constructor call is performed. In addition most (all?) ABIs allow structs of 1 or 2 machine words to be returned in registers (i.e. EAX:EDX on x86). Proof: BigStruct returnsBigStruct() { BigStruct ret = returnsBigStructToo(); ret.data[0] = 42; return ret; } BigStruct returnsBigStructToo() { import std.range; BigStruct ret = BigStruct( iota(20).array[0 .. 20] ); return ret; } struct BigStruct { int[20] data; this(this) { import std.stdio; writeln("I'm typically not called at all."); } } void main() { import std.stdio; immutable bigStruct = returnsBigStruct(); writeln( bigStruct.data ); } -- Marco
Mar 27 2016
parent reply cy <dlang verge.info.tm> writes:
On Sunday, 27 March 2016 at 15:40:47 UTC, Marco Leise wrote:
 Is it just me? I've never heard of a programming environment, 
 let alone a system programming language providing that 
 information.
Well, not by default certainly. It is a bit pie-in-the-sky, but only because it slows everything down. It's got the same cost as profiling. Many languages, even C in some cases, have support for this. With gcc for instance, if you use -finstrument-functions then it calls __cyg_profile_func_enter before every function call and __cyg_profile_func_exit afterwards. That can be used to accumulate _totals_ of how many times a function was called (profiling) but it can also just dump the called functions in order. I certainly would be shocked as heck if a debugger could take non-instrumented code and add all that tracing and/or profiling stuff, but stranger things have happened in the murky realm of code debugging.
 "DOESN'T LET YOU PUT SPACES BETWEEN THE ARGUMENTS" is just 
 silly and factually wrong.
No, it's factually true. You can provide arguments that have spaces in them, but there is no way to put spaces between the arguments to your logging function. I would expect that the logger would be called with the arguments provided, but instead the logging code uses a private function to stringify and concatenate all the arguments, and provides it to the logger as one single opaque string. This is certainly something that could be improved. What I did was write my own logging framework, that joins arguments with spaces in between, and provides that as a single argument to std.experimental.logging. But that requires me to duplicate all the template boilerplate (func = __func__, file = __file__, line = __line__ etc) so all the code in std.experimental.logging to do that can't be used, reducing std.experimental.logging to basically nothing other than writeln.
 If you ask for a *guarantee* of no copy on struct return, then 
 you are right.
I wish I was right. There are still some gotchas there, that I don't fully understand. Things like:
 	BigStruct ret = returnsBigStructToo();
look the same as things like:
 	BigStruct ret = returnedbigstruct;
but the latter is actually a copy. D making paretheses optional for properties makes it even more confusing.
 A a = b.myA // copy or emplacement?
But even taking that into account, I've had mysterious situations where the pointer to a returned structure changed, from within the function to without, without any apparant copying going on. When member functions raise assertions if that pointer was different... it's just not workable. I don't actually know why copying is occurring in many cases, or pseudo-copying or...whatever, so I can't really tell you what I'm talking about exactly. I should ask that as a separate question...
Mar 28 2016
next sibling parent Iain Buclaw via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 28 March 2016 at 21:29, cy via Digitalmars-d <digitalmars-d puremagic.com
 wrote:
 On Sunday, 27 March 2016 at 15:40:47 UTC, Marco Leise wrote:

 Is it just me? I've never heard of a programming environment, let alone a
 system programming language providing that information.
Well, not by default certainly. It is a bit pie-in-the-sky, but only because it slows everything down. It's got the same cost as profiling. Many languages, even C in some cases, have support for this. With gcc for instance, if you use -finstrument-functions then it calls __cyg_profile_func_enter before every function call and __cyg_profile_func_exit afterwards. That can be used to accumulate _totals_ of how many times a function was called (profiling) but it can also just dump the called functions in order. I certainly would be shocked as heck if a debugger could take non-instrumented code and add all that tracing and/or profiling stuff, but stranger things have happened in the murky realm of code debugging.
Most language agnostic features of gcc are possible in gdc too. Coverage and instrumentation come for free.
Mar 29 2016
prev sibling parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Mon, 28 Mar 2016 19:29:38 +0000
schrieb cy <dlang verge.info.tm>:

 On Sunday, 27 March 2016 at 15:40:47 UTC, Marco Leise wrote:
 Is it just me? I've never heard of a programming environment,=20
 let alone a system programming language providing that=20
 information.
=20 Well, not by default certainly. It is a bit pie-in-the-sky [=E2=80=A6].
At first you framed it like it was something to be expected in a PL. As a pie-in-the-sky for DMD on the other hand I agree with you. Maybe it is enough that GDC provides this feature. Or maybe you could turn the idea into a DIP (with GCC as the reference implementation) so eventually DMD and LDC can provide this as well.
 "DOESN'T LET YOU PUT SPACES BETWEEN THE ARGUMENTS" is just=20
 silly and factually wrong.
=20 No, it's factually true. You can provide arguments that have=20 spaces in them, but there is no way to put spaces between the=20 arguments to your logging function. I would expect that the=20 logger would be called with the arguments provided, but instead=20 the logging code uses a private function to stringify and=20 concatenate all the arguments, and provides it to the logger as=20 one single opaque string. This is certainly something that could=20 be improved.
It is straightforward to put spaces between arguments: warningf("%s %s %s", "puts", "spaces", "inbetween"); If you refer to the common headers that go before each message, those are indeed not configurable for existing Logger implementations. Swapping them out is not complicated though: import std.experimental.logger; import std.stdio; stdThreadLocalLog =3D new class FileLogger { this() { super(stderr, LogLevel.all); } override protected void beginLogMsg( string file, int line, string funcName, string prettyFuncName, string moduleName, LogLevel logLevel, Tid threadId, SysTime timestamp, Logger logger) { import std.string : lastIndexOf; auto idx1 =3D file.lastIndexOf('/'); auto idx2 =3D funcName.lastIndexOf('.'); formattedWrite(this.file.lockingTextWriter(), "%s %s %s %u ", timestamp, file[idx1 + 1 .. $], funcName[idx2 + 1 .. $], line); } }; warningf("%s", "<- the header now has spaces instead of ':' in it"); You could also make 'beginLogMsg' call a user provided delegate for formatting to freely change the looks at runtime. =20
 What I did was write my own logging framework, that joins=20
 arguments with spaces in between, and provides that as a single=20
 argument to std.experimental.logging. But that requires me to=20
 duplicate all the template boilerplate (func =3D __func__, file =3D=20
 __file__, line =3D __line__ etc) so all the code in=20
 std.experimental.logging to do that can't be used, reducing=20
 std.experimental.logging to basically nothing other than writeln.
WTF? :p If you wonder why some feature is not provided in the default implementation, the answer is likely that Logger was meant to be as light-weight as possible with the option to completely carve it out and re-implement it. For example, if the header could be formatted with a format string, "%s" would have been the only option for the time stamp.
 If you ask for a *guarantee* of no copy on struct return, then=20
 you are right.
=20 I wish I was right. There are still some gotchas there, that I=20 don't fully understand. Things like:
 	BigStruct ret =3D returnsBigStructToo();
=20 look the same as things like:
 	BigStruct ret =3D returnedbigstruct;
=20 but the latter is actually a copy. D making paretheses optional=20 for properties makes it even more confusing. =20
 A a =3D b.myA // copy or emplacement?
I believe the idea is that to copy or not to copy a struct is just an optimization step and in cases where this strictly must not happen disable this(this); catches all code that would need to perform a copy to work. Maybe you can return your structs by reference or pointer? It is hard to tell without seeing the code, how it could be refactored with Dlang's design choices in mind.
 But even taking that into account, I've had mysterious situations=20
 where the pointer to a returned structure changed, from within=20
 the function to without, without any apparant copying going on.
Be assured that if that happens without this(this) being called, it is worth a bug report.
Mar 29 2016
parent reply cy <dlang verge.info.tm> writes:
On Tuesday, 29 March 2016 at 23:49:21 UTC, Marco Leise wrote:
 It is straightforward to put spaces between arguments:
 	warningf("%s %s %s", "puts", "spaces", "inbetween");
warningf("%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s","I","really","don't","know","how","straightforward","that","is","if","you","have","to","manually","count","every","argument","you","pass.");
 If you refer to the common headers that go before each message,
No, I'm referring to concatenating all the arguments before passing the message to the logger.
 WTF? :p
It's not that crazy an idea. If something takes multiple strings and doesn't format them the way you like it, then you write a wrapper around it that takes multiple strings, formats them, then passes the one string result downward. Just doesn't work so well with logging, since __file__ and the like need to be passed along, so they end up adding up a lot of boilerplate. Anyway, I figured out a way to do it. I thought formattedWrite was just concatenating the arguments with an Appender!string, but I was wrong. It actually is taking an output range that calls logMsgPart for each of the arguments. So... I have nothing to complain about really. What I thought wasn't there, I actually just missed seeing. import std.experimental.logger; import std.stdio; class MyLogger: Logger { bool started; this() { super(LogLevel.warning); started = false; } override void writeLogMsg(ref LogEntry payload) { writeln("uhhh"); } override void logMsgPart(const(char)[] msg) { if(msg.length == 0) return; if(started) write(" "); else started = true; write(msg); } override void finishLogMsg() { started = false; writeln(""); } } void main() { (new MyLogger()).warning("is","this","a","good","idea?"); (new MyLogger()).warning("python","ruined","me"); }
Mar 30 2016
next sibling parent ag0aep6g <anonymous example.com> writes:
On 31.03.2016 04:52, cy wrote:
 warningf("%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s
 %s","I","really","don't","know","how","straightforward","that","is","if","you","have","to","manually","count","every","argument","you","pass.");
---- import std.range: only; warningf("%-(%s %)", only("foo", "bar", "baz")); ---- I was also going to suggest joiner: ---- import std.algorithm: joiner; warning(only("foo", "bar", "baz").joiner(" ")); ---- But warning goes crazy on that. std.experimental.logger seems to have a problem with dchar.
Apr 01 2016
prev sibling parent reply Alex Parrill <initrd.gz gmail.com> writes:
Comparing a logging framework with a basic print function is not 
a fair comparison. I'd like to point out that Python's logging 
module[1] also takes format strings.

So this really is just an argument of D's writeln vs Python's 
print. In which case, this seems like a small thing to get upset 
over. Yes, implicit spacing is convenient, but in some cases it 
isn't. It's a fairly arbitrary choice. I'd argue that D's writeln 
follows Python's philosophy of "Explicit is better than implicit" 
better than Python does.

But it's not overly hard to implement your own print function:

void print(Args...)(Args args) {
     foreach(i, arg; args) {
         if(i != 0) write(" ");
         write(arg);
     }
     writeln();
}

[1] https://docs.python.org/3/library/logging.html
Apr 01 2016
parent cy <dlang verge.info.tm> writes:
On Saturday, 2 April 2016 at 01:13:54 UTC, Alex Parrill wrote:

 But it's not overly hard to implement your own print function:
The biggest problem is that I wanted the file and line information in my print function, which just added a lot of boilerplate that the logger already did. prefix.put(moduleName); prefix.put(':'); prefix.put(to!string(line)); prefix.put(' '); ...and such. But yeah it's not too hard to implement. https://github.com/cyisfor/story-generator/blob/master/source/print.d
Apr 29 2016
prev sibling parent reply Craig Dillabaugh <craig.dillabaugh gmail.com> writes:
On Friday, 25 March 2016 at 08:14:15 UTC, Iain Buclaw wrote:
clip
 * a pony
Of all points above, this is one that can actually be arranged. No joke!
I've got a Border Collie I could throw in to the mix too if that would be helpful.
Mar 25 2016
parent Marco Leise <Marco.Leise gmx.de> writes:
Am Fri, 25 Mar 2016 14:15:57 +0000
schrieb Craig Dillabaugh <craig.dillabaugh gmail.com>:

 On Friday, 25 March 2016 at 08:14:15 UTC, Iain Buclaw wrote:
 clip
 * a pony
Of all points above, this is one that can actually be arranged. No joke!
I've got a Border Collie I could throw in to the mix too if that would be helpful.
My sister always wanted a pony. When we got a dog, she made him run in circles, jump hurdles and pull the sled. O.o :p -- Marco
Mar 27 2016
prev sibling parent reply Vladimir Panteleev <thecybershadow.lists gmail.com> writes:
On Friday, 25 March 2016 at 05:59:01 UTC, cy wrote:
 * a backtrace that displays when you hit ^C, instead of just 
 silent death
Perhaps have a look at what etc.linux.memoryerror does.
 * DWARF debugging symbols that don't scramble the only program 
 on earth that actually uses them.
What compiler flags did you use? Having an up-to-date GDB might help.
 * better ways to report program status besides writeln("we got 
 here somehow");
This sort of works: try throw new Exception(null); catch (Exception e) context = e.toString().splitLines()[1..$]; A `Thread.getStackTrace` would be nice.
 * catching null pointer errors earlier, instead of waiting 
 until you 1) call the class function and 2) the function 
 accesses a member.
Doesn't this already happen if you compile without -release? Calling a class method will invoke the class invariant hidden virtual method, which will segfault when looking up the method in the vtable.
 * ways to ensure that nothing is being copied, if you 
 accidentally write a wrapper that creates an object instead of 
 referencing it, or moving it.
Structs have this: disable this(this);
 * it would also be nice to be able to return references, 
 instead of copying structs every time, or writing wrappers 
 around them (which also cannot be used with inout)
You can return by ref...?
 * heap allocated structs, stack allocated classes, it would be 
 nice to have allocation strategy independent from layout 
 strategy.
Heap allocated struct: auto s = new S; Stack allocated class: auto c = scoped!C;
Mar 25 2016
parent reply cy <dlang verge.info.tm> writes:
On Friday, 25 March 2016 at 08:21:29 UTC, Vladimir Panteleev 
wrote:
 Perhaps have a look at what etc.linux.memoryerror does.
Oh, there it is! In druntime! Oh look, inline assembler! No architectures outside of X86/X86_64. Manually editing the bytes of your stack context! I think I'll just go cry in the shower now.
 * DWARF debugging symbols that don't scramble the only program 
 on earth that actually uses them.
What compiler flags did you use?
make -f posix install ... I learned about BUILD=debug after that, but haven't tried it yet. Takes a _long_ time to compile phobos.
 Having an up-to-date GDB might help.
And an up-to-date GCC, and my own custom version of glibc while I'm at it, and both GDC and DMD, and Phobos, and DRuntime.
 This sort of works:

 	try
 		throw new Exception(null);
 	catch (Exception e)
 		context = e.toString().splitLines()[1..$];
Huh, neat... I'll have to remember that.
 * catching null pointer errors earlier, instead of waiting 
 until you 1) call the class function and 2) the function 
 accesses a member.
Doesn't this already happen if you compile without -release?
Apparantly not, because I've never compiled without -debug, and I infrequently get "null this" errors after having called the function...
 Calling a class method will invoke the class invariant hidden 
 virtual method,
...in a struct, not a class.
 Structs have this:  disable this(this);
I use that very liberally.
Mar 25 2016
next sibling parent reply Vladimir Panteleev <thecybershadow.lists gmail.com> writes:
On Friday, 25 March 2016 at 09:12:56 UTC, cy wrote:
 What compiler flags did you use?
make -f posix install
I meant, which flags you used to build your program.
 * catching null pointer errors earlier, instead of waiting 
 until you 1) call the class function and 2) the function 
 accesses a member.
Doesn't this already happen if you compile without -release?
Apparantly not, because I've never compiled without -debug, and I infrequently get "null this" errors after having called the function...
"null this" is the error I'm talking about. It is coming from the object invariant. It's not caused by a segmentation fault caused by accessing a member.
Mar 25 2016
parent cy <dlang verge.info.tm> writes:
You know what I really want? I want to disable package:/private: 
access entirely! Since GDB is useless, I can't write assertions 
to compare the structure of two objects, without going into that 
3000 lines of code and writing a function to compare them in that 
particular fashion. Not being allowed to turn those accesses into 
warnings, or temporarily disabling them, seems a bit spiteful. It 
takes a lot of hubris for a programmer to decide that nobody else 
will ever want to do something with their code, that they didn't 
themselves anticipate.

On Friday, 25 March 2016 at 09:30:37 UTC, Vladimir Panteleev 
wrote:

 "null this" is the error I'm talking about. It is coming from 
 the object invariant. It's not caused by a segmentation fault 
 caused by accessing a member.
It still happily allows me to pass around that null pointer as if it were a real object, and call member functions on that null pointer. It's only when it tries to access a member variable that it raises the error. I'm of the opinion that null should be categorically different from a pointer to a class or struct. Because when I get "null this" I have no general way to tell where that null pointer came from, and just have to eyeball the code and trace back to guess where it might have returned an unexpected null. Segfaulting on a null this would be totally terrible, but erroring out on "null this" is still fail-slow.
Mar 26 2016
prev sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 25 March 2016 at 09:12:56 UTC, cy wrote:
 This sort of works:

 	try
 		throw new Exception(null);
 	catch (Exception e)
 		context = e.toString().splitLines()[1..$];
Huh, neat... I'll have to remember that.
Better yet, the trick from the end of my book still works, with mild adjustment: // put this function in your helper module string getStackTrace() { import core.runtime; version(Posix) { // druntime cuts out the first few functions on the trace because they are internal // so we'll make some dummy functions here so our actual info doesn't get cut Throwable.TraceInfo f2() { return defaultTraceHandler(); } Throwable.TraceInfo f1() { return f2(); } auto trace = f1(); } else { auto trace = defaultTraceHandler(); } return trace.toString(); } // and call it like this: void foo() { import std.stdio; writeln(getStackTrace()); } void main() { foo(); } It will print the trace without an exception, showing this: stacktrace.d:19 void stacktrace.foo() [0x8076aaf] stacktrace.d:23 _Dmain [0x8076ac7] ??:? _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZ9__lambda1MFZv [0x8077c32] ??:? void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate()) [0x8077b95] ??:? void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll() [0x8077bee] ??:? void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate()) [0x8077b95] ??:? _d_run_main [0x8077b1e] ??:? main [0x8076eab] ??:? __libc_start_main [0xf74fe29f] Compile with -g to get the file and line number from your code. You might also tweak the function to skip the last few lines too since they are just generic functions inside druntime itself. string getStackTrace() { import core.runtime; version(Posix) { // druntime cuts out the first few functions on the trace because they are internal // so we'll make some dummy functions here so our actual info doesn't get cut Throwable.TraceInfo f2() { return defaultTraceHandler(); } Throwable.TraceInfo f1() { return f2(); } auto trace = f1(); } else { auto trace = defaultTraceHandler(); } // cut off the last 7 lines because they are internal // functions anyway import std.string; return join(splitLines(trace.toString())[0 .. $-7], "\n"); } Which now leaves the output as a fairly simple: $ ./stacktrace stacktrace.d:20 void stacktrace.foo() [0x80780a7] stacktrace.d:24 _Dmain [0x80780bf] which might be pretty useful.
Mar 25 2016