Skip to content

Potential undefined behavior when using reinterpret_cast #30300

@safocl

Description

@safocl

Steps to reproduce

Compile this project.
Standard C++ (Working Draft):

[defns.undefined]

3.65[defns.undefined]undefined behavior
behavior for which this document imposes no requirements
[Note 1: Undefined behavior may be expected when this document omits any explicit definition of behavior or when a program uses an incorrect construct or invalid data. Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message ([defns.diagnostic])), to terminating a translation or execution (with the issuance of a diagnostic message). Many incorrect program constructs do not engender undefined behavior; they are required to be diagnosed. Evaluation of a constant expression ([expr.const]) never exhibits behavior explicitly specified as undefined in [intro] through [cpp]. — end note]

[defns.undefined.runtime]

3.50[defns.undefined.runtime]runtime-undefined behavior
behavior that is undefined except when it occurs during constant evaluation
[Note 1: During constant evaluation,
it is implementation-defined whether runtime-undefined behavior results in the expression being deemed non-constant (as specified in [expr.const]) and
runtime-undefined behavior has no other effect.
— end note]

Expected behaviour

Correct program without UB.

Actual behaviour

Standard C++ (Working Draft):

[defns.undefined]

3.65[defns.undefined]undefined behavior
behavior for which this document imposes no requirements
[Note 1: Undefined behavior may be expected when this document omits any explicit definition of behavior or when a program uses an incorrect construct or invalid data. Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message ([defns.diagnostic])), to terminating a translation or execution (with the issuance of a diagnostic message). Many incorrect program constructs do not engender undefined behavior; they are required to be diagnosed. Evaluation of a constant expression ([expr.const]) never exhibits behavior explicitly specified as undefined in [intro] through [cpp]. — end note]

[defns.undefined.runtime]

3.50[defns.undefined.runtime]runtime-undefined behavior
behavior that is undefined except when it occurs during constant evaluation
[Note 1: During constant evaluation,
it is implementation-defined whether runtime-undefined behavior results in the expression being deemed non-constant (as specified in [expr.const]) and
runtime-undefined behavior has no other effect.
— end note]

https://github.com/telegramdesktop/tdesktop/blob/2f80db329bfb44639376396ea4cdc46c8d189bca/Telegram/SourceFiles/data/data_types.cpp#L51C22-L51C38

const auto part2 = *reinterpret_cast<const uint64*>(bytes2.data());

const auto part1 = *reinterpret_cast<const uint32*>(bytes1.data());

const auto part2 = *reinterpret_cast<const uint64*>(bytes2.data());

const auto part3 = *reinterpret_cast<const uint16*>(bytes3.data());

This lines use reinterpret_cast from string (?) to uint32, uint64, uint16. Here a program attempts to access the stored value of an object through a glvalue through which it is not type-accessible.

But:
https://eel.is/c++draft/basic.lval#11

11 An object of dynamic type Tobj is type-accessible through a glvalue of type Tref if Tref is similar ([conv.qual]) to:
(11.1) -- Tobj,
(11.2) -- a type that is the signed or unsigned type corresponding to Tobj, or
(11.3) -- a char, unsigned char, or std​::​byte type.

If a program attempts to access ([defns.access]) the stored value of an object through a glvalue through which it is not type-accessible, the behavior is undefined.38

https://eel.is/c++draft/basic.compound#5

5
#
Two objects a and b are pointer-interconvertible if
(5.1) -- they are the same object, or
(5.2) -- one is a union object and the other is a non-static data member of that object ([class.union]), or
(5.3) -- one is a standard-layout class object and the other is the first non-static data member of that object or any base class subobject of that object ([class.mem]), or
(5.4) -- there exists an object c such that a and c are pointer-interconvertible, and c and b are pointer-interconvertible.

If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a reinterpret_cast ([expr.reinterpret.cast]).

fix: #30301

Operating system

linux

Version of Telegram Desktop

dev

Installation source

Static binary from official website

Crash ID

No response

Logs

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions