public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* gcc warn when pointers not checked non-null before de-referencing.
@ 2021-06-13 22:30 Jonny Grant
  2021-06-14  5:15 ` Xi Ruoyao
  2021-06-14 15:19 ` Martin Sebor
  0 siblings, 2 replies; 16+ messages in thread
From: Jonny Grant @ 2021-06-13 22:30 UTC (permalink / raw)
  To: gcc-help

Hello

This isn't real code, just an example to show.

I've tried with:  -Wall -Wextra -O2  and some other warnings, but couldn't get this to generate a warning that *g was possibly de-referenced. May I ask, does GCC have a way to get warnings when pointers are not checked?
I had a look but -Wnull-dereference didn't help.

#include <stdlib.h>

#include <cstddef>
void f(int * g)
{
    *g = 1;

    if(NULL == g)
    {
        exit(1);
    }
}

Best regards Jonny

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: gcc warn when pointers not checked non-null before de-referencing.
  2021-06-13 22:30 gcc warn when pointers not checked non-null before de-referencing Jonny Grant
@ 2021-06-14  5:15 ` Xi Ruoyao
  2021-06-16 13:01   ` Jonny Grant
  2021-06-14 15:19 ` Martin Sebor
  1 sibling, 1 reply; 16+ messages in thread
From: Xi Ruoyao @ 2021-06-14  5:15 UTC (permalink / raw)
  To: Jonny Grant, gcc-help

On Sun, 2021-06-13 at 23:30 +0100, Jonny Grant wrote:
> Hello
> 
> This isn't real code, just an example to show.
> 
> I've tried with:  -Wall -Wextra -O2  and some other warnings, but
> couldn't get this to generate a warning that *g was possibly de-
> referenced. May I ask, does GCC have a way to get warnings when pointers
> are not checked?
> I had a look but -Wnull-dereference didn't help.
> 
> #include <stdlib.h>
> 
> #include <cstddef>
> void f(int * g)
> {
>     *g = 1;
> 
>     if(NULL == g)
>     {
>         exit(1);
>     }
> }
> 
> Best regards Jonny

It was explained by Chris Lattner at
http://blog.llvm.org/2011/05/what-every-c-programmer-should-know_21.html

GCC (<= 4.4) had -Wunreachable-code which might work for this case.  But
it was too unreliable (as Chris said, generally there is no reliable way
to do this) and removed in later releases.
-- 
Xi Ruoyao <xry111@mengyan1223.wang>
School of Aerospace Science and Technology, Xidian University


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: gcc warn when pointers not checked non-null before de-referencing.
  2021-06-13 22:30 gcc warn when pointers not checked non-null before de-referencing Jonny Grant
  2021-06-14  5:15 ` Xi Ruoyao
@ 2021-06-14 15:19 ` Martin Sebor
  1 sibling, 0 replies; 16+ messages in thread
From: Martin Sebor @ 2021-06-14 15:19 UTC (permalink / raw)
  To: Jonny Grant, gcc-help

On 6/13/21 4:30 PM, Jonny Grant wrote:
> Hello
> 
> This isn't real code, just an example to show.
> 
> I've tried with:  -Wall -Wextra -O2  and some other warnings, but couldn't get this to generate a warning that *g was possibly de-referenced. May I ask, does GCC have a way to get warnings when pointers are not checked?
> I had a look but -Wnull-dereference didn't help.

The pointer test is eliminated before -Wnull-dereference runs so it
can't do anything in this case.  -fno-delete-null-pointer-checks
disables the optimization and retains the test so -Wnull-dereference
could in theory detect it but it isn't designed to do it.  But if
it did, I suspect it would be quite noisy as a result of other
transformations like inlining and constant propagation.  So making
it work with an acceptable S/R ratio would take more work than just
enhancing -Wnull-dereference.

Martin

> 
> #include <stdlib.h>
> 
> #include <cstddef>
> void f(int * g)
> {
>      *g = 1;
> 
>      if(NULL == g)
>      {
>          exit(1);
>      }
> }
> 
> Best regards Jonny
> 


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: gcc warn when pointers not checked non-null before de-referencing.
  2021-06-14  5:15 ` Xi Ruoyao
@ 2021-06-16 13:01   ` Jonny Grant
  2021-06-16 13:36     ` Xi Ruoyao
  2021-06-16 17:59     ` Segher Boessenkool
  0 siblings, 2 replies; 16+ messages in thread
From: Jonny Grant @ 2021-06-16 13:01 UTC (permalink / raw)
  To: Xi Ruoyao, gcc-help



On 14/06/2021 06:15, Xi Ruoyao wrote:
> On Sun, 2021-06-13 at 23:30 +0100, Jonny Grant wrote:
>> Hello
>>
>> This isn't real code, just an example to show.
>>
>> I've tried with:  -Wall -Wextra -O2  and some other warnings, but
>> couldn't get this to generate a warning that *g was possibly de-
>> referenced. May I ask, does GCC have a way to get warnings when pointers
>> are not checked?
>> I had a look but -Wnull-dereference didn't help.
>>
>> #include <stdlib.h>
>>
>> #include <cstddef>
>> void f(int * g)
>> {
>>     *g = 1;
>>
>>     if(NULL == g)
>>     {
>>         exit(1);
>>     }
>> }
>>
>> Best regards Jonny
> 
> It was explained by Chris Lattner at
> http://blog.llvm.org/2011/05/what-every-c-programmer-should-know_21.html
> 
> GCC (<= 4.4) had -Wunreachable-code which might work for this case.  But
> it was too unreliable (as Chris said, generally there is no reliable way
> to do this) and removed in later releases.
> 

Thank you for your reply and the link. And for Martin's reply.

I guess a separate static analyser would do it, GCC is more focused on compilation so I shouldn't ask for it to have so many features it can't support.


Chris Latner also mentioned integer overflow being undefined, that crops up too. There's no easy solution right, we need to hand write code the checks?  It's human-error prone if we need to manually code each check. throwing in C++, or handling in C.

if(N >= INT_MAX)
{
    throw std::overflow_error("N >= INT_MAX would overflow in for loop");
}

for (i = 0; i <= N; ++i)
{
// ...
 }

Cheers, Jonny

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: gcc warn when pointers not checked non-null before de-referencing.
  2021-06-16 13:01   ` Jonny Grant
@ 2021-06-16 13:36     ` Xi Ruoyao
  2021-07-03 15:36       ` Jonny Grant
  2021-06-16 17:59     ` Segher Boessenkool
  1 sibling, 1 reply; 16+ messages in thread
From: Xi Ruoyao @ 2021-06-16 13:36 UTC (permalink / raw)
  To: Jonny Grant, gcc-help

On Wed, 2021-06-16 at 14:01 +0100, Jonny Grant wrote:

> Chris Latner also mentioned integer overflow being undefined, that
> crops up too. There's no easy solution right, we need to hand write
> code the checks?  It's human-error prone if we need to manually code
> each check. throwing in C++, or handling in C.
> 
> if(N >= INT_MAX)
> {
>     throw std::overflow_error("N >= INT_MAX would overflow in for
> loop");
> }
> 
> for (i = 0; i <= N; ++i)
> {
> // ...
>  }

For debugging use -fsanitize=undefined.

And this is buggy anyway, no matter if there is an UB:

for (unsigned i = 0; i <= N; i++)
    make_some_side_effect_without_any_undefined_behavior(i);

If N may be UINT_MAX, this is not UB, but a dead loop. Programming is
just human-error prone, even if you use "some programming language
claimed to be able to eliminate many human errors" (I'll not say its
name, to prevent a flame war).
-- 
Xi Ruoyao <xry111@mengyan1223.wang>
School of Aerospace Science and Technology, Xidian University


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: gcc warn when pointers not checked non-null before de-referencing.
  2021-06-16 13:01   ` Jonny Grant
  2021-06-16 13:36     ` Xi Ruoyao
@ 2021-06-16 17:59     ` Segher Boessenkool
  2021-06-17 20:44       ` Jonny Grant
  1 sibling, 1 reply; 16+ messages in thread
From: Segher Boessenkool @ 2021-06-16 17:59 UTC (permalink / raw)
  To: Jonny Grant; +Cc: Xi Ruoyao, gcc-help

On Wed, Jun 16, 2021 at 02:01:05PM +0100, Jonny Grant wrote:
> I guess a separate static analyser would do it, GCC is more focused on compilation so I shouldn't ask for it to have so many features it can't support.

-fsanitize=undefined already catches null pointer dereferences, is that
enough for your case?


Segher

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: gcc warn when pointers not checked non-null before de-referencing.
  2021-06-16 17:59     ` Segher Boessenkool
