14 hours ago
On Friday, 4 July 2025 at 06:29:26 UTC, Walter Bright wrote:
> not acceptable.

```d
import std;
unittest{
	try{assert(0);}
	catch(Error){
		"hi".writeln;
	}
}
```
13 hours ago
On Friday, July 4, 2025 1:24:33 AM Mountain Daylight Time Walter Bright via Digitalmars-d wrote:
> This whole discussion seems pointless anyway. If you want to unwind the
> exception stack every time, use enforce(), not assert(). That's what it's for.

As you know, Exceptions are for reporting problems with user input and/or the current environment, and they're generally considered recoverable, because programs should be written to be able to handle such errors conditions, meaning that they're part of the program's logic.

Errors are for reporting problems with the program itself, and they're not recoverable, because they prove that program's logic is faulty or that a condition so severe that the program must be terminated has occurred (e.g. running out of memory)

However, neither of those conditions necessarily says anything about not wanting to unwind the stack properly. Yes, if you're going to continue to run the program after the Exception is thrown, then it's that much more critical that the stack be unwound properly, but even with Errors, it can be valuable to have the stack unwind properly, because that very unwinding can be used to get information about the program as it shuts down.

For instance, Timon does this already with programs that actual users use. It's just that he has to work around the fact that not all of the clean up code gets run (some of it does, and some of it doesn't), and the fact that some of the clean up code is skipped means that he's risking memory safety issues in the process that wouldn't have been there if the stack had unwound properly. It also potentially means that he'll miss some of the information that he's trying to log so that the user can give him that information. And that information is critical to his ability to fix bugs, because he's not the one running the program, and he can't get stuff like core dumps from users (not that you get a proper core dump from an Error anyway).

Skipping some of the stack unwinding code when an Error is thrown makes it that much riskier for the code that is run while the program is being shutdown to run. And yes, maybe in some circumstances, that unwinding could result in files being written from bad program data, but as a general rule, Errors are thrown because the program was about to do something terrible, and it was caught, not because something terrible has already happened. And by not unwinding the stack properly, we increase the risk of things going wrong as the stack is unwound.

At minimum, it would be desirable if we could configure the runtime (or use a compiler flag if that's the more appropriate solution) so that programmers can choose whether they want the stack unwinding to work properly with Errors or not. That way, it's possible for programmers to get improved debugging information as the stack is unwound without the stack unwinding causing memory safety issues. And really, what on earth is even the point of unwinding the stack at all if we're not going to unwind it properly?

- Jonathan M Davis




13 hours ago
On Friday, 4 July 2025 at 07:24:33 UTC, Walter Bright wrote:
> This whole discussion seems pointless anyway. If you want to unwind the exception stack every time, use enforce(), not assert(). That's what it's for.

That's not up to me as any two-bit library could use assert() instead of enforce(). What you're really saying is "Never use assert() anywhere ever, always use enforce()", which means we can safely deprecate and remove assert() from the language.

In User Interface Design, a key principle is always make the default response the sane response. If the sane response is enforce(), then enforce() needs to be the default. Or you make assert() behave like enforce(), because the sane response is enforce().
13 hours ago
On 04/07/2025 7:24 PM, Walter Bright wrote:
> On 7/3/2025 1:25 AM, Richard (Rikki) Andrew Cattermole wrote:
>>>  From what I can tell this kind of attack is unlikely in D even without the 
>> codegen protection. So once again, the Error class hierarchy offers no protection from this kind of attack.
> 
> The paper says that exception unwinding of the stack is still vulnerable to malware attack.
> 
> 
>> Need more evidence to suggest that Error shouldn't offer cleanup. Right now I have none.
> 
> Because:
> 
> 1. there is no purpose to the cleanup as the process is to be terminated

A task has to be terminated, that doesn't have to be the process.

Logging still requires the stack to be in a good state that isn't being clobbered over. That can and will produce data corruption.

You need to clean things up like sockets appropriately. They can have side effects on computers on the other side of the planet that isn't just data is corrupt, it could be worse. They are not always accessible in every part of the program. GC may need to run ext.

> 2. code that is not executed is not vulnerable to attack

Sounds good, no more catching of Throwable at any point in programs.

Shall we tell people that unwinding exceptions are hereby recommended against in D code, and that we will be replacing them with a different solution?

Unless we are prepared to rip out unwinding, D program will be vulnerable to these kinds of attacks (even though the probability is low).

> 3. the more code that is executed after the program entered unknown and unanticipated territory, the more likely it will corrupt something that matters
> 
> Do you really want cleanup code to be updating your data files after the program has corrupted its data structures?

Hang on:

- Executing the same control path after a bad event happens.

- Executing a different control path to prevent a bad event.

Are two very different things.

I do not want the first that has long since shown itself to be a lost cause, but the second works fine in other language and people are relying on this behavior. So what is so special about D that we should inhibit entire problem domains from using D appropriately?

> ---
> 
> This whole discussion seems pointless anyway. If you want to unwind the exception stack every time, use enforce(), not assert(). That's what it's for.

The current situation of not having a solution for when people need Error to be recoverable is creating problems, rather than solving them.

You can't "swap out" Error for Exception due to nothrow and druntime not having the ability to do it.

Error has to change, the codegen of nothrow has to change, there is nothing else for it.

Does it have to be the default? Not initially, it can prove itself before any default changes. We'll talk about that at the monthly meeting.
13 hours ago
On Thursday, 3 July 2025 at 23:38:03 UTC, Adam Wilson wrote:
> On Thursday, 3 July 2025 at 10:19:18 UTC, Paolo Invernizzi wrote:
>> [...]
>
> I can't hook debuggers up to code running on a remote server that somebody else owns in a DC hundreds of miles away. Therefore the only debugging data available is stack traces. If the language prevents the emission of stack traces then I get ... absolutely nothing.
>
> [...]

And what is preventing you to ask your colleagues for nix core dumps or win mini dumps?

/P

13 hours ago
On Friday, 4 July 2025 at 08:19:23 UTC, Paolo Invernizzi wrote:
> On Thursday, 3 July 2025 at 23:38:03 UTC, Adam Wilson wrote:
>> On Thursday, 3 July 2025 at 10:19:18 UTC, Paolo Invernizzi wrote:
>>> [...]
>>
>> I can't hook debuggers up to code running on a remote server that somebody else owns in a DC hundreds of miles away. Therefore the only debugging data available is stack traces. If the language prevents the emission of stack traces then I get ... absolutely nothing.
>>
>> [...]
>
> And what is preventing you to ask your colleagues for nix core dumps or win mini dumps?
>
> /P

Not allowed as they contain unsecured/decrypted GDPR or similarly embargoed data. These dumps cannot be transmitted outside the production environment. That rule has been in effect since GDPR was passed. GDPR caused quite a bit of engineering heart-burn at Microsoft for years.
12 hours ago
On Friday, 4 July 2025 at 08:31:03 UTC, Adam Wilson wrote:
> On Friday, 4 July 2025 at 08:19:23 UTC, Paolo Invernizzi wrote:
>> On Thursday, 3 July 2025 at 23:38:03 UTC, Adam Wilson wrote:
>>> On Thursday, 3 July 2025 at 10:19:18 UTC, Paolo Invernizzi wrote:
>>>> [...]
>>>
>>> I can't hook debuggers up to code running on a remote server that somebody else owns in a DC hundreds of miles away. Therefore the only debugging data available is stack traces. If the language prevents the emission of stack traces then I get ... absolutely nothing.
>>>
>>> [...]
>>
>> And what is preventing you to ask your colleagues for nix core dumps or win mini dumps?
>>
>> /P
>
> Not allowed as they contain unsecured/decrypted GDPR or similarly embargoed data. These dumps cannot be transmitted outside the production environment. That rule has been in effect since GDPR was passed. GDPR caused quite a bit of engineering heart-burn at Microsoft for years.

I don't want to be too much pedant, so feel free to just ignore me ..

We operate (also) in EU, and I interact constantly with our external Data Protection Officer.

GDPR is a matter of just being clear about what you do with personal data, and have the user agreement to operate on that data for some clear stated (and justified) purpose.

Debugging software is for sure a pretty common target purpose, also because imply more secure production services. That can be for sure added in the privacy policy the user anyway needs to agree with.

But I can feel your pain in having to deal with, well, pretty dumb way of setting internal rules.

/P
11 hours ago

On Friday, 4 July 2025 at 07:51:00 UTC, Jonathan M Davis wrote:

>

For instance, Timon does this already with programs that actual users use. It's just that he has to work around the fact that not all of the clean up code gets run (some of it does, and some of it doesn't), and the fact that some of the clean up code is skipped means that he's risking memory safety issues in the process that wouldn't have been there if the stack had unwound properly. It also potentially means that he'll miss some of the information that he's trying to log so that the user can give him that information. And that information is critical to his ability to fix bugs

So the argument is that even when you don't recover from Error, it's still desirable to run all (implicit) finally blocks when unwinding the stack because that results in a better error log.

Maybe only Timon can answer this, but what kind of clean up are you doing that makes this important? An example of an error log with and without complete stack unwinding would be illuminating.

Looking at my own destructors / scope(exit) blocks, they mostly just contain free, fclose, CloseHandle, etc. In that case I agree with Walter: when my program trips an assert, I don't need calls to free since that could only lead to more memory corruption, and resource leaks are irrelevant when the program is going to abort shortly.

11 hours ago
On 04/07/2025 9:54 PM, Dennis wrote:
> On Friday, 4 July 2025 at 07:51:00 UTC, Jonathan M Davis wrote:
>> For instance, Timon does this already with programs that actual users use. It's just that he has to work around the fact that not all of the clean up code gets run (some of it does, and some of it doesn't), and the fact that some of the clean up code is skipped means that he's risking memory safety issues in the process that wouldn't have been there if the stack had unwound properly. It also potentially means that he'll miss some of the information that he's trying to log so that the user can give him that information. And that information is critical to his ability to fix bugs
> 
> So the argument is that even when you don't recover from Error, it's still desirable to run all (implicit) `finally` blocks when unwinding the stack because that results in a better error log.
> 
> Maybe only Timon can answer this, but what kind of clean up are you doing that makes this important? An example of an error log with and without complete stack unwinding would be illuminating.
> 
> Looking at my own destructors / scope(exit) blocks, they mostly just contain `free`, `fclose`, `CloseHandle`, etc. In that case I agree with Walter: when my program trips an assert, I don't need calls to `free` since that could only lead to more memory corruption, and resource leaks are irrelevant when the program is going to abort shortly.

scope(exit) is ran when Error passes through it.

This is one of the complicating factors at play.

11 hours ago

On Friday, 4 July 2025 at 09:56:53 UTC, Richard (Rikki) Andrew Cattermole wrote:

>

scope(exit) is ran when Error passes through it.

This is one of the complicating factors at play.

scope guards and destructor calls are internally lowered to finally blocks, they're all treated the same. But let's say they aren't, that still doesn't answer the question: what error logging code are you writing that relies on clean up code being run? What does the output look like with and without?