WTF Bites


  • 🚽 Regular

    @Gąska said in WTF Bites:

    @Zerosquare said in WTF Bites:

    An even better solution is not to reinvent the wheel, and use the installation features every modern OS has.

    Hey!

    Didn't you know? Windows has a package manager now.

    Oh wait. Never mind.


  • Trolleybus Mechanic

    Shit. I badmouthed Tizen and now he threatens to punch me. He already loaded fist instead of a file:

    IMG_20200529_162303.jpg



  • @Zerosquare said in WTF Bites:

    not to reinvent the wheel

    Now I know you're not a real programmer.



  • @Zerosquare said in WTF Bites:

    An even better solution is not to reinvent the wheel, and use the installation features every modern OS has.

    Oddly enough, there's a Windows Store version of this application. Can't get much more Modern than that as far as installing goes.


  • ♿ (Parody)

    @HardwareGeek said in WTF Bites:

    @Zerosquare said in WTF Bites:
    "not to reinvent the wheel"

    Now I know you're not a real programmer.

    Node.js programmer, probably.



  • @sebastian-galczynski said in WTF Bites:

    I badmouthed Tizen and now he threatens to punch me.

    That's par for the course for it.


  • Trolleybus Mechanic

    @Bulb
    Yep, I read the three canonical Tizen threads ;)

    BTW, we finally got rid of the threatening pop-up. It started appearing when someone activated the 'local developer mode' (which didn't work). After returning to remote mode, it looked like the device rebooted, but the error reappeared every time the app was started. Only after physically pulling the plug it stopped appearing.



  • @error said in WTF Bites:

    @hungrier No, I have no interest in that category.

    So either he's never posted outside the garage, or NodeBB is too stupid to filter before paginating.

    One of those is funnier, and the other is more likely.

    I'm going with the first one.


  • Notification Spam Recipient

    @brie said in WTF Bites:

    @error said in WTF Bites:

    @hungrier No, I have no interest in that category.

    So either he's never posted outside the garage, or NodeBB is too stupid to filter before paginating.

    One of those is funnier, and the other is more likely.

    I'm going with the first one.

    Guess what it does with collapsing notifications?



  • @sebastian-galczynski said in WTF Bites:

    Only after physically pulling the plug it stopped appearing.

    Rule Number 1: Always turn it off and back onleave it off.



  • @sebastian-galczynski said in WTF Bites:

    After returning to remote mode, it looked like the device rebooted, but the error reappeared every time the app was started. Only after physically pulling the plug it stopped appearing.

    Oh, the story of a reboot that wasn't.


  • Discourse touched me in a no-no place

    @Applied-Mediocrity said in WTF Bites:

    I've never actually written C code (outside of college).

    It's very simple.

    Except for everything to do with pointers, which is incredibly subtle.



  • And undefined behavior hidden behind seemingly trivial stuff.

    Fortunately, pointers and undefined behavior are rarely encountered in C programming 🏆



  • @HardwareGeek said in WTF Bites:

    @Zerosquare said in WTF Bites:

    not to reinvent the wheel

    Now I know you're not a real programmer.

    Just because I say "that's how it should be done" doesn't mean I actually do it :trollface:

    @boomzilla said in WTF Bites:

    Node.js programmer, probably.

    Hey! This is not the Garage!


  • Trolleybus Mechanic

    @dkf said in WTF Bites:

    Except for everything to do with pointers, which is incredibly subtle.

    Oh, come on, you just cast everything to void*, and go home.


  • :belt_onion:

    @TimeBandit said in WTF Bites:

    @MrL said in WTF Bites:

    I think it did it earlier.

    I think it did 15 years ago 🤷🏻♂

    Yes. Office/Word 2003 works perfectly fine.


  • Discourse touched me in a no-no place

    @sebastian-galczynski said in WTF Bites:

    @dkf said in WTF Bites:

    Except for everything to do with pointers, which is incredibly subtle.

    Oh, come on, you just cast everything to void*, and go home.

    I'd ask just how much of our codebase did you write… except our idiots prefer to cast everything to uint16_t*. Or, for a different (and slightly later) set of idiots, uint32_t*. Because actually declaring and documenting the types that you're working with is hard, so let's go shopping bake our own structure accesses with array accesses with hardcoded constants.


  • Banned

    @dkf said in WTF Bites:

    @sebastian-galczynski said in WTF Bites:

    @dkf said in WTF Bites:

    Except for everything to do with pointers, which is incredibly subtle.

    Oh, come on, you just cast everything to void*, and go home.

    I'd ask just how much of our codebase did you write… except our idiots prefer to cast everything to uint16_t*.

    That violates strict aliasing, doesn't it?



  • @Gąska If it wasn't a uint16_t from the beginning, then yes. Unfortunately quite common, and there's a fair amount of developers and libraries that advocate -fno-strict-aliasing and equivalents as a consequence.

    I have the impression that more people are starting to avoid that kind of code, but it'll be around for a while.


  • BINNED

    @Gąska said in WTF Bites:

    @dkf said in WTF Bites:

    @sebastian-galczynski said in WTF Bites:

    @dkf said in WTF Bites:

    Except for everything to do with pointers, which is incredibly subtle.

    Oh, come on, you just cast everything to void*, and go home.

    I'd ask just how much of our codebase did you write… except our idiots prefer to cast everything to uint16_t*.

    That violates strict aliasing, doesn't it?

    Not necessarily more so than void*, it depends on what you do with it. In other words, probably yes, but probably the void* code would too. You can't do much with it except storing / casting back, and memcpying, which would be the correct thing to do. But I'd assume that after the cast to void usually comes another cast to something else that breaks aliasing anyway. (Not an unfair assumption given that the link goes to some enlightened programmers)


  • Discourse touched me in a no-no place

    @Gąska said in WTF Bites:

    That violates strict aliasing, doesn't it?

    The code in question is packing values into a buffer that's going to be sent out on the network (with a defined format) and the idiots who defined the protocol made it that in some configurations (not all, but actually the ones that come up most often in practice) you end up having to stuff 32-bit integers at half-word boundaries. And the real data structure describing this is very difficult to describe in C because most of the fields within it are not at fixed offsets. It's really miserable to work with.

    I'm generally happy with manually putting restrict in where required. I know what's really going on after all. If only there was a good way to declare a type as being a "pointer to a 32-bit unsigned integer with half-word alignment” (so requiring the use of two strh instructions to read the value instead of a single str), but there doesn't seem to be a way to do this with GCC (some versions of the ARM process. You have to do something ugly like this:

    void set_value(uint32_t *storage, uint32_t value) {
        if ((uint32_t) storage & 2) {
            uint16_t *ptr = (uint16_t *) storage;
            ptr[0] = value & 0xFFFF;
            ptr[1] = value >> 16;
        } else {
            // We are aligned after all, and should use the more efficient option
            storage[0] = value;
        }
    }
    

    The result is quite efficient, but it's one heck of a lot more than a simple array write. Did I mention that I hate the jerkwads who decided to save a few bytes by squashing everything down very hard?



  • @dkf I feel much the same way about grognards (:belt_onion: types) who complain that "back in the day, we fit everything into <space> because we were so efficient...programmers these days." Sure, there are idiots who insist on shoving the whole ui down the pipe as javascript or who shove full resolution images just to reduce them in CSS, but at the other extreme, byte-shaving protocols like this are really painful to deal with and cause bugs everywhere.


  • Discourse touched me in a no-no place

    @Benjamin-Hall When you're working well within the capabilities of the system, you can afford things like sending everything as JSON and so on. When you're pushing some small bit of hardware hard, you've got to be a lot more efficient. (That also applies when you're dealing with a big bit of hardware made out of lots of small bits of hardware; the overall system is gigantic, but the individual parts are tiny and you have to be very careful.)



  • @dkf said in WTF Bites:

    @Benjamin-Hall When you're working well within the capabilities of the system, you can afford things like sending everything as JSON and so on. When you're pushing some small bit of hardware hard, you've got to be a lot more efficient. (That also applies when you're dealing with a big bit of hardware made out of lots of small bits of hardware; the overall system is gigantic, but the individual parts are tiny and you have to be very careful.)

    True enough. Embedded is different. But isn't there better and worse ways of doing that?


  • Discourse touched me in a no-no place

    @Benjamin-Hall said in WTF Bites:

    But isn't there better and worse ways of doing that?

    All the better ways involve not over-packing things or playing smartass games with glomming things together in ways that don't fit well with the C model.



  • @dkf if it saves one lifebyte... :half-trolling:



  • 🎵 Every byte is sacred!


  • Banned

    @topspin said in WTF Bites:

    @Gąska said in WTF Bites:

    @dkf said in WTF Bites:

    @sebastian-galczynski said in WTF Bites:

    @dkf said in WTF Bites:

    Except for everything to do with pointers, which is incredibly subtle.

    Oh, come on, you just cast everything to void*, and go home.

    I'd ask just how much of our codebase did you write… except our idiots prefer to cast everything to uint16_t*.

    That violates strict aliasing, doesn't it?

    Not necessarily more so than void*

    IIRC void and char are explicitly exempt from the strict aliasing rule.



  • @Gąska You can't actually dereference a void* pointer, so there's no need to make it an exception. But, yes, char types and std::byte are exempt from strict aliasing.


  • BINNED

    @Gąska said in WTF Bites:

    @topspin said in WTF Bites:

    @Gąska said in WTF Bites:

    @dkf said in WTF Bites:

    @sebastian-galczynski said in WTF Bites:

    @dkf said in WTF Bites:

    Except for everything to do with pointers, which is incredibly subtle.

    Oh, come on, you just cast everything to void*, and go home.

    I'd ask just how much of our codebase did you write… except our idiots prefer to cast everything to uint16_t*.

    That violates strict aliasing, doesn't it?

    Not necessarily more so than void*

    IIRC void and char are explicitly exempt from the strict aliasing rule.

    Yes. But as I said, you can’t really do much with it, so there’s a fair chance that they (the enlightenment morons) would break the aliasing rules afterwards anyway by casting it to some other wrong type.



  • @dkf said in WTF Bites:

    @sebastian-galczynski said in WTF Bites:

    @dkf said in WTF Bites:

    Except for everything to do with pointers, which is incredibly subtle.

    Oh, come on, you just cast everything to void*, and go home.

    I'd ask just how much of our codebase did you write… except our idiots prefer to cast everything to uint16_t*. Or, for a different (and slightly later) set of idiots, uint32_t*. Because actually declaring and documenting the types that you're working with is hard, so let's go shopping bake our own structure accesses with array accesses with hardcoded constants.

    That sounds like my world. Because when you're dealing with hardware, everything is a 32-bit value, even when it's composed of 7 1-bit fields, a couple of 6-bit fields, a 9-bit field, and a few bits that aren't actually connected to anything. I've seen this done with structs of bits, unioned with uint32_ts, but it's rare; usually it's just a bunch of #defines for masking and shifting the values into the right bits.



  • @HardwareGeek said in WTF Bites:

    Because when you're dealing with hardware, everything is a 32-bit value, even when it's composed of 7 1-bit fields, a couple of 6-bit fields, a 9-bit field, and a few bits that aren't actually connected to anything whose only description is "Reserved.", with strong implications that just looking at them the wrong way could be sufficient to cause the hardware to self-combust.



  • @dkf said in WTF Bites:

    Did I mention that I hate the jerkwads who decided to save a few bytes by squashing everything down very hard?

    In my current project, I'm dealing with a thing that produces 24-bit data. In a previous version, the data was 16-bits, and could be stored one 16-bit value in a 32-bit word, or two 16-bit values packed in a single 32-bit word. There is a spec that defines all the possible ways you could pack 4 24-bit values into 3 32-bit words, but fortunately somebody sane said no. There is one and only one format we are going to support; each 24-bit value goes into the low 24 bits of a 32-bit word. Period. 🎉



  • @HardwareGeek You haven't truly lived until you've debugged a program that uses (variable length) pointer compression. Grab the lower 17 bits from that word, smash them together with 12 from the following, and run them through a function or two, and -presto- there's a (real) pointer.



  • @cvi I've definitely worked with hardware in which a pointer is too big to fit in a single word, many times. I know I've also worked with hardware in which a pointer is split into multiple fields in several words in not entirely sensible ways. The original design had, say, a 16-bit address in one register; a later version added features, including increasing the memory size from 64k to 1M, but the additional bits didn't fit in that register, so they, along with some control bits, got put in another register. Later, the memory size was increased again to, say, 8M, but those 3 additional address bits didn't get put with the others because there were already control bits there, so they got put in yet another register. But I don't remember the context in which I worked with something like that.


  • BINNED

    @cvi said in WTF Bites:

    @HardwareGeek You haven't truly lived until you've debugged a program that uses (variable length) pointer compression. Grab the lower 17 bits from that word, smash them together with 12 from the following, and run them through a function or two, and -presto- there's a (real) pointer.

    This one weird trick lets you compress a full pointer into 17 bits. Garbage Collectors hate him.



  • @HardwareGeek I'm having flashbacks to x86 segment addressing. ⚡ 🤯



  • @topspin said in WTF Bites:

    @Gąska said in WTF Bites:

    That violates strict aliasing, doesn't it?

    Not necessarily more so than void*, it depends on what you do with it.

    There is no way to dereference a void *, so as long as you cast it back to compatible type for dereferencing, it is not violating strict aliasing. Given they cast specifically to uint16_t *, I suppose they are actually dereferencing it too.

    @dkf said in WTF Bites:

    The code in question is packing values into a buffer that's going to be sent out on the network (with a defined format) and the idiots who defined the protocol made it that in some configurations (not all, but actually the ones that come up most often in practice) you end up having to stuff 32-bit integers at half-word boundaries.

    The officially sanctioned approach is to use an uint8_t buffer, which is exempt from strict aliasing by virtue of actually being a char variant (unsigned char).

    void set_value(uint32_t *storage, uint32_t value) {
        if ((uint32_t) storage & 2) {
            uint16_t *ptr = (uint16_t *) storage;
            ptr[0] = value & 0xFFFF;
            ptr[1] = value >> 16;
        } else {
            // We are aligned after all, and should use the more efficient option
            storage[0] = value;
        }
    }
    

    I don't see any advantage over using uint8_t *storage (exempt from strict aliasing) and possibly using memcpy instead of shifts and masks (I'd use memcpy if it's native-endian and shifts if it is fixed endian—as written the words are native-endian, but the order of the two words is fixed-endian, which just risks creating a mixed-endian garbage. Ok, almost everybody finally agreed on little but anyway).

    @Benjamin-Hall said in WTF Bites:

    at the other extreme, byte-shaving protocols like this are really painful to deal with and cause bugs everywhere.

    Well, 60 b/s downlinks are well and alive. Or such that are 1 Mb/s, but with due to number of messages that have to get through and the inability to use any proper access method (range about 1 mls, omnidirectional) are barely usable with the squeezed messages.

    Anyway, there is a couple of generators like protobuf that are fairly tightly packed while preventing bugs by generating the bit-fiddling from easily maintainable declaration.

    @HardwareGeek said in WTF Bites:

    That sounds like my world. Because when you're dealing with hardware, everything is a 32-bit value, even when it's composed of 7 1-bit fields, a couple of 6-bit fields, a 9-bit field, and a few bits that aren't actually connected to anything. I've seen this done with structs of bits, unioned with uint32_ts, but it's rare; usually it's just a bunch of #defines for masking and shifting the values into the right bits.

    Strangely enough unions are not exempt from strict aliasing rules, so shifting and masking constants are actually the correct approach – as long as you either use only one base type (i.e. no switching between 16 and 32 bits) or only mix it with char (8-bit types).


  • Discourse touched me in a no-no place

    @Bulb said in WTF Bites:

    I don't see any advantage over using uint8_t *storage (exempt from strict aliasing)

    It takes a more instructions if you do since when using uint8_t* there's no alignment assumed at all and each byte is written on its own. The code I posted instead uses half-word writes, which makes it approximately twice as fast. (It turns out that memcpy() is suboptimal in this case, as that just switches to doing everything bytewise in this particular case, but only after a series of runtime checks. The code for memcpy() is surprisingly long.)

    The annoying thing is that I can't tell the compiler the information that I know about the pointer. If I try to do that, it just ignores it and writes assembly out that will cause the target machine to keel over with a bus error. Yes, what I'm writing to memory is an ugly format. I can't help that without rewriting a lot more code elsewhere and doing a lot of testing (including in-depth performance analysis across a range of scenarios, so probably several months work given the way other bits and pieces interact).

    risks creating a mixed-endian garbage

    Not a problem. Target platform has defined endianness (it's a single revision of a single chip design; it really is a known target) and the network protocol itself has defined endianness. Even better, they're the same. (Only our boot protocol is pants-on-head retarded that way, and that's only because it was written by an idiot and burned into a real ROM.)


  • Java Dev

    @Bulb said in WTF Bites:

    Strangely enough unions are not exempt from strict aliasing rules

    I seem to recall unions are defined so weakly that #define union struct is legal.



  • Apparently these video cards are so old that they're both older than each other

    97cfa23a-ec18-4918-84ef-eaf6b71ea08f-image.png


  • Discourse touched me in a no-no place

    @PleegWat said in WTF Bites:

    @Bulb said in WTF Bites:

    Strangely enough unions are not exempt from strict aliasing rules

    I seem to recall unions are defined so weakly that #define union struct is legal.

    Not quite. From page 103 of the C99 spec, these are the paragraphs that distinguish a struct and a union:

    1. Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.

    2. The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bitfield, then to the unit in which it resides), and vice versa.

    Note that for a struct we have pointer interconvertability between the struct and the initial member, and for a union we've got it for all members. (It doesn't make actually dereferencing those pointers necessarily legal.)



  • @dkf said in WTF Bites:

    It doesn't make actually dereferencing those pointers necessarily legal.

    I believe it makes them legal if and only if dereferencing the corresponding member is.



  • @dkf said in WTF Bites:

    it was written by an idiot and burned into a real ROM

    Letting idiots do that is not recommended.



  • @BernieTheBernie If he insists, the more c#y way would have been

    public TimeSpan (long ticks)
    

    as

    private TimeSpan m_Timeout = new TimeSpan(8 * TimeSpan.TicksPerSecond);
    

  • Considered Harmful

    @hungrier said in WTF Bites:

    Apparently these video cards are so old that they're both older than each other

    97cfa23a-ec18-4918-84ef-eaf6b71ea08f-image.png

    Eh, 270X was in most aspects a 7870 rebrand (now with Boost!).


  • Notification Spam Recipient

    @SirTwist said in WTF Bites:

    m_Timeout
    


  • @MrL Not my fault, that was in the original.



  • @dkf said in WTF Bites:

    If only there was a good way to declare a type as being a "pointer to a 32-bit unsigned integer with half-word alignment”

    Surely TRWTF with that is that "storage[0] = value" doesn't do what you expect just because storage isn't aligned. If that's not a valid uint32* then it shouldn't be possible to use that value in the first place. (What does it do, by the way?)



  • @dkf said in WTF Bites:

    The result is quite efficient

    I dunno, I could probably make this more efficient.

    01229841-5a39-4733-b566-ca0565d879c2-image.png


Log in to reply