@ 2021-06-17 20:44       ` Jonny Grant
  2021-06-18  4:16         ` Xi Ruoyao
                           ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Jonny Grant @ 2021-06-17 20:44 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: Xi Ruoyao, gcc-help



On 16/06/2021 18:59, Segher Boessenkool wrote:
> On Wed, Jun 16, 2021 at 02:01:05PM +0100, Jonny Grant wrote:
>> I guess a separate static analyser would do it, GCC is more focused on compilation so I shouldn't ask for it to have so many features it can't support.
> 
> -fsanitize=undefined already catches null pointer dereferences, is that
> enough for your case?
> 
> 
> Segher

Hello
Thank you for the suggestion, yes, I had used that before. I did just check, it's runtime checks. I had hoped for something at compile time. warning for every function that didn't check pointer for NULL before de-referencing.

$ ./null
null.c:7:5: runtime error: load of null pointer of type 'int'
Segmentation fault (core dumped)



// gcc -Wall -fsanitize=undefined -o null null.c

#include <stdio.h>

void f(int * p)
{
    printf("%d\n", *p);
}

int main()
{
    f(NULL);
}

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: gcc warn when pointers not checked non-null before de-referencing.
  2021-06-17 20:44       ` Jonny Grant
@ 2021-06-18  4:16         ` Xi Ruoyao
  2021-07-03 14:14           ` Jonny Grant
  2021-06-18  8:38         ` Liu Hao
  2021-06-18 14:53         ` Segher Boessenkool
  2 siblings, 1 reply; 16+ messages in thread
From: Xi Ruoyao @ 2021-06-18  4:16 UTC (permalink / raw)
  To: Jonny Grant, Segher Boessenkool; +Cc: gcc-help

On Thu, 2021-06-17 at 21:44 +0100, Jonny Grant wrote:
> 
> 
> On 16/06/2021 18:59, Segher Boessenkool wrote:
> > On Wed, Jun 16, 2021 at 02:01:05PM +0100, Jonny Grant wrote:
> > > I guess a separate static analyser would do it, GCC is more
> > > focused on compilation so I shouldn't ask for it to have so many
> > > features it can't support.
> > 
> > -fsanitize=undefined already catches null pointer dereferences, is
> > that
> > enough for your case?
> > 
> > 
> > Segher
> 
> Hello
> Thank you for the suggestion, yes, I had used that before. I did just
> check, it's runtime checks. I had hoped for something at compile time.
> warning for every function that didn't check pointer for NULL before
> de-referencing.

There is no way to do this.

int foo(struct dev *dev)
{
    int r = sanitize_input(dev);
    if (r)
        return r;

    bar(&dev->id);
    return dev->id->result;
}

While there is no way to know the behavior of `sanitize_input` (it may
be defined in another TU), there is no way to tell if `foo` has done "a
proper non-null check".

And this "warning" does not make any sense.  It's perfectly legal for a
function to assume the input is not null and the caller should guarantee
it.  Adding a non-null check in every function is just paranoid.  This
really looks like a suggestion from some professors who don't program at
all, but unfortunately teach C and tell their own misconcept of
"defensive programming" everywhere.
-- 
Xi Ruoyao <xry111@mengyan1223.wang>
School of Aerospace Science and Technology, Xidian University


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: gcc warn when pointers not checked non-null before de-referencing.
  2021-06-17 20:44       ` Jonny Grant
  2021-06-18  4:16         ` Xi Ruoyao
@ 2021-06-18  8:38         ` Liu Hao
  2021-06-18 14:53         ` Segher Boessenkool
  2 siblings, 0 replies; 16+ messages in thread
From: Liu Hao @ 2021-06-18  8:38 UTC (permalink / raw)
  To: Jonny Grant, Segher Boessenkool; +Cc: gcc-help


[-- Attachment #1.1: Type: text/plain, Size: 576 bytes --]

在 2021-06-18 04:44, Jonny Grant 写道:
> 
> Hello
> Thank you for the suggestion, yes, I had used that before. I did just check, it's runtime checks. I had hoped for something at compile time. warning for every function that didn't check pointer for NULL before de-referencing.
> 

You might want to have a look at <http://cppcheck.sourceforge.net/demo/>. There are some 'NULL 
pointers' examples which answers your exact question.

If you use Debian or Ubuntu, you can install cppcheck with `sudo aptitude install cppcheck`.



-- 
Best regards,
Liu Hao


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: gcc warn when pointers not checked non-null before de-referencing.
  2021-06-17 20:44       ` Jonny Grant
  2021-06-18  4:16         ` Xi Ruoyao
  2021-06-18  8:38         ` Liu Hao
