How to Check Your Pointers at Runtime

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
today i'm going to show you how to check pointers at runtime and prevent your programs from crashing [Music] hey everybody i know you hate bad pointers and seg faults some of you just hate pointers period and you shouldn't please work on that you really need to make peace with pointers but most programmers do legitimately hate seg vaults so today i want to take a closer look at segfaults and show you a little hack that actually you can use to detect whether a pointer is one of those pointers that's about to crash your program and of course we are going to get into code in this tutorial all the source code from my videos is available through patreon thank you all for supporting this channel and i know that some of you may not be familiar with seg faults you may not know what i'm talking about maybe you've seen the message when your program's crashed but you don't really understand what's going on or what that even means so hopefully today i can add a little bit of clarity so a seg fault is simply when you try to access a spot in memory that isn't mapped your process hasn't requested that memory it doesn't have access to that part of its memory space but you try to access it anyway and when you do boom your program crashes this is almost always due to a bad pointer in your program basically you get an address messed up it's corrupted it's null it's it's a value that you didn't intend and then you try to de-reference that pointer and things go bad and over the years i've had a lot of students ask me if there isn't some way that they could check their pointers just because they don't like getting that segmentation fault message instead they'd like to be able to check the pointer and see if it's bad rather than seeing their program crash and for years my answer has been don't do that just fix your code so that it doesn't generate bad pointers because if you don't produce bad pointers you're not going to have seg faults and for what it's worth that advice still holds regardless of what i show you today the best approach to avoiding seg faults is simply to write correct code use tests be careful use asserts basically write code that doesn't produce bad pointers but okay say you don't subscribe to this philosophy say that you don't like good clean correct code or say you're writing a library that's going to be used by sloppy careless programmers and you don't trust them and so you would rather actually return an error rather than just crashing the program when they pass you a bad pointer whatever your reason that's our challenge for today is how do you do that how do you avoid the crash and return an error instead so that's our challenge for today let's jump into the code okay so for this example let's just start with a really simple program and i'm going to create a pointer let's call it junk that makes sense and let's just assign it to something that we know we can't access something like null okay so then if we try to assign some integer value to that memory location this should do the trick so we compile it we run it and sure enough we get a segmentation fault this is pretty simple all i did is i had a pointer that wasn't going to work because it's not mapped null is not a valid address for a process to access so this code gives me a segmentation fault now what i'd like to do is to find some way to check this pointer before i try to use it to see if it's any good okay so for this example i'm just going to make a quick little example function called test ptr that's going to test a pointer now to this i'm going to pass in a void pointer because i just care about the address i don't care what type it is i'm also going to pass in the number of bytes because every time you access memory you're not just accessing the starting address typically you're accessing a range of bytes at that address and so we want to pass in the number of bytes that we want to check so we're actually checking a range of memory locations and then i'm going to pass in a name and this is just so that because what i'm going to do is i'm going to print out the status of each of these pointers so i'm going to print out the name of this pointer along with the address of the pointer and so that'll give us a little more insight into what's going on so this function we're just going to have a printf and we'll print out the name and let's also print out its status which we haven't figured out yet and then i also want to print out the address that we're actually trying to access that'll be handy okay now for status here this is sort of the thing we're trying to get at now what would be really nice is if we had some kind of function called let's say it's called is mapped and you could pass in a pointer and a number of bytes and it would return true if it's mapped meaning that it's not going to segfault or false if it is not mapped and it's going to give me a problem and it makes sense this seems like something that you'd want to do so you think surely a function like this exists and that would be really nice and it would make sense and i wish it were true if it is i haven't found that function so if you know of one that does this please let me know in the comments below i would love to hear about it but there are a few ways that we can get at this information okay so the first is if i were on linux i could look at the proc file system which tells us what blocks of memory are mapped for this process and from there we can check to see if our pointer is in one of those mapped regions so we can do some math to figure out if it's mapped or unmapped i've looked a little bit at also some different tools like vm map and pmap that allow you to see your address space and what is mapped and what isn't so that would work but it's fairly involved and it isn't going to be very portable some of these tools are only available on linux some are only available on mac for example my mac doesn't have a proc file system so this isn't a very satisfying solution we could also handle the sig seg v signal which is sent to a process whenever a seg fault occurs but that's not quite the same thing that's basically handling a crash we want to determine whether a pointer is safe before we try to use it we're not trying to detect that it was unsafe and that we're about to crash and try to recover that's a separate thing that we could try to do it's a little more complicated and maybe it's something that we'll get to in a future video but for today i want to detect the pointer is bad beforehand okay so our third option and that's the one we're going to use today is we're basically going to trick the operating system the kernel into checking this pointer for us now let me show you how this works let's take a quick look at a man page for a random system call let's look at open that should do the trick okay now if i look at the man page for open and if you look down way down here in the error handling section you'll notice this e fault error code and this is going to be really helpful efault is returned anytime the path name points outside your accessible address space and that's exactly what we're trying to find out right so we could pass in the pointer we want to check into open and then see if we get an e-fault error back but there is a problem with that there are a lot of other things that could go wrong and if my pointer points to a file name then open's actually going to do something it's going to have side effects it's going to open up a file and i don't want to open up a file i just want to check a pointer so what we need is a system call that does this efaul check that returns efault if we are going to segfault if we have a bad pointer but doesn't have any annoying side effects and here today i want to show you one way to do it okay so let's come back to our code and let's create this is mapped function like i said before we're going to pass in a void pointer and we're going to pass in the number of bytes that we want to access just for simplicity because it's such a common case let's check whether our pointer is null and we'll return 0 that's a really quick check and often you will see null pointers and so we might as well check that as a special case but now what i'm going to do because what about the other cases what about other bad pointers that aren't null well so what i'm going to do is i'm actually going to use pipes i'm going to create a pipe here okay and the pipe isn't really going to go anywhere it's not going to communicate with anything we've talked about pipes in other videos i'll link to those in the description in case you're wondering but simply what i'm going to do is create two end points so this is a array of length two these are gonna be two file descriptors they're gonna be the read end and the right end of my pipe and then we can just call pipe fd and what that's gonna do is create a new pipe because i need something that i can write to i want something that i can actually try a pointer out on but that's not going to have any side effects and so this pipe i'm going to create it's basically it is a communication mechanism but it doesn't go anywhere right i'm not going to actually do anything with it so i'm just going to create this pipe and i'm going to try to write to it okay so what i'm going to do is i'm just going to write to the second element in this array that's actually the right end so the read end is the first one and i'm going to write from the pointer i'm going to write the bytes from the pointer that we passed in and i'm going to also tell it to write the number of bytes that i wanted to check into this pipe okay so remember it's a pipe going nowhere so there's no side effects and i'm just going to check to see if there's an error if there is an error and if that error is e fault now at this point i need some kind of value here so i'm going to say so let's make a result variable valid we'll start it out as one so it is valid but if we see this then we say valid is zero so valid is not it's not valid and then we're going to exit and then at the end the reason i didn't just return there is we also need to close our pipe otherwise this could produce a resource leak so let's just close both ends of our pipe and we will return valid so hopefully this all makes sense we are creating a pipe this pipe is a pipe that doesn't go anywhere we just needed something we could write to so we create this new pipe it's a temporary means to an end and then we're going to try to write to it we're going to write from this pointer the number of bytes we care about so that is going to cover our whole block and if we end up running outside of our valid memory space meaning we would get a seg fault if we tried to pull this off under different circumstances rather than a write system call then we would get a segfault okay so now let's go back down to main and let's try this out with a few different addresses okay so let's make a another integer pointer let's make this a block of 50 bytes just for completeness let's say we want a pointer to an address that's on the stack like this and let's come up and make one more junk pointer because we'll call this junk two because we're trying to check whether or not we can actually detect seg faults that aren't just null pointers because we had that checkup here we have a null right here we want to check whether this part of the code works and so we need something that's actually going to try that out so let's just make our own custom address in here is the fun of working in c is you can do stuff like this we can just make a pointer okay so now i have a bunch of pointers let's just come down and let's just try out our test pointer function so let's just try the first one we'll just try one byte accessing at null so that's our our original junk let's try our second one junk two so in both these cases you notice that i'm just passing in one byte and so that's just going to check one byte just we're really just checking that address that we're trying to access but then let's also look at some of these bigger blocks for example we want to test out now px that's going to be the size of an integer uh looks like i typed too quickly forgot my quotes because these are supposed to be names and then let's also get pointer p in here and it is also size of an in that's not a size of an int it's going to be size 50 okay 50 bytes because that's what i allocated so we'll check all 50 bytes there okay so let's see how this works so now if i come back in here and compile it good no errors and if we run it let's just look really quick at what we got okay so you notice it's successfully detecting that null is not valid it's not mapped but you notice that it's also able to catch junk 2 so this just random address that i created totally nonsensical clearly not mapped and it detects it okay so it detects that that's a problem but px just fine p just fine no problem so you can see here that sure enough we are able to predict the seg fault causing pointers now note that this is not going to fix all memory errors it's not for example going to detect heap corruption bugs or double freeze or anything other than seg faults but it will allow you to detect psych faults before they occur okay so now that you know how to do this should you no probably not this is a fun and interesting exercise it is fun to see how you can use something like a pipe which was designed for communication between processes or within a process it's fun to see how that can be used as a way to check for seg faults and check your pointers but checking pointers like this is going to be really really slow notice that to do this just involved probably at least four different system calls in order to check one memory access if you do this a lot in your programs to check pointers you should expect things to get much much slower and like i said at the beginning the right answer is almost always just write correct code right clean code right correct code but maybe just maybe there is that one case where you need to handle pointers that you don't trust and crashing really just isn't an option so when that case happens now you know how to solve it so you're welcome thanks for watching check out my other videos if you found this helpful even if you didn't subscribe to the channel so you don't miss my next one and until then i'll see you later
Info
Channel: Jacob Sorber
Views: 12,736
Rating: 4.9883041 out of 5
Keywords: check your pointers, pointers in c, checking your pointers, checking pointers, seg faults, segmentation fault, program crash, prevent program crashes, detect bugs, c programming, programming tutorial, pointers, runtime checking, operating systems, jacob sorber, system calls, software development, software bugs, bad pointers, detecting back pointers, check for bad pointers, c/c++ example, code example, programming example, systems programming
Id: yM9zteeTCiI
Channel Id: undefined
Length: 14min 11sec (851 seconds)
Published: Tue Oct 20 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.