C++ Weekly - Ep 112 - GCC's Leaky Abstractions

Поділитися
Вставка
  • Опубліковано 24 гру 2024

КОМЕНТАРІ • 42

  • @davemalcolm866
    @davemalcolm866 6 років тому +54

    Thanks for the video.
    I implemented GCC's field-suggestion feature, I meant it for handling misspellings. Clearly we shouldn't be offering *these* fields as suggestions.
    I've filed this bug as gcc.gnu.org/bugzilla/show_bug.cgi?id=85515 and am working on a fix.

    • @Embedonix
      @Embedonix 6 років тому +3

      Dave Malcolm Haha leave it like this its cool :))

    • @superscatboy
      @superscatboy 3 роки тому +1

      Thanks for the feature btw - it's really useful.

  • @MaceUA
    @MaceUA 6 років тому +35

    I believe, if you wrote __for_begin = std::prev(__for_end);, it would work.
    Your attempt failed because of another "++__for_begin" statement at the end of iteration, which caused __for_begin to go past __for_end, and made the "__for_begin != __for_end" condition to start failing forever.

  • @Dziaji
    @Dziaji 2 роки тому +1

    Both if your examples are infinite loops because, in both of them, you are skipping the end iterator, so the loops keeps iterating. Basically you jumped over the flag pole. I think what you meant to do was:
    __for_begin = __for_end - 1
    That way, when the for loop increments the iterator, it will increment to be equal to __for_end and quit with a sum of 1.
    Similarly, since you have an odd number of values, if you increment by 2, you will skip the end, which is [5] and you are in the same boat. For that one, add a 6th element and it will sum every other value.
    I might make a macro that enables deletion and insertion in for range loops by manipulating __for_begin. Thanks for this.

  • @IYXandanYI
    @IYXandanYI 6 років тому +14

    Odd number of elements starting from 5 cause the infinite loop.

  • @andrei-edward-popa
    @andrei-edward-popa 2 роки тому +1

    gcc 8.2 is the latest compiler that has this leaky abstractions for interested people :)

    • @antagonista8122
      @antagonista8122 2 роки тому

      Not really. Compiler doesn't suggest you that __val exists, however you can still access it even on GCC 12 or trunk.

  • @danielrhouck
    @danielrhouck 6 років тому +5

    I know of another leaky abstraction around lambdas: lambdas without captures can be converted to function pointers. GCC implements this by calling the lambda's operator() with this == nullptr. However, if you use GCC 6 (it's been fixed later) and turn off -fsanitize=undefined, it complains about this being null (which is UB), *even in this case where it's GCC's code*. That's been fixed later, but I was confused for a while about why this was undefined.

  • @ldmnyblzs
    @ldmnyblzs 6 років тому +5

    Why are the members coming from capture (or whatever the proper term is) public? And could the solution be as simple as generating private members for them? How does Clang and MSVC do it?

    • @asuasuasu
      @asuasuasu 5 років тому

      Doesn't matter, you still can use tricks to access private class members without modifying the original class.
      If you are accessing that field you are kind of doing it on purpose. Not sure why you would worry about that.

    • @Dziaji
      @Dziaji 2 роки тому

      Nerd Nazis worry about everything man. Check out all the party poopers in the comments crying about the idea of using these leaks. Like the compiler is gonna change and go “gotcha” and delete your hard drive one day. If you are gonna do wacky and fun stuff like this. Just write a unit tester that complains if you upgrade to a compiler in which these tricks stop working. These are the type of people that tell the teacher when they forgot to assign homework.

  • @devluz
    @devluz 6 років тому +4

    In case you are interested in some ideas for videos: I think -fno-strict-aliasing / aliasing rule would be very interesting. Or other "fun" flags that can give you a terrible time such as "-fshort-enums" in gcc

    • @Afief
      @Afief 6 років тому

      That sounds like a great video!

    • @TheMrKeksLp
      @TheMrKeksLp 4 роки тому

      Oh boy strict aliasing is a fun one

  • @mariogalindoq
    @mariogalindoq 5 років тому +6

    Jason: it is very important that you see cppinsights.io/
    There you will see what the compiler really is doing. This can explain all problems you are talking about here.
    Remember also that variables starting with double underline are reserved to the language.

    • @Potti314
      @Potti314 4 роки тому

      Very cool - thanks for the link.

  • @DamianReloaded
    @DamianReloaded 6 років тому

    The range based for seems to be handled in [gcc-master\gcc\cp\parser.c] line 11915
    I'd say the ranged syntax gets straight replaced by it's proper c++ equivalent before compilation? We could check the preprocessed source to see if it is. Also, it'd be fun to check other compilers source to see if they are doing the same and what names are giving to the iterators to see if those leak too. ^_^

    • @danielrhouck
      @danielrhouck 6 років тому +1

      Here's a Compiler Explorer link with an early parsed tree version of the code: godbolt.org/g/mfG3WC

    • @DamianReloaded
      @DamianReloaded 6 років тому

      clang seems to be generating something of the sorts, but it doesn't seem to leak into your own code
      (clang.exe -cc1 -ast-dump):
      -DeclStmt 0x26744a0
      | | `-VarDecl 0x2674258 col:23 implicit used __end 'int *':'int *' cinit
      | | `-BinaryOperator 0x26743e8 'int *' '+'
      | | |-ImplicitCastExpr 0x26743d0 'int *'
      | | | `-DeclRefExpr 0x26741b0 'int [6]' lvalue Var 0x2673f68 '__range' 'int (&&)[6]'
      | | `-IntegerLiteral 0x26743a8 'long long' 6
      | |-BinaryOperator 0x2674538 'bool' '!='
      | | |-ImplicitCastExpr 0x2674508 'int *':'int *'
      | | | `-DeclRefExpr 0x26744b8 'int *':'int *' lvalue Var 0x26741e8 '__begin' 'int *':'int *'
      | | `-ImplicitCastExpr 0x2674520 'int *':'int *'
      | | `-DeclRefExpr 0x26744e0 'int *':'int *' lvalue Var 0x2674258 '__end' 'int *':'int *'
      | |-UnaryOperator 0x2674588 'int *':'int *' lvalue prefix '++'
      | | `-DeclRefExpr 0x2674560 'int *':'int *' lvalue Var 0x26741e8 '__begin' 'int *':'int *'
      | |-DeclStmt 0x2673f18
      | | `-VarDecl 0x2673eb8 col:21 used v 'const int':'const int' cinit
      | | `-ImplicitCastExpr 0x2674688 'int'
      | | `-UnaryOperator 0x26745e8 'int' lvalue prefix '*'
      | | `-ImplicitCastExpr 0x26745d0 'int *':'int *'
      | | `-DeclRefExpr 0x26745a8 'int *':'int *' lvalue Var 0x26741e8 '__begin' 'int *':'int *'
      | `-CompoundStmt 0x26747d8
      | `-CompoundAssignOperator 0x26747a0 'int' lvalue '+=' ComputeLHSTy='int'

  • @HarlowBAshur
    @HarlowBAshur 4 роки тому +3

    Anything user code involving assignments to variables whose names containing "__" is active marauding. Leaking has nothing to do with it.

    • @Dziaji
      @Dziaji 2 роки тому

      You are confused.

  • @NealMiskinMusic
    @NealMiskinMusic 4 роки тому

    Sounds like you could really bork stuff up hard with these hacks!

  • @avis9ditiu
    @avis9ditiu 6 років тому

    This guy is insane.

  • @von_nobody
    @von_nobody 6 років тому +1

    Great catch :D only question is could you encounter this in any valid code?

    • @jakearkinstall5313
      @jakearkinstall5313 6 років тому +1

      von nobody Define valid code. As it isn't in the standard, I wouldn't be comfortable calling this valid, but if you are coding specifically for GCC (and on a fixed version, seeing as they can modify behaviour in later versions) then I guess you can get away with it - it certainly isn't unheard of for people to abuse compiler specific behaviours for in-house, limited-scope applications.

    • @von_nobody
      @von_nobody 6 років тому +1

      My question was different, image you try write valid program that follow standard (do not use names and macros like `__foo`, getting address of std function, etc.) and is possible to do write it in that way that you will see difference caused by this leak? Example could be if you define variable `__for_begin` outside of loop and try alter in inside, but this is not allowed because of naming convention.

    • @taragnor
      @taragnor 5 років тому

      Honestly I'd be real skeptical of any programmer who did this sorta thing. It's one of those cute obscure tricks being used for no reason aside from being cute and obscure. It's easy enough to do pointer manipulation in C++ as it is using a generic for loop, so the for loop example is easy enough, and having alterable lambda variables is trivial with the use of pointers and references.

  • @JesseBusman1996
    @JesseBusman1996 6 років тому

    Cool!

  • @LesleyLai
    @LesleyLai 6 років тому +1

    I hope lambda have capture by constant reference.

    • @connorhorman
      @connorhorman 6 років тому +1

      Yeah its called capture a const object by reference.

  • @toddseiler
    @toddseiler 5 років тому

    Type it into here: cppinsights.io There should be a way to dump out this content via compiler flag.

  • @echosystemd
    @echosystemd 6 років тому

    Fixed here, gcc.gnu.org/bugzilla/show_bug.cgi?id=85515

    • @brainplot
      @brainplot 5 років тому +1

      As of this reply, the error message was fixed. However, if you type l.__val, the code still compiles.

  • @notyetdecided5811
    @notyetdecided5811 6 років тому

    Feels like I never learned c++

    • @Dziaji
      @Dziaji 2 роки тому

      That means you are not a real programmer. Most aren’t. Start now. C++ is the only true language besides assembly.

  • @steveragnar1155
    @steveragnar1155 6 років тому

    Too many leaks: you sink. This is scary but fascinating. The standard does not mention anything on 'leaky' implementations for these C++ standard syntatic contructs and their defined semantics.

    • @danielrhouck
      @danielrhouck 6 років тому +10

      The standard does say that identifiers beginning with a double underscore are reserved. This is, to the best of my knowledge, all perfectly legal. GCC could also create an __do_not_set flag, and if your code ever runs __do_not_set = true, it formats your hard drive.
      This would be a bad idea but would be allowed by the C++ standard.

    • @steveragnar1155
      @steveragnar1155 6 років тому

      Correct. But the C++ standard does not adjudicate on the issue of the visibility of these implementation constructs: client code can access these 'public' variables and in so doing can alter the semantics of standard language features such as the for range as exemplified in the above video. The least that can be said is that it is not portable C++ code.