@ 2021-06-18 14:53         ` Segher Boessenkool
  2 siblings, 0 replies; 16+ messages in thread
From: Segher Boessenkool @ 2021-06-18 14:53 UTC (permalink / raw)
  To: Jonny Grant; +Cc: Xi Ruoyao, gcc-help

On Thu, Jun 17, 2021 at 09:44:27PM +0100, Jonny Grant wrote:
> On 16/06/2021 18:59, Segher Boessenkool wrote:
> > On Wed, Jun 16, 2021 at 02:01:05PM +0100, Jonny Grant wrote:
> >> I guess a separate static analyser would do it, GCC is more focused on compilation so I shouldn't ask for it to have so many features it can't support.
> > 
> > -fsanitize=undefined already catches null pointer dereferences, is that
> > enough for your case?
> 
> Hello
> Thank you for the suggestion, yes, I had used that before. I did just check, it's runtime checks. I had hoped for something at compile time. warning for every function that didn't check pointer for NULL before de-referencing.

That doesn't make too much sense really.  Check pointer and then do
what?  Your code can check for null pointers itself, of course.

Anyway, without any sanitize options, from the following code:

int f(int *p) { return *p; }
int g(void) { return f(0); }

you get on powerpc64le:

f:
	lwa 3,0(3)
	blr
g:
	li 9,0
	lfiwax 0,0,9
	trap

or on aarch64:

f:
	ldr     w0, [x0]
	ret
g:
	mov     x0, 0
	ldr     w0, [x0]
	brk #1000

or on x86_64:

f:
	movl    (%rdi), %eax
	ret
g:
	movl    0, %eax
	ud2

GCC knows the code after the load is not reachable, that is why it
generates a trap instruction there.  I will still do the load though, so
that you get good errors and a reasonable debug experience.


Segher

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: gcc warn when pointers not checked non-null before de-referencing.
  2021-06-18  4:16         ` Xi Ruoyao
@ 2021-07-03 14:14           ` Jonny Grant
  2021-07-03 16:22             ` Segher Boessenkool
  0 siblings, 1 reply; 16+ messages in thread
From: Jonny Grant @ 2021-07-03 14:14 UTC (permalink / raw)
  To: Xi Ruoyao, Segher Boessenkool; +Cc: gcc-help



On 18/06/2021 05:16, Xi Ruoyao wrote:
> On Thu, 2021-06-17 at 21:44 +0100, Jonny Grant wrote:
>>
>>
>> On 16/06/2021 18:59, Segher Boessenkool wrote:
>>> On Wed, Jun 16, 2021 at 02:01:05PM +0100, Jonny Grant wrote:
>>>> I guess a separate static analyser would do it, GCC is more
>>>> focused on compilation so I shouldn't ask for it to have so many
>>>> features it can't support.
>>>
>>> -fsanitize=undefined already catches null pointer dereferences, is
>>> that
>>> enough for your case?
>>>
>>>
>>> Segher
>>
>> Hello
>> Thank you for the suggestion, yes, I had used that before. I did just
>> check, it's runtime checks. I had hoped for something at compile time.
>> warning for every function that didn't check pointer for NULL before
>> de-referencing.
> 
> There is no way to do this.
> 
> int foo(struct dev *dev)
> {
>     int r = sanitize_input(dev);
>     if (r)
>         return r;
> 
>     bar(&dev->id);
>     return dev->id->result;
> }
> 
> While there is no way to know the behavior of `sanitize_input` (it may
> be defined in another TU), there is no way to tell if `foo` has done "a
> proper non-null check".

Yes, this is a good point, could only check the file that is being compiled.

> 
> And this "warning" does not make any sense.  It's perfectly legal for a
> function to assume the input is not null and the caller should guarantee
> it.  Adding a non-null check in every function is just paranoid.  This
> really looks like a suggestion from some professors who don't program at
> all, but unfortunately teach C and tell their own misconcept of
> "defensive programming" everywhere.

We were taught to be careful what we pass to functions, and careful what we accept in functions, feels appropriate.

While I can see that for developer builds, a NULL dereference and core dump would allow a developer to investigate. assert is just as good assert(NULL != ptr);

