Date: Fri, 20 Jan 2023 09:08:34 +0100
> Why is the code iterating over 5 elements of a two-element array to
start with?
Just an example without any practical purpose, written for illustration.
An early developer (my students for example) would easily make such
mistake leading to a segfault at execution. Understanding the reason of
the memory issue is not trivial. A more concrete example is for example:
You have an "interface" Phone (pure virtual methods) and you have to
iterate over a set of Phone calling a method, some of my student wrote:
void f(Phone *t,int l){
for(int i=O;i<l;i++){
t->method(); // t[i].method(); is also accepted by the
language
t++; // but also not valid of course
}
}
Of course, for C++ developers this is a trivial mistake but an early
leaner (with java background in addition) it can be less obvious...
On 20/01/2023 08:42, Jens Maurer wrote:
>
> On 20/01/2023 07.55, Julien Allali via Std-Proposals wrote:
>> Hi everyone,
>>
>> I checked the following code from one of my student:
>>
>> class I{
>> public:
>> virtual ~I(){}
>> virtual void print(){
>> printf("hello %p\n",this);
>> }
>> virtual void f()=0;
>> };
>>
>> class B : public virtual I{
>> int i,j;
>> public:
>> ~B(){}
>> virtual void f(){
>> printf("B %p\n",this);
>> }
>> };
>>
>>
>> void f(I *i){
>> for(int j=0;j<5;++j)
>> {
>> i->print();
>> i->f();
>> printf("i=%p ",i);
>> i++; // PROBLEM IS HERE
>> printf(" => %p \n",i);
>> }
>> }
>>
>> int main(){
>> B b[]={B(),B()};
>> printf("B: %p %p\n",b,b+1);
>> f(b);
>> }
>>
>> As you can see, I is a non instantiable type as it has one pure virtual
>> method. My concern is about the line "i++": I believed it will lead to
>> an error or at least a warning (g++ 11.3.0)... Indeed, I can not imagine
>> a valid case where doing arithmetic on a pointer of a type with pure
>> virtual function can be valid.... Shouldn't the standard forbid such
>> arithmetic?
> Why is the code iterating over 5 elements of a two-element array to
> start with?
>
> Anyway, the "i++" is undefined behavior per [expr.add] p6:
>
>> For addition or subtraction, if the expressions P or Q have type “pointer to cv T”,
>> where T and the array element type are not similar (7.3.6), the behavior is undefined.
> This is a rather broad prohibition that can, in general, not be checked
> by a compiler (halting problem). I agree it can be checked in the narrow
> case of a pointer to an abstract class, but that might not be worth the
> bother. If you feel you want a guaranteed diagnostic in that case, submit
> a short paper to EWG: https://isocpp.org/std/submit-a-proposal
>
> The paper should contain good rationale why diagnosing a comparatively
> rare single case among the many undefined behavior cases in this area is
> worth the (standardization and implementation) effort.
>
> Jens
start with?
Just an example without any practical purpose, written for illustration.
An early developer (my students for example) would easily make such
mistake leading to a segfault at execution. Understanding the reason of
the memory issue is not trivial. A more concrete example is for example:
You have an "interface" Phone (pure virtual methods) and you have to
iterate over a set of Phone calling a method, some of my student wrote:
void f(Phone *t,int l){
for(int i=O;i<l;i++){
t->method(); // t[i].method(); is also accepted by the
language
t++; // but also not valid of course
}
}
Of course, for C++ developers this is a trivial mistake but an early
leaner (with java background in addition) it can be less obvious...
On 20/01/2023 08:42, Jens Maurer wrote:
>
> On 20/01/2023 07.55, Julien Allali via Std-Proposals wrote:
>> Hi everyone,
>>
>> I checked the following code from one of my student:
>>
>> class I{
>> public:
>> virtual ~I(){}
>> virtual void print(){
>> printf("hello %p\n",this);
>> }
>> virtual void f()=0;
>> };
>>
>> class B : public virtual I{
>> int i,j;
>> public:
>> ~B(){}
>> virtual void f(){
>> printf("B %p\n",this);
>> }
>> };
>>
>>
>> void f(I *i){
>> for(int j=0;j<5;++j)
>> {
>> i->print();
>> i->f();
>> printf("i=%p ",i);
>> i++; // PROBLEM IS HERE
>> printf(" => %p \n",i);
>> }
>> }
>>
>> int main(){
>> B b[]={B(),B()};
>> printf("B: %p %p\n",b,b+1);
>> f(b);
>> }
>>
>> As you can see, I is a non instantiable type as it has one pure virtual
>> method. My concern is about the line "i++": I believed it will lead to
>> an error or at least a warning (g++ 11.3.0)... Indeed, I can not imagine
>> a valid case where doing arithmetic on a pointer of a type with pure
>> virtual function can be valid.... Shouldn't the standard forbid such
>> arithmetic?
> Why is the code iterating over 5 elements of a two-element array to
> start with?
>
> Anyway, the "i++" is undefined behavior per [expr.add] p6:
>
>> For addition or subtraction, if the expressions P or Q have type “pointer to cv T”,
>> where T and the array element type are not similar (7.3.6), the behavior is undefined.
> This is a rather broad prohibition that can, in general, not be checked
> by a compiler (halting problem). I agree it can be checked in the narrow
> case of a pointer to an abstract class, but that might not be worth the
> bother. If you feel you want a guaranteed diagnostic in that case, submit
> a short paper to EWG: https://isocpp.org/std/submit-a-proposal
>
> The paper should contain good rationale why diagnosing a comparatively
> rare single case among the many undefined behavior cases in this area is
> worth the (standardization and implementation) effort.
>
> Jens
Received on 2023-01-20 08:08:40