Path: csiph.com!3.us.feeder.erje.net!feeder.erje.net!news.linkpendium.com!news.linkpendium.com!news.snarked.org!border2.nntp.dca1.giganews.com!nntp.giganews.com!news.iecc.com!.POSTED.news.iecc.com!nerds-end From: David Brown Newsgroups: comp.compilers Subject: Re: Bounds checking, Optimization techniques and undefined behavior Date: Tue, 7 May 2019 11:04:04 +0200 Organization: A noiseless patient Spider Lines: 98 Sender: news@iecc.com Approved: comp.compilers@iecc.com Message-ID: <19-05-045@comp.compilers> References: <19-04-021@comp.compilers> <19-04-023@comp.compilers> <19-04-037@comp.compilers> <19-04-039@comp.compilers> <19-04-042@comp.compilers> <19-04-044@comp.compilers> <19-04-047@comp.compilers> <19-05-004@comp.compilers> <19-05-006@comp.compilers> <19-05-016@comp.compilers> <19-05-020@comp.compilers> <19-05-024@comp.compilers> <19-05-025@comp.compilers> <19-05-028@comp.compilers> <19-05-029@comp.compilers> <19-05-034@comp.compilers> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Injection-Info: gal.iecc.com; posting-host="news.iecc.com:2001:470:1f07:1126:0:676f:7373:6970"; logging-data="97371"; mail-complaints-to="abuse@iecc.com" Keywords: C, errors, debug, comment Posted-Date: 07 May 2019 17:28:33 EDT X-submission-address: compilers@iecc.com X-moderator-address: compilers-request@iecc.com X-FAQ-and-archives: http://compilers.iecc.com Content-Language: en-GB Xref: csiph.com comp.compilers:2280 On 06/05/2019 10:15, Hans-Peter Diettrich wrote: > Am 05.05.2019 um 20:44 schrieb Hans-Peter Diettrich: >> Am 05.05.2019 um 12:14 schrieb Bart: >> >>> But how do they get there? Take this: >>> >>>     int A[10], *p; >>>     p = &A[3]; >>> >>> You intend p to refer to the 4-element slice A[3..6], but how does the >>> language know that? How can it stop code from writing to p[5]? >> >> Not pointers are bad, but pointer arithmetic is. It should be allowed >> only with objects of known bounds. >> >> DoDi >> [In this case the bounds look known to me. -John] > > The bounds are known for the array, so that the pointer is guaranteed > valid by compile time check. But p[x] or p+x can not be guaranteed valid > without considerable runtime and bounds storage overhead. Also simple > p++ operation or the like requires an update of the bounds information. That depends on x, and what other operations are done on the pointers. For example, given this: for (int x = 0; x < 7; x++) { p[x] = 10; } the compiler can see that the access is valid. Change the limit to 8, and the compiler can tell that it is invalid. (gcc can spot this one.) But of course if x comes from elsewhere, it is going to take very advanced analysis to figure out anything about its validity. > That's what I consider pointer arithmetic, not above &A[3]. > &A[3] is pointer arithmetic too. A more useful distinction might be for pointer calculations where the compiler knows the addresses or ranges at compile time, however they might be expressed. > I learned to love the Pascal indexing instead of pointers, because a > loop like >   for i := 1 to 10 do sum := sum + A[i]; > can be optimized safely by the Pascal/Delphi compiler into pointer and > auto increment, so that no speed penalty exists vs. explicit pointer > usage. But in a C for loop the index variable can be changed in code, so > that even above code would execute slower with bounds checks. > It will not be slower in C - because the compiler knows that "i" is never changed in the loop. (I'd like some way to have that enforced in C, but I don't know of any good method.) Just for a laugh, try this code: #include int main(void) { int i; int j; int *pi = &i; int *pj = &j; int sum = 0; printf("pi = %p, pj[-1] = %p\n", (void*) pi, (void*) &pj[-1]); for (i = 0; i < 11; i++) { if (i == 3) { pj[-1] = 5; } sum += i; } printf("Sum is %i\n", sum); } Depending on the compiler, you might need to swap "int i;" and "int j;". The first printf shows that "pi" and "pj[-1]" point to the same address, that of "i". With no optimisation and a literal translation of the code, the result will be 48. With optimisation, the compiler knows that access through "pj" cannot possibly affect "i" without invoking undefined behaviour - so it can simplify the loop to "sum = 55;" and shows that result. [For the loop with the unchangable index, you can declare the index const and cast the places you change it, but ugh. const int i; for(*(int*)&i = 0; i < 10; (*(int*)&i)++) { a[i] = i; i++; /* will be diagnosed as an error */ } -John]