- Is this undefined behavior? - 8 Updates
- DCAS-atomic - 6 Updates
- [Jesus Loves You] Society's end - 1 Update
- Fake switch or fake loop only to break - 2 Updates
- std::map rebalancing - 2 Updates
- Augments and variable length data forms - 6 Updates
Sam <sam@email-scan.com>: Jun 15 07:07AM -0400 Chris M. Thomasson writes: > header* const h = reinterpret_cast<header*>(std::malloc(sizeof(*h) + > size)); > How infested with UB is this? Any bugs? Eh, there's probably some teeny amount of UB here, but I would not worry about it too much, the compilers' behavior should not be too surprising here. And gcc even gives its formal blessing to the following: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html |
Manfred <noname@add.invalid>: Jun 17 05:41PM +0200 >>> right? In pure C... >> In C yes, in C++ a type cast is required. A static_cast would suffice. > A static_cast is just a more verbose C cast and the two are interchangable. No, they are not. https://en.cppreference.com/w/cpp/language/expressions#Conversions |
Bo Persson <bo@bo-persson.se>: Jun 16 05:53PM +0200 On 2020-06-16 at 17:29, Paavo Helde wrote: > trigger implicit object creation." > I gather all this fuss is about allowing type-based alias analysis. > Reinterpret_cast works directly against this idea. Yes, the idea was to not have to decorate every other pointer with a 'restrict' keyword (like some other language does). Bo Persson |
boltar@nowhere.co.uk: Jun 17 03:20PM On Wed, 17 Jun 2020 15:27:26 +0200 >> Why would one need to cast the return value? void* can do it as is, >> right? In pure C... >In C yes, in C++ a type cast is required. A static_cast would suffice. A static_cast is just a more verbose C cast and the two are interchangable. |
Juha Nieminen <nospam@thanks.invalid>: Jun 17 06:36AM > Technically, constructing the 'header' object in the malloc'ed buffer > is also reputed to be undefined behaviour if you do it otherwise that > through placement new, even though 'header' is a trivial type. Thinking about it, it might actually have merit to worry about such things being UB, no matter how "technically" and how obscure the rule may be. One could easily just think like "who cares if it's "technically" UB? There's no practical implementation where it would cause anything else than intended behavior." The problem is, UB allows the compiler to do whatever it wants. Including not doing what the programmer "intended" for it to do. Tehcnically speaking if the compiler detects UB, it's allowed to think "this is UB, I don't need to do anything here, I'll just skip the whole thing and optimize it all away". Suddenly you might find yourself with an incredibly obscure "compiler bug" where the compiler isn't generating the code you wrote... when in fact it's not a compiler bug at all. I remember a particularly nasty bug many years ago in the Linux kernel that was caused precisely by this kind of thing. That part of the kernel code was technically UB... and the compiler did whatever it wanted and not the thing that the code was "intending" it to do (and, IIRC, it optimized that part away, which caused the intended thing to not happen. I don't remember now the exact reason, but might have had something to do with deliberately dererencing a null pointer, which is UB, and which the compiler was "optimizing" away because the standard allowed it to.) |
Paavo Helde <eesnimi@osa.pri.ee>: Jun 16 12:15PM +0300 16.06.2020 02:26 Chris Vine kirjutas: > new char[] expression is technically undefined behaviour. See > https://stackoverflow.com/questions/60465235/does-stdunitialized-copy-have-undefined-behavior > However practical implementations will allow it for reasonable uses. Huh, good to know 99% of C programs formally contain UB when compiled as C++. > for this purpose). But even so dereferencing the result of 'this + 1' > is I think technically also undefined behaviour if the buffer at that > address has not been constructed there by placement new[], Just to clarify: are you speaking about dereferencing 'this+1' as another header object? Or about converting 'this+1' to a char* pointer and dereferencing this? For the latter, at least the dereferencing should be kosher if the initial buffer was allocated by new char[]. |
Manfred <noname@add.invalid>: Jun 17 07:13PM +0200 >> https://en.cppreference.com/w/cpp/language/expressions#Conversions > Its close enough as substitute in 99% of circumstances. Though personally > I prefer a C cast, C++ has enough verbiage as it is. Read more carefully: A C-style cast can perform a reinterpret_cast (possibly even combined with a const_cast). This is a major difference with static_cast. Moreover, verbosity has been widely publicized as intentional for cast operators, for obvious reasons. |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 16 05:44PM +0100 On Tue, 16 Jun 2020 17:53:56 +0200 Manfred <noname@add.invalid> wrote: [snip] > I wonder why the standard managed to come up with something that denies > /any/ object allocation with malloc (at least according to the first > example in the proposal). It doesn't say you cannot construct objects in raw memory provided by malloc (or by operator new for that matter). It says that to do it you have to use placement new. (The problem with pointer arithmetic on non-arrays is a different but also annoying fault.) I think this insistence on using placement new is wrong. If an object is of trivial type it does not have a constructor or destructor which does anything. It is a C-like type. For trivial types, I see no reason why the standard cannot take the dynamic type of the memory to be the type of the first trivial object placed in it, say by memcpy or by assignment, which is how the C standard determines the "effective type" of memory allocated by malloc. A standard which regards inter-operability with C as important ought to provide for this. In C++ this has now been overlain since C++17 with std::launder. Prior to C++17 it used to be assumed that the strict aliasing rules regarding dereferencing pointers were what you needed to comply with. Put shortly, it used to be that if there really was an object of type T properly constructed at address n, then you could reinterpret_cast n to pointer to T and dereference that pointer. That seems fair and logical. However this no longer applies generally. Even if you are fully compliant with the strict aliasing rules, unless you fall within one of the cases described as "pointer-interconvertible" then a reinterpret_cast of pointers is no longer enough. You also have to use std::launder. Amongst other things, a pointer to the first element of an array is not pointer-interconvertible to pointer to array even though they are mandated by the standard to have the same address (there is an implicit cast in the reverse direction). You have to use std::launder as well as a reinterpret_cast. Likewise you have to use std::launder to access an object allocated in a buffer by placement new other than through the pointer returned by placement new. What's the point of this? The strict aliasing rules should be enough. And it seems from P0593 that the standard has problems on other matters of memory allocation. How on earth, in a serious technical standard, can you mandate implementers to provided functions such as std::unitialized_copy which, if implemented according to the specification, have undefined behaviour? |
Bonita Montero <Bonita.Montero@gmail.com>: Jun 15 09:20PM +0200 > __sync_bool_compare_and_swap_16 and my linker can't find it: > "undefined reference to `__sync_bool_compare_and_swap_16'" > Any ideas ? I got it. I have to compile it with -march=x86-64. |
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Jun 16 01:23PM -0700 On 6/16/2020 12:53 PM, Bonita Montero wrote: > fences. So I have a private fence( mo_t o ) function that selects > per ifdef if we have neither gcc, nor MSVC, i.e. unknown compilers > are assumed to do no fencing on CAS until the code is adpated. Well, perhaps create a model that can work as if the intrinsic RMW's are naked, or relaxed if you will. In other words, treating InterlockedExchangeAdd as if it has no implied memory order. Call it the working base model for systems with relaxed memory ordering. Akin to SPARC RMO. It seems like you are always putting the membar after the RMW: example: _________________________ inline std::pair<std::uintptr_t, std::uintptr_t> std::atomic<std::pair<std::uintptr_t, std::uintptr_t>>::exchange( pair_t desired, mo_t mo ) { pair_t cmp = m_pair; while( !cmpxchgPair( m_pair, cmp, desired ) ); atomic_thread_fence( mo ); return cmp; } _________________________ This is fine for an acquire barrier, but not for release. The release membar should be _before_ the atomic RMW. |
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Jun 16 12:43PM -0700 On 6/15/2020 9:53 PM, Bonita Montero wrote: >> If not, then you need to go rouge. Take careful note of the >> memory_order_acq_rel membar. > I inserted the appropriate fences. Just make double sure to put them in the correct places within the code. |
Bonita Montero <Bonita.Montero@gmail.com>: Jun 16 06:53AM +0200 > If not, then you need to go rouge. Take careful note of the > memory_order_acq_rel membar. I inserted the appropriate fences. |
Bonita Montero <Bonita.Montero@gmail.com>: Jun 16 09:53PM +0200 >> I inserted the appropriate fences. > Just make double sure to put them in the correct places within the code. The are in the correct places. I've changed the code a bit because the fences aren't necessary because the intrinsics have their own fences. So I have a private fence( mo_t o ) function that selects per ifdef if we have neither gcc, nor MSVC, i.e. unknown compilers are assumed to do no fencing on CAS until the code is adpated. |
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Jun 15 02:16PM -0700 On 6/15/2020 1:59 PM, Chris M. Thomasson wrote: > An atomic CAS with acquire semantics, the membar would go _after_ the CAS. > An atomic CAS with release semantics, the membar would go _before_ the CAS. Fwiw, think about the standalone (atomic_thread_fence) membars required for a general purpose lock: ________________________________ Atomic RMW to take the lock Acquire Membar [critical section] Release Membar Atomic RMW to release the lock ________________________________ An acquire/release would look like: ________________________________ Release Membar Atomic RMW Acquire Membar ________________________________ See how the membars line up with the mutex case? |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 16 11:34PM +0100 > An excellent teaching and calling: > https://www.youtube.com/watch?v=L1-hxP7l7Rw An excellent response to that teaching and calling: https://www.youtube.com/watch?v=42UCpOzTbNU /Flibble -- "Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin "You won't burn in hell. But be nice anyway." – Ricky Gervais "I see Atheists are fighting and killing each other again, over who doesn't believe in any God the most. Oh, no..wait.. that never happens." – Ricky Gervais "Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Byrne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?" "I'd say, bone cancer in children? What's that about?" Fry replied. "How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil." "Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say." |
Christian Gollwitzer <auriocus@gmx.de>: Jun 16 08:40PM +0200 Am 16.06.20 um 19:05 schrieb Makis: >> if ( !cond4 ) return; >> Do Something(); > Very hard if you have to do some cleanup upon leaving On the contrary, very easy. Use RAII and the compiler does the right cleanup in the right order. In real cases, I allocate resources in between the different conditions. That means a lot of conditions for the cleanup sequence, too, (necessary in C without ++) unless you use RAII consequently, which leaves this to the compiler. Christian |
Marcel Mueller <news.5.maazl@spamgourmet.org>: Jun 16 08:08PM +0200 > Does anyone else use fake switches and fake loops like this just to exploit the 'break' keyword? I prefer do { ... break; } while(true); It basically defines two labels. One to repeat the current block: continue, and one after the current block: break. It can also be useful to write do { ... } while (fasle); This is especially useful to escape from a nested switch statement with continue. But all of them are not always better than goto. It mainly helps to keep code guidelines that prohibit the use of goto. E.g. in case of CAS loops I prefer goto retry; since it is no loop in the logical application flow. Marcel |
Sam <sam@email-scan.com>: Jun 15 07:00AM -0400 > itself after deletions. Does it happen after every erase or only after a > certain amount of imbalance occurs? When it does happen how long does it > take and is there a way to force it to happen? This is not specified in the standard, and there are no specified ways to force a rebalance. |
boltar@nowhere.co.uk: Jun 16 09:38AM On Tue, 16 Jun 2020 21:21:24 +1200 >> If you think a major rebalance would only involved updating 3 nodes then >> you have no idea how balancing works. >I thought not. You know there's this very useful tool called Google, you might want to find out about it. In the meantime here's a useful page with a nice example of a small 11 node tree before and after balancing. I suspect even a beginner like you will be able to see that more than 3 node updates had to happen to achieve that: https://en.wikipedia.org/wiki/Self-balancing_binary_search_tree HTH |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 16 08:47PM +0100 > No, but he did invent the lie you use today, again in ignorance. > You're holding on to lies, Leigh. They keep you bound, and will cont- > inue to do so until you begin to seek the truth. And Satan invented fossils, yes? /Flibble -- "Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin "You won't burn in hell. But be nice anyway." – Ricky Gervais "I see Atheists are fighting and killing each other again, over who doesn't believe in any God the most. Oh, no..wait.. that never happens." – Ricky Gervais "Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Byrne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?" "I'd say, bone cancer in children? What's that about?" Fry replied. "How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil." "Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say." |
Scott Newman <scott69@gmail.com>: Jun 13 06:32PM +0200 > int length; > var_char data[0..length]; > }; Do you like this ? #include <cstddef> #include <cassert> template<typename T, std::size_t N> struct Container; template<typename T> struct ContainerBase { T &operator []( std::size_t i ); private: template<typename T, std::size_t N> friend struct Container; #if !defined(NDEBUG) size_t n;
Subscribe to:
Post Comments (Atom)
|
No comments:
Post a Comment