CppCast - PVS-Studio Static Analysis

Episode Date: March 12, 2020

Rob and Jason are joined by Yuri Minaev from PVS-Studio. They first discuss a blog posts on ISO's recent decision not to break the C++ ABI in C++23 and getting rid of volatile in the Qt codebase. Then... they talk to Yuri Minaev, one of the developers at PVS Studio working on the static analyzer. They discuss some of the forms of analysis that the tool excels at and how it's changed the way Yuri programs. News HOly Grail of Logging The Day the Standard Library Died The Performance Benefits of Final Classes Getting rid of 'volatile' in (some of) Qt Links Yuri Minaev Blog Posts Sponsors PVS-Studio. Write #cppcast in the message field on the download page and get one month license Read the article "Zero, one, two, Freddy's coming for you" about a typical pattern of typos related to the usage of numbers 0, 1, 2

Transcript
Discussion (0)
Starting point is 00:00:00 Thank you. In this episode, we discuss breaking the C++ ABI. Then we talk to Yuri Muniv from PVS Studio. Yuri talks to us about his work on PVA Studio Static Analyzer. Welcome to episode 238 of CppCast, the first podcast for C++ developers by C++ developers. I'm your host, Rob Irving, joined by my co-host, Jason Turner. Jason, how are you doing today? I'm doing okay, Rob. How are you doing? Doing okay.
Starting point is 00:01:24 Keeping my hands clean, coughing into my arm. how are you doing in colorado are there a lot of concerns about uh coronavirus uh it's like 18 confirmed cases here now our governor just took a bunch of proactive measures to make sure that uh anyone who needs to take time off regardless of whether they actually have sick leave will get paid sick leave. That's good. And to ensure that all testing is free and just try to alleviate people's concerns so that if they think that they need to get tested or whatever, that they can do that without feeling like I'm going to lose my job or something stupid.
Starting point is 00:01:59 That's very good. I guess we should actually talk for a moment just about how it is affecting the C++ community a bit. I mean, I know it's not a C++ conference, but I was planning on going to the Microsoft MVP Summit next week, and that was canceled. I believe Pacific++ was also canceled, right? Oh, I don't know. I think it was. Are you aware of any other big cancellations or interruptions to anything
Starting point is 00:02:25 uh no i haven't seen um i mean you know e3 and stuff like the game conferences are canceled which is no pacific plus plus didn't have dates announced for 2020 i thought i saw something get canceled yeah um there's yeah there's there's like, we just don't know a lot right now still, because let's see the next conference coming up is core C plus plus. And as far as I know, they haven't announced anything. Um, Israel is, uh, doing quarantine at their borders. So that could affect something, but that's still more than two months away. So yeah, hopefully, uh, in two months things will start to, uh, calm down.
Starting point is 00:03:04 Yeah. And, um um embo plus plus is starting like right now and they are not canceled um but yeah i don't know i have no idea i don't have anything really coming up until the end of may myself so uh i just kind of want to know sooner rather than later if it's going to be canceled, right? Yeah, yeah, definitely. Well, if you are attending any conferences, definitely make sure that you are washing your hands and maybe don't shake as many hands. Okay, well, at the top of every episode, I'd like your piece of feedback. We got this tweet from Kobe Cohen-Razi responding to last episode,
Starting point is 00:03:44 and you, Jason, saying you're asking about app crashing and losing data that's a reference to the logging the logging libraries asynchronous logging asynchronous logging if the app crashes yeah so he's talking about hogel and saying it's another async logging uh library and when the app crashed the unflushed buffers will be in the core file and hoggle has a tool to parse the core dump and extract the unflushed data on flash data so yeah i guess that is a concern that you can lose stuff with async logging but uh hoggle at least has a tool for getting that data out for you i can say i've absolutely never tried to parse a core file, core dump, to try to find logging information. No, I don't think I have either.
Starting point is 00:04:30 Yeah. Okay. Well, we'd love to hear your thoughts about the show. You can always reach out to us on Facebook, Twitter, or email us at feedback at cbcast.com. And don't forget to leave us a review on iTunes or subscribe on YouTube. Joining us today is Yuri Manev. Yuri is working on the PVS Studio company as one of the developers
Starting point is 00:04:47 on the C++ Static Analyzer. His primary responsibility is to keep low-level stuff in order and add new features to the core module. It's been almost two years since he joined the team after about 12 years of IT experience. Apart from that, he periodically gives talks at various conferences, mainly on topics related to static analysis and C++.
Starting point is 00:05:04 In his spare time, Yuri likes to program in C++, play guitar, and sometimes hike around aimlessly. Yuri, welcome to the show. Hi, everyone. Thanks for having me here, guys. It's a pleasure. Certainly. You say hike around aimlessly. Do you live in an area that's good for that? You've got hills or something nearby, a forest? Yes, kind of. We have a forest. Well, a couple of forests. We have
Starting point is 00:05:29 a park here, so there are a lot of places where you can go. I actually like to go around the town surprisingly. I'm sorry, my tone is not cooperating. No, that's nice.
Starting point is 00:05:47 I don't live in a, like, I mean, I run around my neighborhood, but I don't live anywhere close enough to a town to really enjoy walking around the town, unfortunately. Okay, well, Yuri, we've got a couple news articles to discuss. Feel free to comment on any of these, and then we'll start talking more about the work you do at PBS Studio, okay? Alright, so this first one is a blog from
Starting point is 00:06:09 Corentin that he wrote right after the Prague meeting and it's the day the Standard Library died. Mostly just talking about his reaction to the ISO committee voting to not break ABI in c++ 23 and why he thinks that
Starting point is 00:06:29 was a very very bad idea it's a lot of very good article this is a very good article he goes into some of the things yeah he goes into some of the things that could be changed with an abi break um and just you know uh why he thinks that we should be. Sorry, you had something to say? No, I just said that the article was kind of interesting because on one hand breaking ABI doesn't sound like a great idea, but on the other
Starting point is 00:07:00 if we can squeeze performance boosts from it, maybe it's worth it in the end. I read it. I wasn't sure about my opinion at that moment because I think both positions on whether or not we need to break the ABI are kind of valid. So you can argue for both, I guess. Well, his argument that if we're not willing to ever break the ABI, then we have to accept that anything that we add to the standard library tomorrow is just pretty much going
Starting point is 00:07:36 to be that way forever. Yeah. That's a pretty strong argument. Yes, it is. But, okay, if we break it, won't it break backwards compatibility with old projects, with old code, maybe? So, yeah, I personally, I think that changes are good. So I would break it, to be honest. I would break it, to be honest. I would too. I'm definitely in the camp of, yeah, we can be expected to recompile all of our code once every three or six years or whatever, personally. But I've said this many times in the show, I've never had to work in code that relied on binaries from companies that went out of business and they have no chance but to, you know.
Starting point is 00:08:26 And one thing he brings up here is, you know, they had this vote about whether they would break ABI and C++23, and then that was voted against. But then they had several votes to say, you know, we will not promise stability forever, and they will consider proposals requiring an api break so you know if you're not going to break abi in 23 maybe we should decide now when we will break the api because if you just keep holding that same vote every three years like hey will this be the release that we break the api you're probably always going to say no no one's ever the people who are not wanting to break it now are going to not want to break it again three years from now and then six years from now. But maybe if you propose, say, okay, are we going to break it now or are we going to break
Starting point is 00:09:12 it six years from now instead or nine years from now instead? Maybe you need to kind of hold that vote now and hold everyone to it. I liked his argument that if we don't do it now, people will wait for longer and longer and like they will lag behind the changes and code people right will assume that the ABI stays the same and yeah so this one I liked that we need to do it now to make it maybe less painful
Starting point is 00:09:50 and force people to migrate to the new standard. Yeah. Also, I think for anyone who's listening, who's in this boat of saying, well, we can't break ABI
Starting point is 00:10:05 compatibility because I rely on these old binaries. There's a sentence here says, let's be very clear programs that rely on ABI probably violate ODR somewhere and probably using incompatible flags that happen to work. So people who have old code that they're relying on ABI stability today, I agree with them. There's a very good chance that your code's actually broken. You just don't know it yet. So consider that. Yeah,
Starting point is 00:10:31 that's true. Okay. A less controversial article, although we all seem to be on the same side of that one. Yeah, it's no controversy here. Yeah. This is from the Microsoft C++ blog,
Starting point is 00:10:44 and it's a post from Cybrand about the performance benefits of final classes. And this goes into, you know, if you declare final on your class, you can de-virtualize the function calls, which gets you some performance improvements. So it's kind of just a nice brief overview of the benefits of using final. This is a fun one from my perspective, because it started as something of a Twitter conversation resulted in Cy saying, I'm going to write an article about that. And at about the same time, I was making my argument for where I use final and ChaiScript. And I can, I'm going to probably make a C++ weekly episode about this, but I have an intermediate layer in my library. I'm using final. And if I remove the final right there,
Starting point is 00:11:30 I can easily trivially measure a 20% performance hit. Like I need it for the way that I designed that portion of the API. So I'll probably put that in an episode also as a follow on to size article. That's a big performance hit just by removing final yes 20 yeah 20 is what i last measured now to be fair that was like three or four years ago and compilers are constantly changing so we'll see what it is today yeah okay and then this last article is on kdab's blog uh fromppi, and it's getting rid of volatile in sum of Qt. And it's basically a response to the proposal that was accepted in C++20 to deprecate parts of volatile, and the author decided to go through Qt's code base
Starting point is 00:12:18 and clean up instances of volatile that are going to be deprecated with C++20. And found some interesting cases where volatile was being misused, but also some places where volatile needed to be used, which I thought was interesting. You mean long jumps? Yeah. The long jumps part. Yeah, which is also disturbing to me. Yes.
Starting point is 00:12:51 Could either of you maybe explain the set jump, long jump stuff a little bit better for our listeners? I've never used it before. I think I understood the article. I have not used it before either. If Yuri, if you've got insight, I'll let you explain it. Otherwise, I'll do my best. So what I was saying is volatile, I feel, is one of the most misunderstood and misused features in the language. And the article, it seems to be confirming that. For example, I liked the part where volatile was used as an atomic.
Starting point is 00:13:31 And for synchronizations between threads. That was kind of disturbing to me, to be honest. Could you comment on the usage of Volatile as set jump, long jump, which is the legitimate use of volatile, and maybe explain that a little bit better for our listeners? For set jumps and long jumps? Yeah. Well, that's, as I understand it,
Starting point is 00:14:01 it's an old, old piece of legacy code, which came from C. volatile there, well it fends the compiler from doing anything with your jumps between functions. Those long jumps, they are kind of a poor man's exception handling mechanism. I guess along with no return functions in C which you could use to kind of handle some exceptions and maybe terminate your program. Well volatile there is... it seems legitimate
Starting point is 00:14:42 and it seems useful but I, but if you ask me, I would get rid of the long jumps and set jumps in this case instead of using this old mechanism. I was curious about that also because this comes from libjpg usage, I believe. And it seems that that's the prescribed way. That's how they suggest that you handle the errors. And I was wondering if they have some other error handling mechanism where you don't have to use set jump and long jump. Yes. Well, as I understand, the library is old.
Starting point is 00:15:17 I never used JPEG, the libjpeg, personally. Yeah, me neither yeah but it it looks like it looks like it came from an old age you know from c and whatnot ah yes it's dated 1998 right um and he did a little bit of googling and seems to have found that most libraries that use libjpg actually have a bug in their error handling routines. Really? Yeah. Long jumps and set jumps with GTK, GDK, and ImageMagick all seem to have made the same mistake copying and pasting from libjpg's example code. Nice.
Starting point is 00:16:10 I actually just had a class that I taught earlier this week where we discussed very briefly volatile. It wasn't the point of the class, but it came up. And they said they had old code that used volatile for thread synchronization, which we know is not the correct thing to do. And they had migrated that to Atomic, but had not actually dropped the volatile, so now they had volatile Atomics. I said, you probably want to get rid of that volatile.
Starting point is 00:16:35 It's not doing what you think it's doing. The Atomic is what you really need there. Well, I guess in embedded systems, it can be useful if you're waiting for some data from some register. You can use them, volatile variables, kind of to connect them to hardware. And you use volatile to prevent compilers from removing them. Like a compiler can look, for example, at a loop where you're waiting on some value of a variable and decide, hey, this variable never changes, so I'll just remove the whole thing from here.
Starting point is 00:17:16 So that's a good usage, I guess. So out of curiosity, while we're still on the topic of volatile, is this something that PVS Studio has checks around as well? We consider volatile in cases like loop optimization and things like that. So if we see it, we know that the compiler won't kick it out. And we also check for some cases of incorrect usage, but they are rare. We use it mainly as a marker that anything can happen to the variable and the compiler won't optimize it away properly. You know, one interesting case is there is that cursed thing called memset.
Starting point is 00:18:15 People like to use it sometimes for zeroing memory. If you have sensitive data, you want to zero it out, but compilers like to kick it out of your code just for reasons because I guess they like to do that. But if you use volatile pointers in
Starting point is 00:18:37 memset, compilers sometimes skip it. Interesting. So some people are using it as a way to for some level of security, to stop the compiler from removing their call to MSAT. Yes, you can use it like that, but I think it's still a hack. Sure. Okay. Well, why don't we start talking a little bit more about the work you do? I guess maybe to start off, how did you get interested in stack analysis?
Starting point is 00:19:07 I was looking for a job as a programmer, and I looked at different companies, and I came across this one and said, hey, something interesting is going on here. And I started reading about that, and I decided, okay, I want to go work there. Because those guys, my reasoning, I guess reading about that and I decided okay I want to go work there because those guys they my reasoning I guess was that okay all those different companies they just use the language to do stuff but those guys they the language is not only a tool to them it's the subject of the study if you want to call it like that.
Starting point is 00:19:46 So yeah, I just came across the company and I decided to read more about static analysis in general. And I decided that, okay, I want to go work there. And you said you've been working there for
Starting point is 00:20:01 two years now? About two years, yeah. Okay. What is different about And you said you've been working there for two years now? About two years, yeah. Okay. Okay. What is different about PVS Studio's analyzer compared to some other static analyzers out there? You know, that's the question we get often. And usually we say something along the lines of, you know, we don't compare our tool to other tools because it's our tool and it will look better than others. Blah, blah, blah, blah, blah. You know, the usual stuff companies do.
Starting point is 00:20:33 Well, actually, I don't have a definitive answer to that. I guess every tool is good in its own area. Maybe some tools do some stuff better than others, and it's been like that since forever, it looks like. I would say we test our analyzer very thoroughly. We have a test base of about 100 something open source projects. And every time we do any change, we run tests against that base of projects. And we see if anything broke. So we've got a very vast code base for tests. I don't know if others do that.
Starting point is 00:21:31 I have no idea. Yeah, that's a difficult question, but it's a good one. Maybe if I could change the question, the original question of what sets it apart is perhaps are there certain types of errors that pvs studio is very good at catching copy paste oh okay uh copy paste uh also null pointers if you are trying to dereference a null, we usually can catch it very well. I can tell you what it's not so good. It's multi-threading mutexes and stuff like that.
Starting point is 00:22:14 Oh. So yeah, it's not very good at that. I didn't even know that any static analysis tools checked for that. I just used thread sanitizer or something. Run time. that any static analysis tools checked for that. I just used thread sanitizer or something. Yeah, you will end up better with a sanitizer if you want to check that kind of stuff. We have a couple of diagnostics for multithreading.
Starting point is 00:22:40 Mostly stuff like, oh, you locked a mutex which was already locked, stuff like, oh, you locked a mutex which was already locked. Stuff like that. Oh, okay. So like if in the same code block or something or in the same control flow. Potential deadlock. Okay. So you said copy-paste errors.
Starting point is 00:22:57 How much trouble can you get in with copy-paste errors that you just said you will find? Yeah. errors that you will find. It's surprising how many copy-paste errors we find almost every day. I don't know if you know that, but we like to check some open source project and
Starting point is 00:23:18 write an article about that. Okay, so here is this error and that error. And copy-paste is usually a huge part of that. People copy paste conditions inside their ifs and they like you do this and this and that and that and you can screw up indexes in your arrays. You can screw up variable names. I've seen a lot of that. If you're initializing a block of
Starting point is 00:23:51 similar variables, many errors occur there. So copy-paste brings a lot of fun. So you can find where you did a copy-paste but only updated two out of the three variables that needed to be updated or something. Yes. And we can also find when you have the same code
Starting point is 00:24:15 in two lines in a block. So, for example, if you have a condition, again, going back to conditions, you decided to check different things and use some logical operator like and, or, whatever. And in this block, you have two lines with the same code, two conditions with the same code. We can find it very well. And we do find it constantly.
Starting point is 00:24:49 Reminds me of some refactoring work I've been doing recently where I have if and else blocks in a client code that were just very, very large. And I started to refactor and clean things up. And as I started refactoring, cleaning things up, I realized that the if and else were actually the same block of code. So I did the same work twice, but I couldn't see it until I had reduced it. Oh, I'm doing a heavy refactoring right now. We decided to clean everything up. And once I believe I made two functions that had exactly the same bodies. I completely missed that.
Starting point is 00:25:33 I want to interrupt the discussion for just a moment to bring you a word from our sponsor. This episode of CppCast is sponsored by the PVS Studio Company. The company produces the same name PVS Studio Static Code Analyzer, that has proved to be great at the search for errors and especially typos. The tool supports the analysis of C, C++, C Sharp, and Java code.
Starting point is 00:25:53 The article, 012 Freddy's Coming For You, which has been recently posted, clearly demonstrates the analyzer's outstanding abilities of searching typos. The article shows how easy it is to make a mistake, even in simple code, and that no one is immune from making it. You can find a link to the article in the podcast description. There's also a link to the PVS Studio download page. When requesting a license, write the hashtag CppCast and you'll receive a trial license for a full month instead
Starting point is 00:26:18 of one week. Since you're talking about refactoring the PVS Studio code, could we ask you a little bit about how you write the actual static analyzer? I mean, is it written in C++? Yes, it's written in C++. We have our own parser and our own AST. And that's not... How to say it better, that was a hard decision because the thing is kind of old and dated and it has a lot of legacy code in it. And we considered to use clan at some point, you know, just to make things easier. Right.
Starting point is 00:27:06 But then we thought, oh, wait a minute. There is that thing called Windows and that thing called Microsoft. And Microsoft has a thing called CLI and CX. And we support that. Okay. And we looked at Clang and thought, there's no way we can make Clang support that. Yeah, so we decided to keep our own parser and our own system
Starting point is 00:27:39 and just upgrade it to new standards and add new features. So how hard is... Oh, sorry. That's why I'm doing refactoring right now, because we've decided to add more abstraction levels. Let's say that. It was lacking. Okay.
Starting point is 00:28:00 How hard has it been to keep up with the changing C++ standard with your parser? Depends on the change. I can tell you that things like if with initializer, it was easy. Structured binding was not too easy, but not difficult. But we are looking at concepts now, and they are kind of scary right now because that's a new thing entirely. And we need to understand everything about them from their declaration to usage.
Starting point is 00:28:37 Please go ahead. No, go ahead. I was just going to ask about that. Are you trying to get ahead? Are you supporting concepts and coroutines, that kind of thing? We are starting to do that, yes. We are trying to do it ahead of the standard release. But if we do it too early,
Starting point is 00:29:03 we can end up supporting something which will change in the next standard version, in the release version of the standard. Right. If it makes sense. So we try not to do it too early, but we try not to do it too late. Right. So you think you should have support for most of the C++20 features Pretty close to the release of C++20? I'm not sure about most features
Starting point is 00:29:30 But we won't choke on the C++20 code for sure Good, that's good One question I have is Obviously it's a professional tool But are there options for open source developers or students? Yes, if you have GitHub, you can
Starting point is 00:29:52 get a free license which you can use with your account. Also there is a kind of trollish free license where you enter a special key, it's not really a key. You just enter free, free, free, free,
Starting point is 00:30:08 free everywhere in the registration form. But you have to add some comments in your code which say, that's an open source or school or something, project BVS Studio, please check it. I think it was trolling.
Starting point is 00:30:24 Kind of trolling. So, if I have GitHub and I want to use it with one of the continuous build environments like Travis or something, is that possible? It's just a command line tool. You can do it.
Starting point is 00:30:39 And we have a bunch of tutorials on Travis and things like that. Okay. So it's totally possible to do it in the cloud environment in your build system. Okay. What are some of the more interesting things you've discovered while working on the static analyzer? Oh, one thing. Once I was doing...
Starting point is 00:31:05 Well, I was upgrading one diagnostic rule about noexcept functions. The thing was going like that. We have a noexcept function, and inside of that function we look for stuff which can throw. So, for example, if you have new there, it can throw. If you have, I don't know, some weird cast between... If you dynamic cast a reference somewhere, it can throw. And functions which don't have the noexcept specifier, they also can throw. But if we complained about every function not marked as noexcept, it would be too noisy. Right.
Starting point is 00:31:50 So, yeah, we decided to look deeper inside those functions and check if they actually throw and so on and so forth. And it worked very well. But at some point our tests went crazy and decided to tell us, okay, this noexcept function calls something which can throw potentially. Okay, I go there, look at the tests and see Windows API calls there. It wasn't a no except function it was DLL main but basically it's the same thing you cannot throw from DLL main okay so I see API functions there and I go like what's going on API functions don't throw anything they are C yeah. They're not C++, really.
Starting point is 00:32:46 Okay, so I'm in Visual Studio pressing F12, and I get into the code of this API function which was used in that DLL main function, and I'm like, hmm, an API function, and I have its source
Starting point is 00:33:02 code, the definition, the body, everything. All right, I look further down. It still doesn't throw, doesn't look like. And at some point, I get to another quote-unquote API function, which calls new. So it was, I don't remember what project it was, but I guess it was some project
Starting point is 00:33:29 which decided to overwrite standard Windows API functions and rewrite them in C++ to place hooks or do something like that. So, yeah. It doesn't make sense, Jake. No, I've seen code, yes, where you, you know, yeah, create your own version of, I don't know what's a good one, open.
Starting point is 00:33:55 Open, I've seen. And so that you can hook any open call and try to intercept that and open something that's been embedded in your library instead of loading from the file system or whatever. Also, people use this technique in stuff like, I don't know, do you know about sweet effects for games? I don't. So basically, there are tools which you can use to add more fancy stuff in your game. You launch an executable, and you use some shaders and maybe even some different germ tree.
Starting point is 00:34:36 So yeah, people often use this technique. They just rewrite standard DirectX functions, put them in a DLL, and place it near your game's executable. And the game, when it calls DirectX library functions, it gets into your DLL and ends up calling your code. So yeah, that's a widespread thing. Yeah, I've also seen that for game overlays to tell you your current FPS or whatever.
Starting point is 00:35:09 Yeah, yeah, yeah. And interestingly, when I first released ChaiScript many, many years ago, when I was Googling around to see how people were using it, I think one of the early users was someone who was making game cheats that did a similar thing,
Starting point is 00:35:24 hooking into dll calls to cheat yeah yeah oh yeah i am curious now at this point after you've spent a couple of years working at pbs studio how has this changed the way you write code personally um i became paranoid paranoid. Really. You start to look at code from the point of view like, what is this thing going to find there to complain about? And then it's not like I'm afraid of it or anything, but some things just... when you see them a lot of times, they just get into you and you try to avoid them. I'm not good at that, I admit, because, for example, dereferencing an all pointer, it happened for me more than once since then.
Starting point is 00:36:29 But definitely I became more careful about what I write. And it's kind of surprising how many things you don't even think about before you take a closer look at what some tool can find in your code. So it sounds like it's definitely made you a better programmer, albeit a more... I don't know if it's better. Well, it also sounds like you still see a place for runtime analysis like Valgrind or the sanitizers
Starting point is 00:37:06 for catching the kinds of things that static analysis isn't best at. Yeah, sure. Dynamic analysis is a huge part, actually, of reliability. I think you should use sanitizers
Starting point is 00:37:21 or stuff like that if you can. Because they just add to your application security stability and stuff like that. Right. And plus, dynamic analysis can catch things that no static analyzer will be able to catch. For example, memory leaks. Let's say memory leaks are challenging, especially if you allocate something in one function
Starting point is 00:37:55 and then it goes around in your program between calls, between functions, and you delete it somewhere else in the destructor or something. Sometimes static analysis can choke on that, let's say. Right, like you would almost effectively have to execute the entire program during static analysis to know if that was ever deleted. Yes, and the most difficult part of that is data flow, because you have to track the state of every variable for the entire control graph.
Starting point is 00:38:33 And if your control graph is branchy, it can become a difficult task. Is it fair to say that simpler, more readable code is also something that the static analyzer can work with better? Yes, to some extent. Okay. You mentioned in your bio that you do give talks at conferences.
Starting point is 00:38:59 Are there any talks online that listeners should maybe look for? Well, the thing here is the conferences I've been to are in Russian. Oh. Well, we have Russian listeners. We do have Russian listeners, yeah. Yes.
Starting point is 00:39:17 I've been to, well, I don't know if I should just list them, but the link, Rob, I sent you to our site. There are videos there with me, and those are not all of the videos, but some of them. And one of them is in English. It was recorded here just to show off, maybe. Okay, I'll make sure to get those links into the show notes. Yeah. Okay, well, is there anything else you wanted to go over
Starting point is 00:39:51 before we let you go today, Yuri? Well, I just want to thank you. It was an interesting experience for me, and it was a pleasure to meet you guys. Okay, well, it was great having you on the show today, Gary. Thanks for coming on. Thanks so much for listening in as we chat about C++. We'd love to hear what you think of the podcast.
Starting point is 00:40:12 Please let us know if we're discussing the stuff you're interested in, or if you have a suggestion for a topic, we'd love to hear about that too. You can email all your thoughts to feedback at cppcast.com. We'd also appreciate if you can like CppCast on Facebook and follow CppCast on Twitter. You can also follow me at Rob W. Irving and Jason at Lefticus on Twitter. We'd also like to thank all our patrons who help support the show through Patreon. If you'd like to support us on Patreon, you can do so at patreon.com slash cppcast. And of course, you can find all that info and the show notes on the podcast website
Starting point is 00:40:45 at cppcast.com. Theme music for this episode is provided by podcastthemes.com.

There aren't comments yet for this episode. Click on any sentence in the transcript to leave a comment.