We'd rather have stability and logging of errors than a core dump. Especially on embedded systems that need to guarantee safety. It's easy enough to check for NULL and check the bounds of buffers etc before using. Asserts would trigger in a debug build.

I know GCC is a compiler, not a static analyser, so I'll probably run cppcheck

Kind regards
Jonny

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: gcc warn when pointers not checked non-null before de-referencing.
  2021-06-16 13:36     ` Xi Ruoyao
@ 2021-07-03 15:36       ` Jonny Grant
  2021-07-06 15:39         ` Xi Ruoyao
  0 siblings, 1 reply; 16+ messages in thread
From: Jonny Grant @ 2021-07-03 15:36 UTC (permalink / raw)
  To: Xi Ruoyao, gcc-help



On 16/06/2021 14:36, Xi Ruoyao wrote:
> On Wed, 2021-06-16 at 14:01 +0100, Jonny Grant wrote:
> 
>> Chris Latner also mentioned integer overflow being undefined, that
>> crops up too. There's no easy solution right, we need to hand write
>> code the checks?  It's human-error prone if we need to manually code
>> each check. throwing in C++, or handling in C.
>>
>> if(N >= INT_MAX)
>> {
>>     throw std::overflow_error("N >= INT_MAX would overflow in for
>> loop");
>> }
>>
>> for (i = 0; i <= N; ++i)
>> {
>> // ...
>>  }
> 
> For debugging use -fsanitize=undefined.
> 
> And this is buggy anyway, no matter if there is an UB:
> 
> for (unsigned i = 0; i <= N; i++)
>     make_some_side_effect_without_any_undefined_behavior(i);
> 
> If N may be UINT_MAX, this is not UB, but a dead loop. Programming is
> just human-error prone, even if you use "some programming language
> claimed to be able to eliminate many human errors" (I'll not say its
> name, to prevent a flame war).
> 
Hi Xi


Checking the UINT_MAX would at least prevent the continual running of any such buggy loop where it increments right? and the code within the loop does not modify 'i'

for (unsigned i = 0; (i <= N) && (i != UINT_MAX); i++)
    make_some_side_effect_without_any_undefined_behavior(i);

Is there any way to have a way to make loop variables like this 'i' const within the body of the loop, to avoid accidental changing of 'i' by the body of the loop

Jonny

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: gcc warn when pointers not checked non-null before de-referencing.
  2021-07-03 14:14           ` Jonny Grant
@ 2021-07-03 16:22             ` Segher Boessenkool
  2021-07-06 10:33               ` Jonny Grant
  0 siblings, 1 reply; 16+ messages in thread
From: Segher Boessenkool @ 2021-07-03 16:22 UTC (permalink / raw)
  To: Jonny Grant; +Cc: Xi Ruoyao, gcc-help

On Sat, Jul 03, 2021 at 03:14:21PM +0100, Jonny Grant wrote:
> We'd rather have stability and logging of errors than a core dump. Especially on embedded systems that need to guarantee safety. It's easy enough to check for NULL and check the bounds of buffers etc before using. Asserts would trigger in a debug build.

There *is* no generic way you can sanely and even safely handle null
pointer dereferences at all.  You *have to* separately write code for
every place you want to do something special with null pointers (or any
other special case for that matter).

In case you are talking about a system with an event loop (or similar),
where you can just abort the task you are doing, and get back to waiting
for more work to do: you can just catch *all* fatal errors (which a null
dereference normally is), log it, and go back to the main loop.  But
even then the null dereference could be caused by something that is not
yet fixed.  If you are lucky other tasks can still be done.   OTOH,
perhaps just as often nothing will work anymore.

In any case, there is nothing the compiler can do for you here.  If
programming were a mechanical job, we wouldn't need all those pesky
programmers :-)


Segher

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: gcc warn when pointers not checked non-null before de-referencing.
  2021-07-03 16:22             ` Segher Boessenkool
@ 2021-07-06 10:33               ` Jonny Grant
  0 siblings, 0 replies; 16+ messages in thread
From: Jonny Grant @ 2021-07-06 10:33 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: Xi Ruoyao, gcc-help



