Issue 19769 - CTFE format(): str[index] is used before initialized
Summary: CTFE format(): str[index] is used before initialized
Status: NEW
Alias: None
Product: D
Classification: Unclassified
Component: phobos (show other issues)
Version: D2
Hardware: All All
: P3 normal
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-03-28 23:58 UTC by elpenguino+D
Modified: 2024-12-01 16:34 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description elpenguino+D 2019-03-28 23:58:40 UTC
trying to format the result of a const asCapitalized(string) at compile-time causes a used-before-initialized error in std.utf.decode(), as demonstrated below:

```
import std.uni;
import std.format;
static immutable x = format("%s", cast(const)"test".asCapitalized);
```

results in this error:

```
/dlang/dmd/linux/bin64/../../src/phobos/std/utf.d(1132): Error: str[index] is used before initialized
/dlang/dmd/linux/bin64/../../src/phobos/std/uni.d(9143):        originally uninitialized here
/dlang/dmd/linux/bin64/../../src/phobos/std/format.d(3457):        called from here: decode(str, i)
/dlang/dmd/linux/bin64/../../src/phobos/std/format.d(4233):        called from here: formatElement(w, e, f)
/dlang/dmd/linux/bin64/../../src/phobos/std/format.d(1854):        called from here: formatValueImpl(w, val, f)
/dlang/dmd/linux/bin64/../../src/phobos/std/format.d(3552):        called from here: formatValue(w, val, f)
/dlang/dmd/linux/bin64/../../src/phobos/std/format.d(4233):        called from here: formatElement(w, e, f)
/dlang/dmd/linux/bin64/../../src/phobos/std/format.d(1854):        called from here: formatValueImpl(w, val, f)
/dlang/dmd/linux/bin64/../../src/phobos/std/format.d(575):        called from here: formatValue(w, _param_2, spec)
/dlang/dmd/linux/bin64/../../src/phobos/std/format.d(6403):        called from here: formattedWrite(w, fmt, _param_1)
onlineapp.d(3):        called from here: format("%s", asCapitalized("test"))
```
Comment 1 berni44 2019-12-05 14:58:35 UTC
The problem here is, that asCapitalized returns a struct (ToCapitalizerImpl, which is a range), but the overload of formatValueImpl for structs (instead of ranges or the more expected strings) is choosen for printing. This wrong formatValueImpl tries to print all members of the struct, including the uninitialized ones.
Comment 2 berni44 2019-12-05 16:20:06 UTC
My former comment is a little bit misleading. It's the correct formatValueImpl, which is called, but inside this function the static if, checking for an InputRange, is not executed. This is, because after the cast to const, we have a `const(ToCapitalizerImpl)` which is not anymore recoginzed as an InputRange (i.e. isInputRange fails).

The reason is, that empty, front and popFront would need to be const for a const object, but they cannot be const, because they change the object.

IMHO, this is an invalid bug. The result of "test".asCapitalized is an InputRange and not a string as probably was intended. So, the correct call (if that cast(const) is really needed) would be:

import std.uni;
import std.format;
import std.array;
static immutable x = format("%s", cast(const)"test".asCapitalized.array);

Having said this: The errormessage is confusing. Maybe, the struct part of formatValueImpl should check if a member is initialized, before trying to access it... Therefore I leave this open.

New test example:

```
import std.format;

struct Foo
{
    int a = void;
}

static x = format("%s", Foo());
```
Comment 3 Ali Cehreli 2019-12-05 20:53:17 UTC
Similar:

import std.string;

struct S {
  int i = void;
}

void main() {
  auto s = S(42);
  auto f = format!"%s"(s);
}

Error: cannot read uninitialized variable `i` in CTFE
Comment 4 dlangBugzillaToGithub 2024-12-01 16:34:55 UTC
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/phobos/issues/10369

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB