July 15
On Monday, 15 July 2024 at 18:36:07 UTC, Walter Bright wrote:
> On 7/14/2024 7:06 AM, Timon Gehr wrote:
>> On 7/13/24 22:39, Walter Bright wrote:
>>> I propose that the compiler rewrite:
>>>
>>> ```
>>> char[] name;
>>> printf("name = %s\n", name);
>>> ```
>>> into:
>>> ```
>>> printf("name = %.*s\n", cast(int)name.length, name.ptr);
>>> ```
>>> (and mark any other use of %.*s as unsafe)
>> 
>> This part is actually not memory safe.
>
> How is it not safe?

C23, section 7.23.6.1 ("The fprintf function"), paragraph 5:

> As noted previously, a field width, or precision, or both, may be indicated
> by an asterisk. In this case, an int argument supplies the field width or
> precision. [...] A negative precision argument is taken as if the precision
> were omitted.

So, if the length overflows a 32-bit int, it will be ignored, and printf will read until it finds a zero byte.

I suppose we could have the compiler insert a bounds check, in addition to all of the other rewrites, but at this point, it feels like we're not really calling printf at all; we're calling some other formatted-output function that's stolen printf's identity.
July 15
On 7/15/2024 11:26 AM, Richard (Rikki) Andrew Cattermole wrote:
>> What is IES?
> 
> https://dlang.org/spec/istring.html

Thank you.
July 15
On 7/15/2024 12:56 PM, Paul Backus wrote:
>> How is it not safe?
> 
> C23, section 7.23.6.1 ("The fprintf function"), paragraph 5:
> 
>> As noted previously, a field width, or precision, or both, may be indicated
>> by an asterisk. In this case, an int argument supplies the field width or
>> precision. [...] A negative precision argument is taken as if the precision
>> were omitted.
> 
> So, if the length overflows a 32-bit int, it will be ignored, and printf will read until it finds a zero byte.

Huh, I missed that little gem!

But there's a simple solution:

```
printf("%.*s\n", cast(int)s.length & 0x7FFF_FFFF, s.ptr);
```

Hence, it will always be a positive integer.

That means one can print a maximum of 2 billion characters via printf. Like 640Kb, that ought to be enough for anyone!

While failing to print the entirety of such a (suspiciously) long string, it would not be a memory safety issue.


> I suppose we could have the compiler insert a bounds check, in addition to all of the other rewrites, but at this point, it feels like we're not really calling printf at all; we're calling some other formatted-output function that's stolen printf's identity.

Wrapping APIs with a better interface is what we do all the time :-/
July 16
On Tuesday, 16 July 2024 at 01:22:14 UTC, Walter Bright wrote:
>> I suppose we could have the compiler insert a bounds check, in addition to all of the other rewrites, but at this point, it feels like we're not really calling printf at all; we're calling some other formatted-output function that's stolen printf's identity.
>
> Wrapping APIs with a better interface is what we do all the time :-/

Of course. What I find objectionable in this case is that (a) the better interface is implemented using a bunch of compiler-internal rewrites, rather than normal D code; and (b) it shadows the existing C printf function rather than existing alongside it.

If we need a safer printf for DMD that doesn't carry all the bloat and baggage of Phobos's writef, then by all means, let's write one. But let's write it in D and put it in a normal D module, instead of sneaking around and redefining printf behind our users' backs.
July 16
Followups: https://www.digitalmars.com/d/archives/digitalmars/dip/development/First_Draft_Making_printf_safe_266.html
July 17

On Saturday, 13 July 2024 at 20:39:32 UTC, Walter Bright wrote:

>

The idea is printf is already largely safe:
[...]

@safe functions cannot perform pointer arithmetic, but printf does because it indexes a char* (its first parameter).

July 17

On Wednesday, 17 July 2024 at 08:58:56 UTC, IchorDev wrote:

>

On Saturday, 13 July 2024 at 20:39:32 UTC, Walter Bright wrote:

>

The idea is printf is already largely safe:
[...]

@safe functions cannot perform pointer arithmetic, but printf does because it indexes a char* (its first parameter).

The idea is to make certain calls of printf safe when the first argument is a string literal:

char[] s;
printf("%s\n", s);

See https://forum.dlang.org/post/v775k1$1tmj$1@digitalmars.com.

July 17

On Wednesday, 17 July 2024 at 09:20:23 UTC, Nick Treleaven wrote:

>

On Wednesday, 17 July 2024 at 08:58:56 UTC, IchorDev wrote:

>

On Saturday, 13 July 2024 at 20:39:32 UTC, Walter Bright wrote:

>

The idea is printf is already largely safe:
[...]

@safe functions cannot perform pointer arithmetic, but printf does because it indexes a char* (its first parameter).

The idea is to make certain calls of printf safe when the first argument is a string literal:

char[] s;
printf("%s\n", s);

See https://forum.dlang.org/post/v775k1$1tmj$1@digitalmars.com.

I fail to see why there can’t be a dprintf that works like printf except that for *.s bound to a const(char)[] object, it decomposes it properly into its length and pointer component. Or, even better, use a different specifier, e.g. %D.

July 17
Please continue this here:

https://www.digitalmars.com/d/archives/digitalmars/dip/development/First_Draft_Making_printf_safe_266.html
July 17

On Wednesday, 17 July 2024 at 09:20:23 UTC, Nick Treleaven wrote:

>

The idea is to make certain calls of printf safe when the first argument is a string literal:

char[] s;
printf("%s\n", s);

See https://forum.dlang.org/post/v775k1$1tmj$1@digitalmars.com.

And the function will still perform pointer arithmetic.