On 03/07/2021 17:22, Segher Boessenkool wrote:
> On Sat, Jul 03, 2021 at 03:14:21PM +0100, Jonny Grant wrote:
>> We'd rather have stability and logging of errors than a core dump. Especially on embedded systems that need to guarantee safety. It's easy enough to check for NULL and check the bounds of buffers etc before using. Asserts would trigger in a debug build.
> 
> There *is* no generic way you can sanely and even safely handle null
> pointer dereferences at all.  You *have to* separately write code for
> every place you want to do something special with null pointers (or any
> other special case for that matter).
> 
> In case you are talking about a system with an event loop (or similar),
> where you can just abort the task you are doing, and get back to waiting
> for more work to do: you can just catch *all* fatal errors (which a null
> dereference normally is), log it, and go back to the main loop.  But
> even then the null dereference could be caused by something that is not
> yet fixed.  If you are lucky other tasks can still be done.   OTOH,
> perhaps just as often nothing will work anymore.

Yes, you are quite right! The error could be handled by the calling code, or logged for later debugging use, and hopefully for a safety critical system it continues to run. In some instances we would restart that module after a recurring error, and use a watchdog thread to reboot if something severe that can't be recovered on an overall system.

An example would be as follows sample function:

int component_msg(unsigned int component, const char * msg)
{
    if(NULL == msg)
    {
        log_msg("component_msg component %d called with NULL msg\n", component);
        return EFAULT;
    }
    else
    {
        log_msg("%s", msg);
        return 0;
    }
}

The calling code could also check the return of component_msg() and handle some appropriate way. Restarting the module, notifying another system, ignoring a faulty device etc

> 
> In any case, there is nothing the compiler can do for you here.  If
> programming were a mechanical job, we wouldn't need all those pesky
> programmers :-)
> 
> 
> Segher
> 


Cheers, Jonny


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: gcc warn when pointers not checked non-null before de-referencing.
  2021-07-03 15:36       ` Jonny Grant
@ 2021-07-06 15:39         ` Xi Ruoyao
  2021-07-19 18:20           ` Jonny Grant
  0 siblings, 1 reply; 16+ messages in thread
From: Xi Ruoyao @ 2021-07-06 15:39 UTC (permalink / raw)
  To: Jonny Grant, gcc-help

On Sat, 2021-07-03 at 16:36 +0100, Jonny Grant wrote:
> 
> 
> On 16/06/2021 14:36, Xi Ruoyao wrote:
> > On Wed, 2021-06-16 at 14:01 +0100, Jonny Grant wrote:
> > 
> > > Chris Latner also mentioned integer overflow being undefined, that
> > > crops up too. There's no easy solution right, we need to hand write
> > > code the checks?  It's human-error prone if we need to manually code
> > > each check. throwing in C++, or handling in C.
> > > 
> > > if(N >= INT_MAX)
> > > {
> > >     throw std::overflow_error("N >= INT_MAX would overflow in for
> > > loop");
> > > }
> > > 
> > > for (i = 0; i <= N; ++i)
> > > {
> > > // ...
> > >  }
> > 
> > For debugging use -fsanitize=undefined.
> > 
> > And this is buggy anyway, no matter if there is an UB:
> > 
> > for (unsigned i = 0; i <= N; i++)
> >     make_some_side_effect_without_any_undefined_behavior(i);
> > 
> > If N may be UINT_MAX, this is not UB, but a dead loop. Programming is
> > just human-error prone, even if you use "some programming language
> > claimed to be able to eliminate many human errors" (I'll not say its
> > name, to prevent a flame war).
> > 
> Hi Xi
> 
> 
> Checking the UINT_MAX would at least prevent the continual running of
> any such buggy loop where it increments right? and the code within the
> loop does not modify 'i'
> 
> for (unsigned i = 0; (i <= N) && (i != UINT_MAX); i++)
>     make_some_side_effect_without_any_undefined_behavior(i);

Even if i is signed, it will still "work" if you modify the &&
expression a little:

for (int i = 0; i != UINT_MAX && i < N; i++)
     make_some_side_effect_without_any_undefined_behavior(i);

The problem is, now the behavior when N == UINT_MAX is same with when N
== (UINT_MAX - 1).  This can really puzzle someone who will call your
function.

If I'm designing this function I'd make it to interpret N as [0, N),
instead of [0, N]:

// Do something for each integer in [0, N).
void do_something(int N)
{
    for (int i = 0; i < N; i++)
        do_something_once(i);
}

> Is there any way to have a way to make loop variables like this 'i'
> const within the body of the loop, to avoid accidental changing of 'i'
> by the body of the loop

I don't think there is one in C.  Perhaps, maybe use some "nasty"
macros.
-- 
Xi Ruoyao <xry111@mengyan1223.wang>
School of Aerospace Science and Technology, Xidian University


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: gcc warn when pointers not checked non-null before de-referencing.
  2021-07-06 15:39         ` Xi Ruoyao
