-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SIGSEGV due to freeing of uninitialized local string, during exception handling #23645
Comments
same on 2.0, refc is safe |
But it disarms the destructor via if (NIM_UNLIKELY(*nimErr_)) goto LA1_;
_ZN6system7eqsink_E3varI6stringE6string((&(*output_p3)), str);
_ZN6system11eqwasMoved_E3varI6stringE((&str));
{
LA1_:;
}
{
if (str.p && !(str.p->cap & NIM_STRLIT_FLAG)) {
deallocShared(str.p); |
as far as I can read, |
ah, in fact, it doesn't even reach |
of course, it's a stack variable so it'll depend on conditions - that said, with |
oops wrong button |
Well
|
Ah, got it. |
The bug is in |
you mean, in to me, it also seems like a pretty serious issue that it reads |
Fixed by #23279 It checks the right side of result assignement to ensure it doesn't contain exceptions. After the change:
|
Correct, it is transformed to: var str
try:
str = toString(self)
`=sink`(output, str)
`=wasMoved`(str)
finally:
`=destroy`(str)
When it should be transformed into: var str
str = toString(self)
try:
`=sink`(output, str)
`=wasMoved`(str)
finally:
`=destroy`(str)
However, this is a much more invasive change with unclear side effects. |
so a separate issue needed for this one, or is it known? apart from any correctness issues (that I guess can be worked around by excessive zeroing), it'll make the code harder for the compiler to optimize, because of variable liveness extensions) |
It is a known issue and my current attempt at fixing it is to make ARC produce The downside is that the other backends need to replicate what the C backend does. So the days of "Nim produces C++'s and JavaScript's exception handling code" are numbered... |
why? can't the information be transferred to the backends? this would also break the usage of dwarf EH in nlvm |
We'll see, but in general implementing the exception handing in a central place in the compiler instead of N times has obvious benefits. |
...and downsides ;) reasoning about that global error flag is harder for llvm than reasoning about its own EH model (which btw is important for windows when integrating with SEH) so that will have significant impact on the quality of optimizations |
can have the cookie and eat it if it's implemented as a separate, optional transformation step |
How so? The C codegen uses the transformation step and the other backends do what exactly? :-) |
Well, the way an exception-raising function would ideally be modelled is as having two return paths (akin to an if/else) - this would allow correctly selecting happy and error code paths before any other side effects are evaluated - the way llvm models it is having a special Incidentally, this is also the correct way to model the above What I'm looking for, in order to be able to generate efficient and consistently correct code is more or less: var either = toString(self)
if either.isexception:
return either
var str = move(either.value)
str = toString(self)
try:
`=sink`(output, str)
`=wasMoved`(str)
finally:
`=destroy`(str) notably, in this model there is no global error flag - the fact that every exception-involved function reads a global is a pessimization for the optimizer because it can no longer assume purity which disables a lot of potential. |
The global error flag is not modelled currently either, it's nothing to worry about. The problem with But maybe this works:
Can be translated to:
|
… or seq[T] with index out of range (#23279) follow up #23013 fixes #22852 fixes #23435 fixes #23645 reports rangeDefect correctly ```nim /workspaces/Nim/test9.nim(1) test9 /workspaces/Nim/lib/system/indices.nim(116) [] /workspaces/Nim/lib/system/fatal.nim(53) sysFatal Error: unhandled exception: value out of range: -2 notin 0 .. 9223372036854775807 [RangeDefect] ``` (cherry picked from commit c615828)
Description
In the C code, this is quite visible:
_ZN6testit8toStringEN6testit3RlpE
returns an uninitializedresult
because_ZN6testit4itemEN6testit3RlpE
sets the error flag, then_ZN6testit10inspectAuxE3varIN6testit3RlpEE3int4bool3varI6stringE
assigns that uninitialized return value tostr
, then goes on todeallocateShared(str)
which obviously fails due to the garbage it receives.For the crash to happen, there has to be some garbage in the stack - an easy way to get garbage on the stack is to turn on stack tracing..
Nim Version
/home/arnetheduck/src/Nim/bin/nim -version
Nim Compiler Version 2.1.1 [Linux: amd64]
Compiled at 2024-05-24
Copyright (c) 2006-2024 by Andreas Rumpf
Current Output
Expected Output
No response
Possible Solution
No response
Additional Information
No response
The text was updated successfully, but these errors were encountered: