Providing implicit conversion of - memory-safety

bachmeier no at spam.net
Tue Jan 23 21:18:53 UTC 2024


On Tuesday, 23 January 2024 at 19:27:26 UTC, Renato wrote:
>> Here's a reduced version of one of the most bizarre bugs I've 
>> dealt with in any language. The only reason I didn't move on 
>> to another language was because I was too busy at the time.
>>
>> The code allows for initial values if the index is less than 
>> 0, otherwise it returns the element.
>>
>> ```
>> import std;
>>
>> double value(T)(T index, double * x) {
>>   if (index - 5 < 0) {
>>     return 0.0;
>>   } else {
>>     return x[index-5];
>>   }
>> }
>>
>> void main() {
>>   double[] v = [1.1, 2.2, 3.3];
>>   // Works
>>   writeln(value(3, v.ptr));
>>   // Lucky: program segfaults
>>   writeln(value(v.length, v.ptr));
>> }
>> ```
>>
>> I noticed this behavior only because the program crashes. Once 
>> I figured out what was going on, I realized that the thousands 
>> of lines of code I had already written needed to be checked 
>> and possibly rewritten. If only I had a compiler to do that 
>> for me.
>
> This code seems to be doing everything it can to run into 
> undefined behaviour, though?
>
> Why is `index` of a type T that has no requirements at all 
> (when the implementation quite clearly wants `size_t`, or at 
> least an unsigned numerical value)? Why is it using a pointer 
> for x when clearly you intend to use it as a slice? You 
> probably have context that I don't, but I would never expect 
> this sort of code to be anywhere near @safe :D

There are two things things that cause the problem. One is the 
use of a template and the other is passing an unsigned type. The 
reason the first parameter uses a template is because there are a 
lot of types I could send as the first argument, and for some of 
them there was a transformation of index (for instance, you can 
pass a date as a long[2], or you can pass another type and pull 
out the length, that sort of thing). It's using a pointer because 
I was working with a C library, and that's how the data is stored 
and passed around.

The data is time series. If after the transformations the index 
is less than zero, it returns 0.0, which is used for all 
pre-sample values. If it's non-negative, return the element at 
that position.

One of the nice things about D is the ability to write this kind 
of code in such a natural and (I thought) intuitive style. I 
really like the way all this comes together. There's really no 
way that code should have been able to do anything wrong. What's 
terribly frustrating is that the compiler had full knowledge of 
what was happening, but by choice it didn't say anything, even 
though D is supposed to prevent these things that happen in C.


More information about the Digitalmars-d-learn mailing list