@ 2021-07-19 18:20           ` Jonny Grant
  0 siblings, 0 replies; 16+ messages in thread
From: Jonny Grant @ 2021-07-19 18:20 UTC (permalink / raw)
  To: Xi Ruoyao; +Cc: gcc-help

On Tue, 6 Jul 2021 at 16:39, Xi Ruoyao <xry111@mengyan1223.wang> wrote:
>
> On Sat, 2021-07-03 at 16:36 +0100, Jonny Grant wrote:
> >
> >
> > On 16/06/2021 14:36, Xi Ruoyao wrote:
> > > On Wed, 2021-06-16 at 14:01 +0100, Jonny Grant wrote:
> > >
> > > > Chris Latner also mentioned integer overflow being undefined, that
> > > > crops up too. There's no easy solution right, we need to hand write
> > > > code the checks?  It's human-error prone if we need to manually code
> > > > each check. throwing in C++, or handling in C.
> > > >
> > > > if(N >= INT_MAX)
> > > > {
> > > >     throw std::overflow_error("N >= INT_MAX would overflow in for
> > > > loop");
> > > > }
> > > >
> > > > for (i = 0; i <= N; ++i)
> > > > {
> > > > // ...
> > > >  }
> > >
> > > For debugging use -fsanitize=undefined.
> > >
> > > And this is buggy anyway, no matter if there is an UB:
> > >
> > > for (unsigned i = 0; i <= N; i++)
> > >     make_some_side_effect_without_any_undefined_behavior(i);
> > >
> > > If N may be UINT_MAX, this is not UB, but a dead loop. Programming is
> > > just human-error prone, even if you use "some programming language
> > > claimed to be able to eliminate many human errors" (I'll not say its
> > > name, to prevent a flame war).
> > >
> > Hi Xi
> >
> >
> > Checking the UINT_MAX would at least prevent the continual running of
> > any such buggy loop where it increments right? and the code within the
> > loop does not modify 'i'
> >
> > for (unsigned i = 0; (i <= N) && (i != UINT_MAX); i++)
> >     make_some_side_effect_without_any_undefined_behavior(i);
>
> Even if i is signed, it will still "work" if you modify the &&
> expression a little:
>
> for (int i = 0; i != UINT_MAX && i < N; i++)
>      make_some_side_effect_without_any_undefined_behavior(i);
>
> The problem is, now the behavior when N == UINT_MAX is same with when N
> == (UINT_MAX - 1).  This can really puzzle someone who will call your
> function.
>
> If I'm designing this function I'd make it to interpret N as [0, N),
> instead of [0, N]:
>
> // Do something for each integer in [0, N).
> void do_something(int N)
> {
>     for (int i = 0; i < N; i++)
>         do_something_once(i);
> }

That's good, specify the limit.
>
> > Is there any way to have a way to make loop variables like this 'i'
> > const within the body of the loop, to avoid accidental changing of 'i'
> > by the body of the loop
>
> I don't think there is one in C.  Perhaps, maybe use some "nasty"
> macros.

Probably I could use this pattern to avoid the risk of code modifying
the loop counter by accident.

for (int loop_var = 0; loop_var < N; loop_var++)
{
    const int i = loop_var;
    printf("i: %d\n", i);
}

Jonny

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2021-07-19 18:20 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-13 22:30 gcc warn when pointers not checked non-null before de-referencing Jonny Grant
2021-06-14  5:15 ` Xi Ruoyao
2021-06-16 13:01   ` Jonny Grant
2021-06-16 13:36     ` Xi Ruoyao
2021-07-03 15:36       ` Jonny Grant
2021-07-06 15:39         ` Xi Ruoyao
2021-07-19 18:20           ` Jonny Grant
2021-06-16 17:59     ` Segher Boessenkool
2021-06-17 20:44       ` Jonny Grant
2021-06-18  4:16         ` Xi Ruoyao
2021-07-03 14:14           ` Jonny Grant
2021-07-03 16:22             ` Segher Boessenkool
2021-07-06 10:33               ` Jonny Grant
2021-06-18  8:38         ` Liu Hao
2021-06-18 14:53         ` Segher Boessenkool
2021-06-14 15:19 ` Martin Sebor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).