msoucy / dproto

D Protocol Buffer mixins to create structures at compile time
Boost Software License 1.0
37 stars 16 forks source link

Possible to use dproto in @safe code. #79

Open puzzlehawk opened 8 years ago

puzzlehawk commented 8 years ago

1) With this changes it should be possible to use structs generated with dproto in @safe functions. However, parsing protobuf code is still not @safe.

2) Removed deprecated inline imports.

coveralls commented 8 years ago

Coverage Status

Coverage decreased (-0.2%) to 74.663% when pulling 5e95d6d9d38832310333485253adfd82b3499567 on puzzlehawk:safeness into 4e47edbdd832dd425c9139d3b335a4f0d0a10e50 on msoucy:master.

WebDrake commented 8 years ago

My earlier comment, that @safe should only be applied to non-templated functions and methods, should be taken as applying to the entire commit. It's simply not appropriate to make promises about templated methods where you have no way of knowing if the instantiation will actually be compatible with the @safe attribute.

Apart from that, the commit message should be something meaningful explaining the rationale for the changes.

WebDrake commented 8 years ago

Broadly, I'm concerned that this PR is just trying to get dproto code to compile inside @safe code blocks, without actually thinking through the rationale of what actually is safe.

I speak here purely as a user, not a maintainer, but I would not be happy to see dproto promising @safe code without a better rationale than is given here for the changes made.

WebDrake commented 8 years ago

2) Removed deprecated inline imports.

I don't see any sign of this in the diff ... ?

puzzlehawk commented 8 years ago

@WebDrake: Thanks for having a look at this.

Broadly, I'm concerned that this PR is just trying to get dproto code to compile inside @safe code blocks, without actually thinking through the rationale of what actually is safe.

Partially true. For me it seems to be important that processing of non-trusted data cannot lead to memory corruptions. dproto will likely be used in networking where none of the incoming data can be trusted. Therefore I claim providing @safety should be mandatory for that kind of library. Clearly we can argue about user provided code such as output ranges. For instance how to we handle R.put() in writeProto()? Do we require it to be @safe? Could be reasonable. I agree that having writeProto() just @trusted would be dangerously transparent to the user.

2) Removed deprecated inline imports.

I don't see any sign of this in the diff ... ?

Your eyes are right. Copy-paste accident on my side.

WebDrake commented 8 years ago

For me it seems to be important that processing of non-trusted data cannot lead to memory corruptions.

Yes. This is why it's important to differentiate between code that actually is safe, versus code that merely compiles inside a @safe block. Your changes as they are currently actually make the user less safe, by providing a false promise that the code meets the requirements of @safe.

Therefore I claim providing @safety should be mandatory for that kind of library.

Note that the library's ability to provide genuine guarantees of safety may depend on the way the downstream user is using the library. It isn't necessarily the place of a library author to ban use-cases that are incompatible with @safe code blocks.

For instance how to we handle R.put() in writeProto()? Do we require it to be @safe? Could be reasonable.

You should not be putting @trusted on anything that you cannot manually verify as memory-safe. Given that you don't know what R is, it would be very dangerous to use @trusted in this context. A @safe put() method for the given R is therefore a necessary (but not sufficient) condition in order for the corresponding writeProto() instantiation to be inferred as @safe.

In this case, I think the problem with writeProto() may not only be whether R.put() is safe, but also the cast to ubyte[]. I would suggest looking at how converting a BuffType!T to ubyte[] could be made verifiably safe. Probably the best way would be to replace the cast with a function that takes BuffType!T as input and returns a const(ubyte[]) in a way that is guaranteed safe for the types that the BuffType template evaluates to.

Note that if BuffType!T is a value-type, you may have to deal with the fact that the resulting ubyte[] will be invalid the moment the BuffType!T src variable goes out of scope.