* Volatile qualification on pointer and data @ 2011-09-20 16:08 Paulo J. Matos 2011-09-20 16:36 ` Ian Lance Taylor 0 siblings, 1 reply; 30+ messages in thread From: Paulo J. Matos @ 2011-09-20 16:08 UTC (permalink / raw) To: gcc Hi, I am noticing a very concerning change of behaviour from GCC45 to GCC46 on our applications. The following code: static const unsigned int foo = 1; unsigned int test( void ) { const volatile unsigned int *bar = &foo; return ( *bar ); } in GCC45 works as expected: $test: ld AL,#foo ;; AL is return register bra 0,X ;; end function in GCC46: $test: ld AL,0 bra 0,X This is worrying because qualifying the data as volatile should be enough to prevent these sort of optimizations. It did until GCC46. I noticed that this seems to be implementation dependent according to C99 6.7.3.6, however, this change of implementation is unexpected and I don't see a reason for it. Is there any reason for this change? The correct code is generated is both the pointer and data are qualified as volatile even it is not straightforward code since it has some moves to and from the stack pointer. This is easily reproducible in i386 so, it's definitely not backend specific. Cheers, -- PMatos ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-20 16:08 Volatile qualification on pointer and data Paulo J. Matos @ 2011-09-20 16:36 ` Ian Lance Taylor 2011-09-21 7:07 ` David Brown 2011-09-21 8:14 ` Paulo J. Matos 0 siblings, 2 replies; 30+ messages in thread From: Ian Lance Taylor @ 2011-09-20 16:36 UTC (permalink / raw) To: Paulo J. Matos; +Cc: gcc "Paulo J. Matos" <paulo@matos-sorge.com> writes: > The following code: > static const unsigned int foo = 1; > unsigned int test( void ) > { > const volatile unsigned int *bar = &foo; > return ( *bar ); > } > > in GCC45 works as expected: > $test: > ld AL,#foo ;; AL is return register > bra 0,X ;; end function > > in GCC46: > $test: > ld AL,0 > bra 0,X > > This is worrying because qualifying the data as volatile should be > enough to prevent these sort of optimizations. It did until GCC46. I agree that this looks like a bug. Please file a bug report marked as a regression. Ian ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-20 16:36 ` Ian Lance Taylor @ 2011-09-21 7:07 ` David Brown 2011-09-21 8:22 ` Paulo J. Matos 2011-09-21 8:14 ` Paulo J. Matos 1 sibling, 1 reply; 30+ messages in thread From: David Brown @ 2011-09-21 7:07 UTC (permalink / raw) To: gcc On 20/09/2011 18:35, Ian Lance Taylor wrote: > "Paulo J. Matos"<paulo@matos-sorge.com> writes: > >> The following code: >> static const unsigned int foo = 1; >> unsigned int test( void ) >> { >> const volatile unsigned int *bar =&foo; >> return ( *bar ); >> } >> >> in GCC45 works as expected: >> $test: >> ld AL,#foo ;; AL is return register >> bra 0,X ;; end function >> >> in GCC46: >> $test: >> ld AL,0 >> bra 0,X >> >> This is worrying because qualifying the data as volatile should be >> enough to prevent these sort of optimizations. It did until GCC46. > > I agree that this looks like a bug. Please file a bug report marked as > a regression. > > Ian > Are you sure about that? In the declaration of "bar", the "const" part is just a promise to the compiler that the code won't try to change the data pointed to by bar. But when "foo" is defined as "const", that tells the compiler that foo cannot change, and being "static" and non-volatile, the compiler then knows everything about foo and can eliminate it in the code. Asking to read it by a volatile read does not change the nature of "foo" - the compiler can still implement it as a compile-time constant. So the compiler does it's best to generate code for a volatile read of an immediate constant. David ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-21 7:07 ` David Brown @ 2011-09-21 8:22 ` Paulo J. Matos 2011-09-21 10:20 ` David Brown 0 siblings, 1 reply; 30+ messages in thread From: Paulo J. Matos @ 2011-09-21 8:22 UTC (permalink / raw) To: gcc On 21/09/11 08:03, David Brown wrote: > Asking to read it by a volatile read does not > change the nature of "foo" - the compiler can still implement it as a > compile-time constant. But since I am accessing the data through the pointer and the pointer qualifies the data as volatile, shouldn't the compiler avoid this kind of optimization for reads through the pointer? It still is a regression from GCC45, however it might be considered a feature instead of a bug as I already mentioned to Ian. -- PMatos ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-21 8:22 ` Paulo J. Matos @ 2011-09-21 10:20 ` David Brown 2011-09-21 13:57 ` Ian Lance Taylor 0 siblings, 1 reply; 30+ messages in thread From: David Brown @ 2011-09-21 10:20 UTC (permalink / raw) To: gcc On 21/09/2011 10:21, Paulo J. Matos wrote: > On 21/09/11 08:03, David Brown wrote: >> Asking to read it by a volatile read does not >> change the nature of "foo" - the compiler can still implement it as a >> compile-time constant. > > But since I am accessing the data through the pointer and the pointer > qualifies the data as volatile, shouldn't the compiler avoid this kind > of optimization for reads through the pointer? > My thought is that the nature of "foo" is independent of how it is accessed. On the other hand, some uses of a variable will affect its implementation - if you take the address of "foo" and pass that on to an external function or data, then the compiler would have to generate "foo" in memory (but in read-only memory, and it can still assume its value does not change). So I am not sure what the "correct" behaviour is here - I merely ask the question. Fortunately, this situation is not going to occur in real code. > It still is a regression from GCC45, however it might be considered a > feature instead of a bug as I already mentioned to Ian. > ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-21 10:20 ` David Brown @ 2011-09-21 13:57 ` Ian Lance Taylor 2011-09-21 14:25 ` David Brown 0 siblings, 1 reply; 30+ messages in thread From: Ian Lance Taylor @ 2011-09-21 13:57 UTC (permalink / raw) To: David Brown; +Cc: gcc David Brown <david@westcontrol.com> writes: > On 21/09/2011 10:21, Paulo J. Matos wrote: >> On 21/09/11 08:03, David Brown wrote: >>> Asking to read it by a volatile read does not >>> change the nature of "foo" - the compiler can still implement it as a >>> compile-time constant. >> >> But since I am accessing the data through the pointer and the pointer >> qualifies the data as volatile, shouldn't the compiler avoid this kind >> of optimization for reads through the pointer? >> > > My thought is that the nature of "foo" is independent of how it is > accessed. On the other hand, some uses of a variable will affect its > implementation - if you take the address of "foo" and pass that on to > an external function or data, then the compiler would have to generate > "foo" in memory (but in read-only memory, and it can still assume its > value does not change). So I am not sure what the "correct" behaviour > is here - I merely ask the question. > > Fortunately, this situation is not going to occur in real code. I think your description is supported by the standard. However, I also think that gcc should endeavor to fully honor the volatile qualifier in all cases, because that is least surprising to the programmer. This is not a case where we should let optimization override the programmer's desire; by using volatile, the programmer has explicitly told us that they do not want any optimization to occur. Ian ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-21 13:57 ` Ian Lance Taylor @ 2011-09-21 14:25 ` David Brown 2011-09-21 14:57 ` Paulo J. Matos 2011-09-21 18:51 ` Georg-Johann Lay 0 siblings, 2 replies; 30+ messages in thread From: David Brown @ 2011-09-21 14:25 UTC (permalink / raw) To: gcc On 21/09/2011 15:57, Ian Lance Taylor wrote: > David Brown<david@westcontrol.com> writes: > >> On 21/09/2011 10:21, Paulo J. Matos wrote: >>> On 21/09/11 08:03, David Brown wrote: >>>> Asking to read it by a volatile read does not >>>> change the nature of "foo" - the compiler can still implement it as a >>>> compile-time constant. >>> >>> But since I am accessing the data through the pointer and the pointer >>> qualifies the data as volatile, shouldn't the compiler avoid this kind >>> of optimization for reads through the pointer? >>> >> >> My thought is that the nature of "foo" is independent of how it is >> accessed. On the other hand, some uses of a variable will affect its >> implementation - if you take the address of "foo" and pass that on to >> an external function or data, then the compiler would have to generate >> "foo" in memory (but in read-only memory, and it can still assume its >> value does not change). So I am not sure what the "correct" behaviour >> is here - I merely ask the question. >> >> Fortunately, this situation is not going to occur in real code. > > I think your description is supported by the standard. However, I also > think that gcc should endeavor to fully honor the volatile qualifier in > all cases, because that is least surprising to the programmer. This is > not a case where we should let optimization override the programmer's > desire; by using volatile, the programmer has explicitly told us that > they do not want any optimization to occur. > That makes sense - the principle of least surprise. And since this situation would not occur in real code (at least, not code that is expected to do something useful other than test the compiler's code generation), there is no harm in making sub-optimal object code. Are there any warning flags for "programmer doing something technically legal but logically daft", that could be triggered by such cases? :-) ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-21 14:25 ` David Brown @ 2011-09-21 14:57 ` Paulo J. Matos 2011-09-22 8:39 ` David Brown 2011-09-22 21:15 ` Richard Guenther 2011-09-21 18:51 ` Georg-Johann Lay 1 sibling, 2 replies; 30+ messages in thread From: Paulo J. Matos @ 2011-09-21 14:57 UTC (permalink / raw) To: gcc On 21/09/11 15:21, David Brown wrote: > And since this > situation would not occur in real code (at least, not code that is > expected to do something useful other than test the compiler's code > generation), there is no harm in making sub-optimal object code. > Actually the reason why I noticed this is because one of our engineers told that GCC stopped generating instructions for certain operations when he moved from GCC45 to GCC46. This code is real code. Cheers, -- PMatos ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-21 14:57 ` Paulo J. Matos @ 2011-09-22 8:39 ` David Brown 2011-09-22 21:15 ` Richard Guenther 1 sibling, 0 replies; 30+ messages in thread From: David Brown @ 2011-09-22 8:39 UTC (permalink / raw) To: gcc On 21/09/2011 16:57, Paulo J. Matos wrote: > On 21/09/11 15:21, David Brown wrote: >> And since this >> situation would not occur in real code (at least, not code that is >> expected to do something useful other than test the compiler's code >> generation), there is no harm in making sub-optimal object code. >> > > Actually the reason why I noticed this is because one of our engineers > told that GCC stopped generating instructions for certain operations > when he moved from GCC45 to GCC46. This code is real code. > > Cheers, If you really have a "static const" object which you need to read as "volatile" for some reason, then I would seriously consider changing the code. With "static const" you are telling the compiler it knows everything about the use of that object, and its value will never change - with "volatile" you are telling it that it's value might change behind the scenes. Obviously you've only posted a code snippet and not your full code, but that sounds self-contradictory to me. Somewhere along the line you are lying to the compiler - that's never a good idea when you want correct and optimal code. David ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-21 14:57 ` Paulo J. Matos 2011-09-22 8:39 ` David Brown @ 2011-09-22 21:15 ` Richard Guenther 2011-09-23 11:33 ` Paulo J. Matos 2011-09-23 13:17 ` Paulo J. Matos 1 sibling, 2 replies; 30+ messages in thread From: Richard Guenther @ 2011-09-22 21:15 UTC (permalink / raw) To: Paulo J. Matos; +Cc: gcc On Wed, Sep 21, 2011 at 4:57 PM, Paulo J. Matos <paulo@matos-sorge.com> wrote: > On 21/09/11 15:21, David Brown wrote: >> >> And since this >> situation would not occur in real code (at least, not code that is >> expected to do something useful other than test the compiler's code >> generation), there is no harm in making sub-optimal object code. >> > > Actually the reason why I noticed this is because one of our engineers told > that GCC stopped generating instructions for certain operations when he > moved from GCC45 to GCC46. This code is real code. Btw, I think this is an old bug that has been resolved. Did you make sure to test a recent 4.6 branch snapshot or svn head? > Cheers, > -- > PMatos > > ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-22 21:15 ` Richard Guenther @ 2011-09-23 11:33 ` Paulo J. Matos 2011-09-23 11:51 ` Paulo J. Matos 2011-09-23 13:17 ` Paulo J. Matos 1 sibling, 1 reply; 30+ messages in thread From: Paulo J. Matos @ 2011-09-23 11:33 UTC (permalink / raw) To: gcc On 22/09/11 22:15, Richard Guenther wrote: > > Btw, I think this is an old bug that has been resolved. Did you make sure to > test a recent 4.6 branch snapshot or svn head? > Should have tested git head. Compiling git head now to check the current status of this issue. -- PMatos ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-23 11:33 ` Paulo J. Matos @ 2011-09-23 11:51 ` Paulo J. Matos 0 siblings, 0 replies; 30+ messages in thread From: Paulo J. Matos @ 2011-09-23 11:51 UTC (permalink / raw) To: gcc On 23/09/11 12:33, Paulo J. Matos wrote: > On 22/09/11 22:15, Richard Guenther wrote: >> >> Btw, I think this is an old bug that has been resolved. Did you make >> sure to >> test a recent 4.6 branch snapshot or svn head? >> > > Should have tested git head. Compiling git head now to check the current > status of this issue. > > Git head 36181f98f doesn't compile (x86_64, --enable-checking=all, GCC 4.5.2): gcc -c -g -fkeep-inline-functions -DIN_GCC -W -Wall -Wwrite-strings -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wmissing-format-attribute -pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings -Wold-style-definition -Wc++-compat -fno-common -DHAVE_CONFIG_H -I. -I. -I../../../repositories/gcc/gcc -I../../../repositories/gcc/gcc/. -I../../../repositories/gcc/gcc/../include -I../../../repositories/gcc/gcc/../libcpp/include -I../../../repositories/gcc/gcc/../libdecnumber -I../../../repositories/gcc/gcc/../libdecnumber/bid -I../libdecnumber ../../../repositories/gcc/gcc/fold-const.c -o fold-const.o ../../../repositories/gcc/gcc/fold-const.c: In function ‘fold_overflow_warning’: ../../../repositories/gcc/gcc/fold-const.c:326:5: warning: format not a string literal and no format arguments ../../../repositories/gcc/gcc/fold-const.c: In function ‘fold_checksum_tree’: ../../../repositories/gcc/gcc/fold-const.c:13803:3: error: invalid application of ‘sizeof’ to incomplete type ‘struct tree_type’ -- PMatos ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-22 21:15 ` Richard Guenther 2011-09-23 11:33 ` Paulo J. Matos @ 2011-09-23 13:17 ` Paulo J. Matos 1 sibling, 0 replies; 30+ messages in thread From: Paulo J. Matos @ 2011-09-23 13:17 UTC (permalink / raw) To: gcc On 22/09/11 22:15, Richard Guenther wrote: > > Btw, I think this is an old bug that has been resolved. Did you make sure to > test a recent 4.6 branch snapshot or svn head? > My hopes were high but unfortunately it is not fixed yet. git head 36181f98 still generates the same unexpected code. Cheers, -- PMatos ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-21 14:25 ` David Brown 2011-09-21 14:57 ` Paulo J. Matos @ 2011-09-21 18:51 ` Georg-Johann Lay 2011-09-22 8:53 ` David Brown 1 sibling, 1 reply; 30+ messages in thread From: Georg-Johann Lay @ 2011-09-21 18:51 UTC (permalink / raw) To: David Brown; +Cc: gcc David Brown schrieb: > On 21/09/2011 15:57, Ian Lance Taylor wrote: > >> David Brown<david@westcontrol.com> writes: >> >>> On 21/09/2011 10:21, Paulo J. Matos wrote: >>> >>>> On 21/09/11 08:03, David Brown wrote: >>>> >>>>> Asking to read it by a volatile read does not >>>>> change the nature of "foo" - the compiler can still implement it as a >>>>> compile-time constant. >>>> >>>> But since I am accessing the data through the pointer and the pointer >>>> qualifies the data as volatile, shouldn't the compiler avoid this kind >>>> of optimization for reads through the pointer? >>> >>> My thought is that the nature of "foo" is independent of how it is >>> accessed. On the other hand, some uses of a variable will affect its >>> implementation - if you take the address of "foo" and pass that on to >>> an external function or data, then the compiler would have to generate >>> "foo" in memory (but in read-only memory, and it can still assume its >>> value does not change). So I am not sure what the "correct" behaviour >>> is here - I merely ask the question. >>> >>> Fortunately, this situation is not going to occur in real code. >> >> I think your description is supported by the standard. However, I also >> think that gcc should endeavor to fully honor the volatile qualifier in >> all cases, because that is least surprising to the programmer. This is >> not a case where we should let optimization override the programmer's >> desire; by using volatile, the programmer has explicitly told us that >> they do not want any optimization to occur. ACK. > That makes sense - the principle of least surprise. And since this > situation would not occur in real code (at least, not code that is > expected to do something useful other than test the compiler's code > generation), there is no harm in making sub-optimal object code. > > Are there any warning flags for "programmer doing something technically > legal but logically daft", that could be triggered by such cases? :-) The combination of const and volatile can be reasonable in real world code. One example is a special function register (SFR) that is read-only but can be altered by hardware. Second example is a lookup table that can be changed after building the software, e.g. you have some calibration data that has to be drawn from the environment (drift of sensors, inductivity of motor windings, offset of actors, etc). In such a case you want to read the data from the lookup table in, say, .rodata. By no means you want the compiler to insert/propagate known values from the lookup table to immediate operands in instructions. That's exacly what "const volatile" does. Johann ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-21 18:51 ` Georg-Johann Lay @ 2011-09-22 8:53 ` David Brown 2011-09-24 15:10 ` John Regehr 0 siblings, 1 reply; 30+ messages in thread From: David Brown @ 2011-09-22 8:53 UTC (permalink / raw) To: gcc On 21/09/2011 20:50, Georg-Johann Lay wrote: > David Brown schrieb: >> On 21/09/2011 15:57, Ian Lance Taylor wrote: >> >>> David Brown<david@westcontrol.com> writes: >>> >>>> On 21/09/2011 10:21, Paulo J. Matos wrote: >>>> >>>>> On 21/09/11 08:03, David Brown wrote: >>>>> >>>>>> Asking to read it by a volatile read does not >>>>>> change the nature of "foo" - the compiler can still implement it as a >>>>>> compile-time constant. >>>>> >>>>> But since I am accessing the data through the pointer and the pointer >>>>> qualifies the data as volatile, shouldn't the compiler avoid this kind >>>>> of optimization for reads through the pointer? >>>> >>>> My thought is that the nature of "foo" is independent of how it is >>>> accessed. On the other hand, some uses of a variable will affect its >>>> implementation - if you take the address of "foo" and pass that on to >>>> an external function or data, then the compiler would have to generate >>>> "foo" in memory (but in read-only memory, and it can still assume its >>>> value does not change). So I am not sure what the "correct" behaviour >>>> is here - I merely ask the question. >>>> >>>> Fortunately, this situation is not going to occur in real code. >>> >>> I think your description is supported by the standard. However, I also >>> think that gcc should endeavor to fully honor the volatile qualifier in >>> all cases, because that is least surprising to the programmer. This is >>> not a case where we should let optimization override the programmer's >>> desire; by using volatile, the programmer has explicitly told us that >>> they do not want any optimization to occur. > > ACK. > >> That makes sense - the principle of least surprise. And since this >> situation would not occur in real code (at least, not code that is >> expected to do something useful other than test the compiler's code >> generation), there is no harm in making sub-optimal object code. >> >> Are there any warning flags for "programmer doing something >> technically legal but logically daft", that could be triggered by such >> cases? :-) > > The combination of const and volatile can be reasonable in real world code. > > One example is a special function register (SFR) that is read-only but > can be altered by hardware. > That is /very/ different - you are talking about an "extern volatile const uint8_t readOnlySFR" declaration, or something effectively like: #define readOnlySFR (*(volatile const uint8_t *) 0x1234) Either way, what you are telling the compiler is that this item is "volatile", and may change it's value unbeknownst to the compiler, and that is "const", meaning that /your/ code may not change its value. That's fine, and consistent. It might sound strange at first - many people think "const" means the data is constant and cannot change, when in fact C has its one peculiar meaning for "const". What can't make sense is a /static/ "volatile const" which is /defined/ locally, rather than just declared. > Second example is a lookup table that can be changed after building the > software, e.g. you have some calibration data that has to be drawn from > the environment (drift of sensors, inductivity of motor windings, offset > of actors, etc). In such a case you want to read the data from the > lookup table in, say, .rodata. By no means you want the compiler to > insert/propagate known values from the lookup table to immediate > operands in instructions. That's exacly what "const volatile" does. > Again, you are talking about a "volatile const" declaration of data that is defined externally, and that's okay. Also note that in this case the local static const data is not volatile - it is only accessed as a volatile through a pointer cast. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-22 8:53 ` David Brown @ 2011-09-24 15:10 ` John Regehr 2011-09-24 15:49 ` David Brown 0 siblings, 1 reply; 30+ messages in thread From: John Regehr @ 2011-09-24 15:10 UTC (permalink / raw) To: David Brown; +Cc: gcc > What can't make sense is a /static/ "volatile const" which is /defined/ > locally, rather than just declared. The code in question sounds well-defined (but probably poor style) to me. It is never OK to access a qualified object through an unqualified pointer, but my understanding is that accessing an unqualified object through a qualified pointer is well-defined and that the usual qualifier rules apply to that access. David, is your "can't make sense" backed up by a standard? There is no "lying to the compiler", there is only conforming and non-conforming code. John ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-24 15:10 ` John Regehr @ 2011-09-24 15:49 ` David Brown 2011-09-24 16:26 ` David Brown 2011-09-24 19:38 ` John Regehr 0 siblings, 2 replies; 30+ messages in thread From: David Brown @ 2011-09-24 15:49 UTC (permalink / raw) To: John Regehr; +Cc: gcc On 24/09/2011 17:09, John Regehr wrote: >> What can't make sense is a /static/ "volatile const" which is >> /defined/ locally, rather than just declared. > > The code in question sounds well-defined (but probably poor style) to me. > > It is never OK to access a qualified object through an unqualified > pointer, but my understanding is that accessing an unqualified object > through a qualified pointer is well-defined and that the usual qualifier > rules apply to that access. > That is correct, and it is best to view the qualifiers as qualifying the access to the object, rather than the object itself. Qualifying the object just states the minimum qualifiers needed to legally access it. > David, is your "can't make sense" backed up by a standard? There is no > "lying to the compiler", there is only conforming and non-conforming code. > I don't think the standard has any restrictions on the combinations of qualifiers you can have on an object - thus it is legal C to have a "static volatile const" object, or to access a "static const" through a "volatile" access. But being legal C does not imply that it makes logical sense! Is it "lying to the compiler"? Perhaps not, but it is certainly saying two different things at the same time - they cannot both make sense, and I think the compiler is free to implement whichever of the conflicting ideas it wants. However, I am far from sure here - I am raising the question, not answering it. And while I think the compiler should be allowed to generate the optimised code of 4.6 (i.e., the change is not a bug IMHO), I fully understand the idea of generating the older, slower, but definitely correct code of 4.5. I am still trying to imagine a real-world use-case for declaring an object "static const" and later accessing it as "volatile". mvh., David ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-24 15:49 ` David Brown @ 2011-09-24 16:26 ` David Brown 2011-09-24 19:38 ` John Regehr 1 sibling, 0 replies; 30+ messages in thread From: David Brown @ 2011-09-24 16:26 UTC (permalink / raw) To: gcc; +Cc: gcc On 24/09/2011 17:09, John Regehr wrote: >> What can't make sense is a /static/ "volatile const" which is >> /defined/ locally, rather than just declared. > > The code in question sounds well-defined (but probably poor style) to me. > > It is never OK to access a qualified object through an unqualified > pointer, but my understanding is that accessing an unqualified object > through a qualified pointer is well-defined and that the usual qualifier > rules apply to that access. > That is correct, and it is best to view the qualifiers as qualifying the access to the object, rather than the object itself. Qualifying the object just states the minimum qualifiers needed to legally access it. > David, is your "can't make sense" backed up by a standard? There is no > "lying to the compiler", there is only conforming and non-conforming code. > I don't think the standard has any restrictions on the combinations of qualifiers you can have on an object - thus it is legal C to have a "static volatile const" object, or to access a "static const" through a "volatile" access. But being legal C does not imply that it makes logical sense! Is it "lying to the compiler"? Perhaps not, but it is certainly saying two different things at the same time - they cannot both make sense, and I think the compiler is free to implement whichever of the conflicting ideas it wants. However, I am far from sure here - I am raising the question, not answering it. And while I think the compiler should be allowed to generate the optimised code of 4.6 (i.e., the change is not a bug IMHO), I fully understand the idea of generating the older, slower, but definitely correct code of 4.5. I am still trying to imagine a real-world use-case for declaring an object "static const" and later accessing it as "volatile". mvh., David ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-24 15:49 ` David Brown 2011-09-24 16:26 ` David Brown @ 2011-09-24 19:38 ` John Regehr 2011-09-25 13:03 ` David Brown 1 sibling, 1 reply; 30+ messages in thread From: John Regehr @ 2011-09-24 19:38 UTC (permalink / raw) To: David Brown; +Cc: gcc > it. And while I think the compiler should be allowed to generate the > optimised code of 4.6 (i.e., the change is not a bug IMHO), I fully > understand the idea of generating the older, slower, but definitely correct > code of 4.5. My understanding is that the standard mandates the old behavior, so 4.6 is in error. > I am still trying to imagine a real-world use-case for declaring an object > "static const" and later accessing it as "volatile". Yeah, it would seem far clearer to declare it as static const volatile in the first place. I've done a bunch of automated testing of GCC's implementation of volatile. None of that testing would have exposed this bug because we only count acceses to objects declared as volatile. I've come to the conclusion that "volatile" is a language design error. It complicates the compiler implementation and has confusing, underspecified semantics. If you want to force a load or store, an explicit function call is a clearer way to do it. John ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-24 19:38 ` John Regehr @ 2011-09-25 13:03 ` David Brown 2011-09-25 15:15 ` Andreas Schwab 2011-09-25 16:06 ` Dave Korn 0 siblings, 2 replies; 30+ messages in thread From: David Brown @ 2011-09-25 13:03 UTC (permalink / raw) To: gcc On 24/09/2011 18:25, John Regehr wrote: >> it. And while I think the compiler should be allowed to generate the >> optimised code of 4.6 (i.e., the change is not a bug IMHO), I fully >> understand the idea of generating the older, slower, but definitely >> correct code of 4.5. > > My understanding is that the standard mandates the old behavior, so 4.6 > is in error. > >> I am still trying to imagine a real-world use-case for declaring an >> object "static const" and later accessing it as "volatile". > > Yeah, it would seem far clearer to declare it as static const volatile > in the first place. > I still can't think why one would ever want such a thing. There is a big difference between defining an object as "const", and merely declaring it as const or accessing it as const. When you access it as const, you are saying "/I/ won't change the object with this access". When you declare an object as const (such as an extern object), you are saying "/I/ won't change this object". When you /define/ an object as const, as you do with a "static const", you are saying "this object is constant. It will never change value - you (the toolchain) can safely place it in read-only memory that cannot ever change value". And then you make it volatile, telling the compiler "this object might change unexpectedly, or use values written to it unexpectedly". If someone could explain to me how this could have real-world usage, I think it would be easier for me (and others) to be sure of what it really means. > I've done a bunch of automated testing of GCC's implementation of > volatile. None of that testing would have exposed this bug because we > only count acceses to objects declared as volatile. > > I've come to the conclusion that "volatile" is a language design error. > It complicates the compiler implementation and has confusing, > underspecified semantics. If you want to force a load or store, an > explicit function call is a clearer way to do it. > I agree on that, as I think do many - "volatile" is not defined clearly enough. It is also not flexible enough for optimal code generation in many cases when it is used regularly, such as for embedded programming. There it is not uncommon to want something that has volatile write accesses, but does not need volatile read accesses. It gets seriously messy when you combine "volatile" with bitfields - the standards are (AFAIK) unclear, and implementations of volatile bitfields vary wildly. And since "volatile" does not have any interaction with things like cpu instruction re-ordering, speculative accesses, write buffering and combining, caches, etc., or with any operating system specific interactions, it often doesn't do what the user thinks it will do. However, it is currently the only tool we have in C. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-25 13:03 ` David Brown @ 2011-09-25 15:15 ` Andreas Schwab 2011-09-25 16:33 ` David Brown 2011-09-25 16:06 ` Dave Korn 1 sibling, 1 reply; 30+ messages in thread From: Andreas Schwab @ 2011-09-25 15:15 UTC (permalink / raw) To: David Brown; +Cc: gcc David Brown <david@westcontrol.com> writes: > There is a big difference between defining an object as "const", and > merely declaring it as const or accessing it as const. When you access it > as const, you are saying "/I/ won't change the object with this access". > When you declare an object as const (such as an extern object), you are > saying "/I/ won't change this object". When you /define/ an object as > const, as you do with a "static const", you are saying "this object is > constant. It will never change value - you (the toolchain) can safely > place it in read-only memory that cannot ever change value". You are interpreting too much into const here. The C standard says in footnote 112: "The implementation may place a const object that is not volatile in a read-only region of storage." Note the use of "not volatile". But in any case this is not part of the C standard: it's only a footnote. > And then you make it volatile, telling the compiler "this object might > change unexpectedly, or use values written to it unexpectedly". > > If someone could explain to me how this could have real-world usage, I > think it would be easier for me (and others) to be sure of what it really > means. It's an object that is never written to, but may change unexpectedly. Andreas. -- Andreas Schwab, schwab@linux-m68k.org GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different." ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-25 15:15 ` Andreas Schwab @ 2011-09-25 16:33 ` David Brown 2011-09-25 16:36 ` David Brown 0 siblings, 1 reply; 30+ messages in thread From: David Brown @ 2011-09-25 16:33 UTC (permalink / raw) To: Andreas Schwab; +Cc: David Brown, gcc On 25/09/11 16:16, Andreas Schwab wrote: > David Brown<david@westcontrol.com> writes: > >> There is a big difference between defining an object as "const", and >> merely declaring it as const or accessing it as const. When you access it >> as const, you are saying "/I/ won't change the object with this access". >> When you declare an object as const (such as an extern object), you are >> saying "/I/ won't change this object". When you /define/ an object as >> const, as you do with a "static const", you are saying "this object is >> constant. It will never change value - you (the toolchain) can safely >> place it in read-only memory that cannot ever change value". > > You are interpreting too much into const here. The C standard says in > footnote 112: "The implementation may place a const object that is not > volatile in a read-only region of storage." Note the use of "not > volatile". But in any case this is not part of the C standard: it's > only a footnote. > I stand corrected on that point - thanks. >> And then you make it volatile, telling the compiler "this object might >> change unexpectedly, or use values written to it unexpectedly". >> >> If someone could explain to me how this could have real-world usage, I >> think it would be easier for me (and others) to be sure of what it really >> means. > > It's an object that is never written to, but may change unexpectedly. > Again, I can see that "volatile const" is useful for declaring external objects (or accesses to objects), but not when the address of the object is allocated by the toolchain (as is the case here with a "static const volatile". The only scenario I have heard where this might be useful is for debugging - making what is normally a "static const" volatile so that it's value can be changed with a debugger. Personally, I think that in such cases you would be better removing the "const" when you add the "volatile". ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-25 16:33 ` David Brown @ 2011-09-25 16:36 ` David Brown 0 siblings, 0 replies; 30+ messages in thread From: David Brown @ 2011-09-25 16:36 UTC (permalink / raw) To: gcc; +Cc: David Brown, gcc On 25/09/11 16:16, Andreas Schwab wrote: > David Brown<david@westcontrol.com> writes: > >> There is a big difference between defining an object as "const", and >> merely declaring it as const or accessing it as const. When you access it >> as const, you are saying "/I/ won't change the object with this access". >> When you declare an object as const (such as an extern object), you are >> saying "/I/ won't change this object". When you /define/ an object as >> const, as you do with a "static const", you are saying "this object is >> constant. It will never change value - you (the toolchain) can safely >> place it in read-only memory that cannot ever change value". > > You are interpreting too much into const here. The C standard says in > footnote 112: "The implementation may place a const object that is not > volatile in a read-only region of storage." Note the use of "not > volatile". But in any case this is not part of the C standard: it's > only a footnote. > I stand corrected on that point - thanks. >> And then you make it volatile, telling the compiler "this object might >> change unexpectedly, or use values written to it unexpectedly". >> >> If someone could explain to me how this could have real-world usage, I >> think it would be easier for me (and others) to be sure of what it really >> means. > > It's an object that is never written to, but may change unexpectedly. > Again, I can see that "volatile const" is useful for declaring external objects (or accesses to objects), but not when the address of the object is allocated by the toolchain (as is the case here with a "static const volatile". The only scenario I have heard where this might be useful is for debugging - making what is normally a "static const" volatile so that it's value can be changed with a debugger. Personally, I think that in such cases you would be better removing the "const" when you add the "volatile". ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-25 13:03 ` David Brown 2011-09-25 15:15 ` Andreas Schwab @ 2011-09-25 16:06 ` Dave Korn 2011-09-25 22:05 ` David Brown 1 sibling, 1 reply; 30+ messages in thread From: Dave Korn @ 2011-09-25 16:06 UTC (permalink / raw) To: David Brown; +Cc: gcc On 25/09/2011 13:56, David Brown wrote: > There is a big difference between defining an object as "const", and > merely declaring it as const or accessing it as const. When you access > it as const, you are saying "/I/ won't change the object with this > access". When you declare an object as const (such as an extern > object), you are saying "/I/ won't change this object". When you > /define/ an object as const, as you do with a "static const", you are > saying "this object is constant. It will never change value - you (the > toolchain) can safely place it in read-only memory that cannot ever > change value". > > And then you make it volatile, telling the compiler "this object might > change unexpectedly, or use values written to it unexpectedly". > > If someone could explain to me how this could have real-world usage, I > think it would be easier for me (and others) to be sure of what it > really means. Just because it's static doesn't mean the address can't escape: /* May read or write to dest, according to direction flag. */ extern void start_dma_xfer (void *dest, unsigned int size, bool direction, uint64_t bus_addr); /* We don't want to change this ourselves, and nor do we want the symbol to be externally visible. */ static const volatile char *dma_buffer[BUFFERSIZE]; [ ... later, in a function ... ] start_dma_transfer (&dma_buffer[0], size, DIRECTION_DMA_TO_MEMORY, devaddr); A bit contrived perhaps, but start_dma_transfer (or some similar function) might be part of the OS or written in assembly and so necessarily C-type-safe. cheers, DaveK ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-25 16:06 ` Dave Korn @ 2011-09-25 22:05 ` David Brown 2011-09-25 22:05 ` David Brown 2011-09-26 7:14 ` Miles Bader 0 siblings, 2 replies; 30+ messages in thread From: David Brown @ 2011-09-25 22:05 UTC (permalink / raw) To: gcc; +Cc: David Brown, gcc On 25/09/11 17:15, Dave Korn wrote: > On 25/09/2011 13:56, David Brown wrote: > >> There is a big difference between defining an object as "const", and >> merely declaring it as const or accessing it as const. When you access >> it as const, you are saying "/I/ won't change the object with this >> access". When you declare an object as const (such as an extern >> object), you are saying "/I/ won't change this object". When you >> /define/ an object as const, as you do with a "static const", you are >> saying "this object is constant. It will never change value - you (the >> toolchain) can safely place it in read-only memory that cannot ever >> change value". >> >> And then you make it volatile, telling the compiler "this object might >> change unexpectedly, or use values written to it unexpectedly". >> >> If someone could explain to me how this could have real-world usage, I >> think it would be easier for me (and others) to be sure of what it >> really means. > > Just because it's static doesn't mean the address can't escape: > > /* May read or write to dest, according to direction flag. */ > extern void start_dma_xfer (void *dest, unsigned int size, bool direction, > uint64_t bus_addr); > > /* We don't want to change this ourselves, and nor do we want the symbol > to be externally visible. */ > static const volatile char *dma_buffer[BUFFERSIZE]; > > [ ... later, in a function ... ] > > start_dma_transfer (&dma_buffer[0], size, DIRECTION_DMA_TO_MEMORY, devaddr); > > > A bit contrived perhaps, but start_dma_transfer (or some similar function) > might be part of the OS or written in assembly and so necessarily C-type-safe. > > cheers, > DaveK > > I can see that as a possibility, though to me it reads as bad style. I'm aware that taking the address of a static object can let it "escape", and mentioned that possibility in other posts - it will certainly force the object to be created in memory. However, I just don't see why a buffer like this would be defined "const" - it's not constant, so what are you trying to achieve by saying "const"? To answer that, you have to first say /why/ anyone would use the "const" qualifier in the first place. There are five reasons I can think of. First, you have compatibility with other code and types. Then you have error-checking - if you know you will not change an object, you make it "const" to let the compiler check that you haven't changed it by mistake. Then there is optimisation - by telling the compiler that the object won't change value, you let it generate better code (such as using "static const" instead of old-fashioned "#define" or enum constants). Next, you define objects as "const" to let the toolchain place the object in read-only memory - this is very important for small embedded systems running from flash memory. Finally, you use "const" as documentation - you use it when it makes it clearer what the code is doing, why it is doing it, or how it is doing it. So what advantages would there be in declaring a volatile buffer like this to be "const"? At best, you are helping the compiler check that you don't accidentally write to it in your own code. It is dangerous regarding optimisation - you definitely don't want the compiler to optimise the buffer, yet this whole discussion started because some compilers /do/ optimise such code (rightly or wrongly). You don't want the toolchain to put it read-only memory (as noted by another poster, doing so would be against the standards - but toolchain writers are not infallible, and weird corner-cases like this are where mistakes are less likely to be spotted and fixed). So does the "const" make the program clearer to the code writer, and other readers? I would say it has the opposite effect, and leaves a reader wondering what it is supposed to mean - the buffer is clearly not meant to be constant, so why is it declared "const"? When I write code, I almost always define objects as "const" when possible. But in this case there would be no doubt in my mind - that buffer is /not/ constant, and should not be defined as "const" even if it happened to compile and run correctly. I am aware that this is a stylistic choice. But I don't see it as good programming to push boundaries with "risky" code that might or might not work depending on how the compiler writers interpreted the standards - especially when it makes the code less clear to human readers. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-25 22:05 ` David Brown @ 2011-09-25 22:05 ` David Brown 2011-09-26 7:14 ` Miles Bader 1 sibling, 0 replies; 30+ messages in thread From: David Brown @ 2011-09-25 22:05 UTC (permalink / raw) To: Dave Korn; +Cc: David Brown, gcc On 25/09/11 17:15, Dave Korn wrote: > On 25/09/2011 13:56, David Brown wrote: > >> There is a big difference between defining an object as "const", and >> merely declaring it as const or accessing it as const. When you access >> it as const, you are saying "/I/ won't change the object with this >> access". When you declare an object as const (such as an extern >> object), you are saying "/I/ won't change this object". When you >> /define/ an object as const, as you do with a "static const", you are >> saying "this object is constant. It will never change value - you (the >> toolchain) can safely place it in read-only memory that cannot ever >> change value". >> >> And then you make it volatile, telling the compiler "this object might >> change unexpectedly, or use values written to it unexpectedly". >> >> If someone could explain to me how this could have real-world usage, I >> think it would be easier for me (and others) to be sure of what it >> really means. > > Just because it's static doesn't mean the address can't escape: > > /* May read or write to dest, according to direction flag. */ > extern void start_dma_xfer (void *dest, unsigned int size, bool direction, > uint64_t bus_addr); > > /* We don't want to change this ourselves, and nor do we want the symbol > to be externally visible. */ > static const volatile char *dma_buffer[BUFFERSIZE]; > > [ ... later, in a function ... ] > > start_dma_transfer (&dma_buffer[0], size, DIRECTION_DMA_TO_MEMORY, devaddr); > > > A bit contrived perhaps, but start_dma_transfer (or some similar function) > might be part of the OS or written in assembly and so necessarily C-type-safe. > > cheers, > DaveK > > I can see that as a possibility, though to me it reads as bad style. I'm aware that taking the address of a static object can let it "escape", and mentioned that possibility in other posts - it will certainly force the object to be created in memory. However, I just don't see why a buffer like this would be defined "const" - it's not constant, so what are you trying to achieve by saying "const"? To answer that, you have to first say /why/ anyone would use the "const" qualifier in the first place. There are five reasons I can think of. First, you have compatibility with other code and types. Then you have error-checking - if you know you will not change an object, you make it "const" to let the compiler check that you haven't changed it by mistake. Then there is optimisation - by telling the compiler that the object won't change value, you let it generate better code (such as using "static const" instead of old-fashioned "#define" or enum constants). Next, you define objects as "const" to let the toolchain place the object in read-only memory - this is very important for small embedded systems running from flash memory. Finally, you use "const" as documentation - you use it when it makes it clearer what the code is doing, why it is doing it, or how it is doing it. So what advantages would there be in declaring a volatile buffer like this to be "const"? At best, you are helping the compiler check that you don't accidentally write to it in your own code. It is dangerous regarding optimisation - you definitely don't want the compiler to optimise the buffer, yet this whole discussion started because some compilers /do/ optimise such code (rightly or wrongly). You don't want the toolchain to put it read-only memory (as noted by another poster, doing so would be against the standards - but toolchain writers are not infallible, and weird corner-cases like this are where mistakes are less likely to be spotted and fixed). So does the "const" make the program clearer to the code writer, and other readers? I would say it has the opposite effect, and leaves a reader wondering what it is supposed to mean - the buffer is clearly not meant to be constant, so why is it declared "const"? When I write code, I almost always define objects as "const" when possible. But in this case there would be no doubt in my mind - that buffer is /not/ constant, and should not be defined as "const" even if it happened to compile and run correctly. I am aware that this is a stylistic choice. But I don't see it as good programming to push boundaries with "risky" code that might or might not work depending on how the compiler writers interpreted the standards - especially when it makes the code less clear to human readers. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-25 22:05 ` David Brown 2011-09-25 22:05 ` David Brown @ 2011-09-26 7:14 ` Miles Bader 2011-09-26 8:53 ` David Brown 1 sibling, 1 reply; 30+ messages in thread From: Miles Bader @ 2011-09-26 7:14 UTC (permalink / raw) To: gcc David Brown <david.brown@hesbynett.no> writes: > So what advantages would there be in declaring a volatile buffer like > this to be "const"? At best, you are helping the compiler check that > you don't accidentally write to it in your own code. That's actually pretty handy tho... -Miles -- Everywhere is walking distance if you have the time. -- Steven Wright ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-26 7:14 ` Miles Bader @ 2011-09-26 8:53 ` David Brown 2011-09-26 8:58 ` David Brown 0 siblings, 1 reply; 30+ messages in thread From: David Brown @ 2011-09-26 8:53 UTC (permalink / raw) To: Miles Bader; +Cc: gcc On 26/09/2011 02:37, Miles Bader wrote: > David Brown<david.brown@hesbynett.no> writes: >> So what advantages would there be in declaring a volatile buffer like >> this to be "const"? At best, you are helping the compiler check that >> you don't accidentally write to it in your own code. > > That's actually pretty handy tho... > Oh, I'm all in favour of static error checking - use const pointers where possible, and there are not many of gcc's warning flags that I don't use. But I'd weigh code clarity above error checking in this case, especially since it is very unlikely that you'd write code that accidentally wrote to the buffer. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-26 8:53 ` David Brown @ 2011-09-26 8:58 ` David Brown 0 siblings, 0 replies; 30+ messages in thread From: David Brown @ 2011-09-26 8:58 UTC (permalink / raw) To: gcc; +Cc: gcc On 26/09/2011 02:37, Miles Bader wrote: > David Brown<david.brown@hesbynett.no> writes: >> So what advantages would there be in declaring a volatile buffer like >> this to be "const"? At best, you are helping the compiler check that >> you don't accidentally write to it in your own code. > > That's actually pretty handy tho... > Oh, I'm all in favour of static error checking - use const pointers where possible, and there are not many of gcc's warning flags that I don't use. But I'd weigh code clarity above error checking in this case, especially since it is very unlikely that you'd write code that accidentally wrote to the buffer. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Volatile qualification on pointer and data 2011-09-20 16:36 ` Ian Lance Taylor 2011-09-21 7:07 ` David Brown @ 2011-09-21 8:14 ` Paulo J. Matos 1 sibling, 0 replies; 30+ messages in thread From: Paulo J. Matos @ 2011-09-21 8:14 UTC (permalink / raw) To: gcc On 20/09/11 17:35, Ian Lance Taylor wrote: > I agree that this looks like a bug. Please file a bug report marked as > a regression. > > Ian > Thanks. Reported as 50472 even though I am just reading Davids post and he is convincing me that this might not be a bug after all, however, it is still behaving differently than GCC45 but you might then consider it a feature instead of a bug. -- PMatos ^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2011-09-26 7:41 UTC | newest] Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2011-09-20 16:08 Volatile qualification on pointer and data Paulo J. Matos 2011-09-20 16:36 ` Ian Lance Taylor 2011-09-21 7:07 ` David Brown 2011-09-21 8:22 ` Paulo J. Matos 2011-09-21 10:20 ` David Brown 2011-09-21 13:57 ` Ian Lance Taylor 2011-09-21 14:25 ` David Brown 2011-09-21 14:57 ` Paulo J. Matos 2011-09-22 8:39 ` David Brown 2011-09-22 21:15 ` Richard Guenther 2011-09-23 11:33 ` Paulo J. Matos 2011-09-23 11:51 ` Paulo J. Matos 2011-09-23 13:17 ` Paulo J. Matos 2011-09-21 18:51 ` Georg-Johann Lay 2011-09-22 8:53 ` David Brown 2011-09-24 15:10 ` John Regehr 2011-09-24 15:49 ` David Brown 2011-09-24 16:26 ` David Brown 2011-09-24 19:38 ` John Regehr 2011-09-25 13:03 ` David Brown 2011-09-25 15:15 ` Andreas Schwab 2011-09-25 16:33 ` David Brown 2011-09-25 16:36 ` David Brown 2011-09-25 16:06 ` Dave Korn 2011-09-25 22:05 ` David Brown 2011-09-25 22:05 ` David Brown 2011-09-26 7:14 ` Miles Bader 2011-09-26 8:53 ` David Brown 2011-09-26 8:58 ` David Brown 2011-09-21 8:14 ` Paulo J. Matos
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).