[Issue 18016] using uninitialized value is considered @safe but has undefined behavior

d-bugmail at puremagic.com d-bugmail at puremagic.com
Wed Jun 5 22:45:38 UTC 2019


https://issues.dlang.org/show_bug.cgi?id=18016

--- Comment #8 from Manu <turkeyman at gmail.com> ---
(In reply to Steven Schveighoffer from comment #7)
> It's garbage data, but it's not garbage pointers. As long as the memory is
> not used to reference anything, it's not going to cause a memory corruption
> to use it.

You can't know what the memory is going to be used for. You would need
astonishingly competent flow-analysis to make judgements of that kind.
It could be given as an argument to any operation that references something,
perhaps as an offset, or any conceivable thing could be done with that data,
and it's 100% guaranteed to be a rubbish operation.

It's a varifiably rubbish value, how could that inject valid program flow into
any usage context?

> Why would you want to use this? Because it's more efficient to not
> initialize stack data before overwriting it with the real value.

Right, but it requires very special-case handling, and it's error-prone; for
instance, you might think you can simply:
  T x = void;
  x = T();

For some subset of possible T's that might be fine, but then some T arrives
with elaborate assignment semantics and it's a spectacular crash. It would be
easy for that to slip through the cracks, or not demonstrate issue on the lib
author's projects, but then a customer exposes the issue.
@trusted should be a locator for dangerous code, exactly like such an
assignment above. That code above is absolutely not @safe, it's making
assumptions way outside the language semantics, anything could happen if you're
not careful.

D has many semantics when operating on objects that make the basic assumption
that objects are *valid*. `init` exists for this reason. Every semantic that
assumes a valid object is violated by `= void`, which makes every such
operation `risky` at best.

> Can you explain a way that f() is unsafe in the example above?

f() is potentially @safe, assuming that `x` is a type without elaborate
assignment (it is `int` above), but it depends on the compiler having powerful
flow analysis to determine those facts.
So it *could* be @safe, but I don't think DMD has the technology required to
prove that at this time?

> That is, it
> results in corrupted memory? Or alternatively, show how you can write code
> that is exploitable or could cause memory corruption?

Exposing uninitialised memory is a data leak at best. Many forms of exploit
take advantage of leaking private or inaccessible data, but typically it can be
used to source or craft values that lead to unexpected or otherwise invalid
program flow or improper array offsets.

> Would you consider this function @safe?
> 
> int[] allocate(int size)
> {
>    auto result = cast(int *)malloc(size * int.sizeof);
>    return result[0 .. size];
> }
> 
> It doesn't corrupt any memory, the data is not left dangling, as it's not
> freed, but it's also not initialized. Is that a big problem?

malloc's not @safe (it's not even D), neither is dynamically slicing a pointer,
and the memory is uninitialised. This function is certainly not @safe.
@system functions are perfectly fine. There's nothing wrong with @system code,
it's just up to the caller to confirm a valid interaction.

--


More information about the Digitalmars-d-bugs mailing list