Thread overview | |||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
February 07, 2015 A safer interface for core.stdc | ||||
---|---|---|---|---|
| ||||
I was looking into ways to make core.stdc safer. That should be relatively easy to do by defining a few wrappers. For example: int setvbuf(FILE* stream, char* buf, int mode, size_t size); is unsafe because there's no relationship between buf and size. But this is fine: @trusted int setvbuf(T)(FILE* stream, T[] buf, int mode) if (is(T == char) || is(T == byte) || is(T == ubyte)) { return setvbuf(stream, cast(char*) buf.ptr, mode, buf.length); } Another example is: int stat(in char*, stat_t*); which may start reading through random memory if the string is not zero-terminated. Again, the solution is here to ensure the string does have a terminating zero: @trusted int stat(in char[] name, stat_t* p) { if (isZeroTerminated(name)) return stat(name.ptr, p); auto t = cast(char*) malloc(name.length + 1); scope(exit) free(t); memcpy(t, name.ptr, name.length); t[name.length] = 0; return stat(t, p); } Such wrappers would allow safe code to use more C stdlib primitives. The question is whether these wrappers are worth adding to core.stdc.stdio. Thanks, Andrei |
February 08, 2015 Re: A safer interface for core.stdc | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu:
> Such wrappers would allow safe code to use more C stdlib primitives.
I'd also like a safer templated wrapper for calloc() and malloc() and similar.
Bye,
bearophile
|
February 08, 2015 Re: A safer interface for core.stdc | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Sun, Feb 08, 2015 at 12:39:39AM +0000, bearophile via Digitalmars-d wrote: > Andrei Alexandrescu: > > >Such wrappers would allow safe code to use more C stdlib primitives. > > I'd also like a safer templated wrapper for calloc() and malloc() and > similar. [...] You mean something like this? T* malloc(T)() @trusted { return cast(T*)malloc(T.sizeof); } struct MyStruct { int x, y, z; } void main() { auto p = malloc!MyStruct(); // Not sure how to make free() usable from @safe, unless // we wrap the pointer returned by malloc(). free(p); } T -- Leather is waterproof. Ever see a cow with an umbrella? |
February 08, 2015 Re: A safer interface for core.stdc | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On 2/7/15 5:26 PM, H. S. Teoh via Digitalmars-d wrote: > On Sun, Feb 08, 2015 at 12:39:39AM +0000, bearophile via Digitalmars-d wrote: >> Andrei Alexandrescu: >> >>> Such wrappers would allow safe code to use more C stdlib primitives. >> >> I'd also like a safer templated wrapper for calloc() and malloc() and >> similar. > [...] > > You mean something like this? > > T* malloc(T)() @trusted > { > return cast(T*)malloc(T.sizeof); > } I think that would go as follows: private @system T[] mallocUninitializedArrayImpl(T)(size_t n) { auto p = malloc(n * T.sizeof); p || assert(0, "Not enough memory"); return (cast(T*) p)[0 .. n]; } @trusted T[] mallocUninitializedArray(size_t n) if (!hasIndirections!T) { return mallocUninitializedArrayImpl!T(n); } @system T[] mallocUninitializedArray(size_t n) if (hasIndirections!T) { return mallocUninitializedArrayImpl!T(n); } Similarly there'd be a mallocMinimallyInitializedArray that zeroes only pointers and is @trusted for all types. Then we'd probably have a @trusted callocArray that blasts zeros throughout. It's @trusted because we know pointers are zeroes (an assumption somewhat not robust in theory but fine in practice). Then we'd have a mallocArray that allocates an array and initializes each element with .init. > struct MyStruct { > int x, y, z; > } > > void main() { > auto p = malloc!MyStruct(); > > // Not sure how to make free() usable from @safe, unless > // we wrap the pointer returned by malloc(). > free(p); > } Indeed we have no safe way to wrap free. Andrei |
February 08, 2015 Re: A safer interface for core.stdc | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Saturday, 7 February 2015 at 23:50:55 UTC, Andrei Alexandrescu wrote:
> I was looking into ways to make core.stdc safer. That should be relatively easy to do by defining a few wrappers. For example:
>
> int setvbuf(FILE* stream, char* buf, int mode, size_t size);
>
> is unsafe because there's no relationship between buf and size. But this is fine:
>
> @trusted int setvbuf(T)(FILE* stream, T[] buf, int mode)
> if (is(T == char) || is(T == byte) || is(T == ubyte))
> {
> return setvbuf(stream, cast(char*) buf.ptr, mode, buf.length);
> }
>
> Another example is:
>
> int stat(in char*, stat_t*);
>
> which may start reading through random memory if the string is not zero-terminated. Again, the solution is here to ensure the string does have a terminating zero:
>
> @trusted int stat(in char[] name, stat_t* p)
> {
> if (isZeroTerminated(name)) return stat(name.ptr, p);
> auto t = cast(char*) malloc(name.length + 1);
> scope(exit) free(t);
> memcpy(t, name.ptr, name.length);
> t[name.length] = 0;
> return stat(t, p);
> }
>
> Such wrappers would allow safe code to use more C stdlib primitives. The question is whether these wrappers are worth adding to core.stdc.stdio.
>
>
> Thanks,
>
> Andrei
One of the reasons why I use C functions is that I expect same behaviour from D code what I would expect from C. I don't think it is a good idea to make wrapper on top of them. Maybe you could say, "Hey, look, it just makes safer, that's all", but, hmm there are so many functions, and this wrapping process can go in many directions.
|
February 08, 2015 Re: A safer interface for core.stdc | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Sat, Feb 07, 2015 at 06:19:19PM -0800, Andrei Alexandrescu via Digitalmars-d wrote: [...] > private @system T[] mallocUninitializedArrayImpl(T)(size_t n) > { > auto p = malloc(n * T.sizeof); > p || assert(0, "Not enough memory"); This is a truly strange way of writing it... why not: assert(p !is null, "Not enough memory"); ? > return (cast(T*) p)[0 .. n]; > } T -- Tell me and I forget. Teach me and I remember. Involve me and I understand. -- Benjamin Franklin |
February 08, 2015 Re: A safer interface for core.stdc | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On Sunday, 8 February 2015 at 04:02:52 UTC, H. S. Teoh wrote:
>> p || assert(0, "Not enough memory");
>
> This is a truly strange way of writing it... why not:
>
> assert(p !is null, "Not enough memory");
I think Andrei's version will remain in release builds, but yours will be elided.
|
February 08, 2015 Re: A safer interface for core.stdc | ||||
---|---|---|---|---|
| ||||
Posted in reply to tcak | On 2/7/15 7:52 PM, tcak wrote:
> One of the reasons why I use C functions is that I expect same behaviour
> from D code what I would expect from C. I don't think it is a good idea
> to make wrapper on top of them. Maybe you could say, "Hey, look, it just
> makes safer, that's all", but, hmm there are so many functions, and this
> wrapping process can go in many directions.
Just looking at making them safe. Not all can be made safe btw. -- Andrei
|
February 08, 2015 Re: A safer interface for core.stdc | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On 2/7/15 8:00 PM, H. S. Teoh via Digitalmars-d wrote:
> On Sat, Feb 07, 2015 at 06:19:19PM -0800, Andrei Alexandrescu via Digitalmars-d wrote:
> [...]
>> private @system T[] mallocUninitializedArrayImpl(T)(size_t n)
>> {
>> auto p = malloc(n * T.sizeof);
>> p || assert(0, "Not enough memory");
>
> This is a truly strange way of writing it... why not:
>
> assert(p !is null, "Not enough memory");
>
> ?
assert(0) is not removed in release mode. -- Andrei
|
February 08, 2015 Re: A safer interface for core.stdc | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Sat, Feb 07, 2015 at 08:14:39PM -0800, Andrei Alexandrescu via Digitalmars-d wrote: > On 2/7/15 7:52 PM, tcak wrote: > >One of the reasons why I use C functions is that I expect same behaviour from D code what I would expect from C. I don't think it is a good idea to make wrapper on top of them. Maybe you could say, "Hey, look, it just makes safer, that's all", but, hmm there are so many functions, and this wrapping process can go in many directions. > > Just looking at making them safe. Not all can be made safe btw. -- Andrei Come to think of it, is there any point in making malloc @safe/@trusted at all? I don't think it's possible to make free() @safe, so what's the purpose of making malloc callable from @safe code? Unless you make a ref-counted wrapper of some sort around it, in which case you might as well use RefCounted instead. I thought about making the equivalent of auto_ptr, but unless you make it non-copyable (or only destructively copyable, and no pointer extraction is permitted), there's no way it can be truly @safe. The only possible advantage we could gain is *type* safety by wrapping malloc in a type-safe way (i.e., don't expose void*). T -- Long, long ago, the ancient Chinese invented a device that lets them see through walls. It was called the "window". |
Copyright © 1999-2021 by the D Language Foundation