 Anybody have anything about project five homework four if they want to ask questions? Yeah. So in the C file, the compiler dot C when it's reading the data structure once we've built it for if statements, it does not do a PC next. So why is it designed that way? That is the way it's designed. So that's part of the project is you don't have the control of the back end. You know how it works and you know the data structure is there. So you have to create the input to get it to do what you want to do. From its perspective, an inch statement has a condition and then has a true branch and a false branch. And so it does do the next instruction that it executes if that condition is true. It will go to start executing at the true branch. If it's false, it starts executing at the false branch. Those are just the semantics of the back end if statement. Yeah. For the homework, what happens on the stack when you call a print depth function? What happens on the stack? Does that come into play? Yeah, there's a print depth function. We just draw the stack response for it. But what happens when a function returns? Is it going to be on the stack anymore? Exactly. So what's actually on the stack above the currently asking function? You don't know, but you know something about it. If there are other things that are on there. So there's something that called in. So you think about the execution trace. So the function above you on the call stack is the function that called you. And the function above that is the function that called that function. And so on and so forth all the way of the stack. All of those functions above you haven't finished yet. That's why they saved everything for the stack and called the next function. But then once you return, you're gone and you're not on the stack anymore. More questions? Please better than none. One more. Project five. Midterm next Wednesday. So focused on not having class on Wednesday. I forgot. Are we going to have a study guide? We'll do practice. So I'll release probably on Wednesday. I'll do a practice midterm. And then on Monday next week we'll do practice midterm on Monday. And then on Wednesday we'll have the actual midterm. What was the first problem? I don't remember because I just created one and you all do it. What was it? Structurally equivalent. Structurally equivalent. Yeah. What was the question? Yeah. Exactly. Yeah. You should go through that troops table. Assume that everything is structurally equivalent. And then go through trying to disprove structural equivalents as you can. And then just like when we did first and follow sets. And you go through and change something on the table. And you go through again. And you keep doing it until you found out everything that's true. That is structurally equivalent and what is not structurally equivalent. We need some of the variable. It's types, right? So it's all types. Yeah. It's not that big of a computer, right? No. Yeah. You said last class that you were possibly going to keep your office hours on Wednesday as an escalator. Yeah. So that's the other announcement. So I'm going to have to move my office hours today to five o'clock. So instead of right after class I'm moving them five. So five to six. So in response to that I'll keep my office hours on Wednesday. So if you want to show up I'll be there. Anything else? Going once. Going twice. So. All right. So I made a slight change of plans. We're not going to go over Lambda Calculus today because I want to keep you focused. And because Lambda Calculus is pretty in-depth. So we're going to, I don't want to go over it now. And then in two weeks I have to be like, hey, remember that thing we talked about with all these crazy random symbols? And you'll just kind of like, I don't know. So we're going to save that until after the midterm. So to talk about is we've gone, ah, sorry. We went over that. So what are the three types of memory allocation that we talked about when we talked about semantics? Memory allocation. Not parameter passing. Yeah. Well, let's go. So what are the three types of parameter passing? Passed by a name? Passed by what? Passed by value. By value. And then? By reference. By reference. Okay. Good. So those are different ways to pass parameters to a function. So what about the different types of memory allocation? Yeah. Stack. Stack. Heap. Global. Yeah, static. Yeah, exactly. So those are the three global stack and heap. So what have we actually seen so far about how it's implemented? Stack. Yes, please. Somebody said that, right? We went over in depth how the stack works. What about global? Do we talk about global allocation? Kind of. I mean, we looked at it, right? We basically said the compiler puts it in global memory and that place never changes, right? So we did look at that. Do we look at heap allocation? No, not really. What do we know about heap allocation? It's persistent from function to function. Yeah. What else do we know? Yeah. So we have to call the programmer. That's the call malloc or new to get some new memory that persists between function calls. What else? Yeah, the program has to manually deallocate the memory, right? By calling free. So that's kind of the, with great power comes great responsibility, right? It's like, well, here's some memory that will persist after its function leaves. And you can tell me how much memory you want, but you as the programmer, you're saying, okay, I'll take care of this memory and I will free it responsibly. The stack, I think, you share the same area for memory. They just start on different ends and grow in different directions. I'm not sure that we talked about that. Did we talk about that? No, well, it is. It's true, though. Trust me. I know that. Yeah. So, yeah, we're actually going to look at that, but yeah. So they're all in the same address space, right? We really didn't kind of get into that. So we talked about, okay, the programmer was manually asked for memory allocation. The programmer has to actually explicitly release the memory back to the system. Unless it's Java. Right? So unless it's Java, right? So why not in Java? Because it's garbage collection. Garbage collection. Yeah. So Java and other language with garbage collection will, you as a programmer can alloc memory, you never have to free it because the compiler, or not the compiler, but the runtime environment will go through all the memory that's been allocated to see what's being used, not being used, and what things it can free. But that's more of an advanced topic. Because before, we even need to think about that. We need to think about, well, how does C work when you maloc memory? Right? Where does that memory come from? How does it get to our programmer? Because the JVM, right, is using the C language. It's written in C, or C++, I don't really know, but it doesn't matter. It's using that language so that memory comes from the same place. So when you need to call maloc or free, what libraries do you have to include? Where are these functions defined? Are they part of the C language? The C library? Which library? Yeah, standard lib. What are the memory allocation functions? And what do they mean? Maloc. Maloc? What was it? Caloc. Caloc? What's the difference? Yeah, so that's why we're using caloc in the program in some of the code that we gave you, right? So it initialized the memory all to zero. Otherwise, if you just call maloc, you're just getting some chunk of memory. Good. Maloc, caloc, any other things? Or something else? Yeah. Realloc. Realloc. What's the semantics of realloc? Like, it doesn't have to be precise. High-level semantics. Realloc quicks. It's used for when you already allocated memory, that's something before, like allocated to you. Like, deallocated memory. That, I don't know actually. Yeah. When you allocate a memory from the heap and you run out of space, you want to take all that information without having to rewrite it. So realloc will automatically reallocate that entire used memory on back to the larger space on the heap, right? Right. So I think that's the important little difference, right? Basically, maloc, you say, hey, give me 100 bytes. And it goes, okay, bam, here's a pointer to 100 bytes. Do it with it, whatever you want to do. See, realloc says, give me 100 bytes and make sure that they're all zeros. Okay, pretty easy to do that. Realloc says, hey, here's a pointer, increase in size now to 200 bytes. And so maybe it can just do that magically, or maybe it has to find more memory, copy over the previous 100 bytes into our 200 bytes and then resize it and then return that to us. Anything else? Yeah. Free. Free. Yeah, we're going to be able to return them better. What does this make except for free? What was it? Yeah, so if you just pass any pointer into free, why not? What if you try to pass the address of a stack, a variable out of stack allocation into free? Why isn't that a lot? Yeah. I don't think in all cases that can probably be smart enough to detect that. Because you can think about very complicated execution paths with multiple function calls. How is it going to know that? In very simple cases, you can try to detect those things, but programs can get incredibly complicated. Yeah. If heat memory is defined in the same address space as the stack, the heat memory starts at a certain address, won't those functions only be valid for that address forward? Yeah, that's a good way to think about it. Yeah, the kind of, as we've said a lot, right, it's because that's what the semantics are. The semantics of free says, give me a pointer to something that was returned from malloc. Otherwise, I can't do anything with it. And I pretty sure if you try it, there'll be an exception or some expectation fault, which would actually be something really fun to try. But we'll actually look at kind of why that is, that it does grow in error. So, okay, so these are defined in, so they're part of the C standard library, right? They're not actually part of C the language. Kind of like Java has a language and then Java has a standard library, right? Those are two different things. So how many, so what implementation of malloc, calloc, realloc and free are you using in CentOS? What was that? The ones that are installed in your system, right? That's the whole thing. So your program, your regular program uses some standard libraries and those libraries are present on your system. Are these the only ones you could ever use? No. Yeah, there's multiple implementations. In fact, hopefully they'll be so inspired after this lecture that you'll spend all of Wednesday or maybe Tuesday because Wednesday is a holiday so you should be honoring veterans. But on Tuesday, you'll write your own implementations of malloc, calloc, realloc and free. And you can do this, right? Because you can provide these library functions. There's nothing to say, it says that you can't. In fact, there's actually a lot of computing scenarios where you actually really may want to do this. So can I even think of why? Performance, in what aspects? For an allocation pattern, it might be different than the one that's available. Exactly. So yeah, your program has a certain way of allocating memory, right? They're all kind of different. There's lots of little things. There's lots of big things. Is it one big thing? All kinds of ways, right? So you could, when you're doing profiling, you could say, actually, it's a lot of time being spent in here. Maybe I should think about a better way to do that in any other scenarios. Maybe like an embedded system, right? Like a Raspberry Pi or something. It could be that there's not really a lot of memory. Or maybe that has specific constraints. Maybe you actually don't ever want to call these functions, so you want to throw an error when somebody tries to call them, right? So that way they crash. Yeah, what would be another reason? Security, yeah. You could maybe want to do some kind of secure wrapper around these things. I was thinking about that. Because you want to learn, because you desperately need to know how these things work so you want to write your own to understand how it works. All totally legit reasons. Questions? Maybe you have a better idea for a new malloc system that's going to be faster in all kinds of applications. So you'll write your own. Good luck. All right, so now we're going to look at a program. So now I want to say, okay, how do these functions actually work? So to get some idea of that, we're going to run through just some executions of seeing what happens when we call these functions, seeing what they return, seeing what we can learn about them and interacting with them before we kind of dive in and see how malloc kind of conceptually works. And then we won't actually go into how it actually works because this thing's been around for 20 plus years and it's very optimized and it's very crazy, but we can talk about the general concepts. Okay, first thing we got to do, we got to include the standard lib.h, right? Because that's where malloc and three of those functions are defined. We're going to include standard out. We're going to define our main function. We're going to have a local void pointer called test. We're going to have a local integer i. What kind of allocation are these variables? Stack. Static is global. That's why we use different terms. Global stack allocation. Then we're going to find the size as htoi of argv1. What is this doing? What's in argv? What was it? Are arguments that are possible? Yeah, arguments that are passed to the function. From where? From the command line. From the command line, right? Exactly. So you did this in project three. We gave you the code for it, but you did the code to parse in that parameter. So why am I not doing argv0 and not argv1? argv0 is actually the name of the program. Yeah, so you execute the program and what gets passed to the program is the program name in argv0 and argv1 has the first command line parameter if there is one, argv2 has a second if there is one. What's in argc? What was that? Size of argv. Yeah, size of argv. So that that way you know, right? So the program otherwise has no way of knowing how many arguments are passed in. So I'm being super lazy and not checking argc and doing all kinds of fancy error checking. So what's atoi doing? Right, we're going to come a string into an integer in what base? Yeah, by default base 10, I believe. I think there's other ways you can specify different bases. So in effect, what is this allowing me to do? It doesn't matter where this has been used, but we know that whatever I pass it as the first argument on the command line, that's going to be interpreted as an integer by the program and going to be set to this size local variable. It's all nice. Okay, then we've got a for loop. We're going to loop from i from 0 to 10 and we're going to say, we're going to malloc new memory, how many bytes are we going to malloc? 10 times size, why 10 times size? Okay, we're calling malloc 10 times, but just in this call, how many? The size, just the size. Size, yes. You got it, you're saying the right things. Yeah, so we're mallocing size, which is whatever we passed in. So what's malloc return? Remember semantics? What's malloc return? A pointer to what? Yeah, memory address, right? So it's sort of box diagrams. It's returning a new address for a new box that it created for us. All right, and then we're just printing out test. So is this printing out what test points to? It's bringing out the address of the pointer. So it's bringing out the value of test as a pointer. So remember function, so this is why we're calling malloc, right? So c, pass by value semantics. So what gets passed into printf is the value of that address that we just got back from malloc. And then we're printing that out as a pointer, which means printed out in text, so it's easier for us to reach. So this is the address of that memory that just got returned from malloc. Yeah. You would have made test in star the size of the state, the same size it is up there. So what happens if I change this what's star to an in star, change nothing else? What is still the problem? Yes, yes. Because you're allocating, what if I make it to bytes to... What's the type of what's the type of what's the type of what's the type of what's the type of what's the type of what's the type of what's the type of malloc, what's the signature? What's the type of malloc, what's the signature? What's the type of malloc, what's the signature? Yeah, in terms of void star, and I'm trying to cast that void star as an in star. I think you can turn on all the warnings, it should give you a warning. It doesn't give you warnings. It doesn't give you warnings. I thought it was the other way. So you could do that, right? Does that change how many bytes are allocated? No. Yeah, because it's just test, right? So, or size, whatever we're passing as the size, that's how many bytes are allocated. Not... It doesn't matter what the pointer is, right? That affects how we use it and how we interpret that pointer. Is there more? That was it. Did that actually answer your question? Well, I got kind of wrong with it. So it does throw, it throws a warning? I don't know. Maybe not, probably not. C plus plus if there's a warning, and it returns zero. So if I can pile this, is there going to be any errors, warnings, anything wrong with this program? Memory leak. Memory leak, in what way? Because after each time you iterate through, you lose the address of the malloc, so you never get it again. So it's a memory that's allocated and never be able to use. Which is, what is the other term for that? Somebody said garbage? Garbage, yeah. So if you were asked on a test, what would be garbage memory at these places, that would be the answer, right? Because all those nine, ten because they're never free, but yeah, all those nine memory allocations are being allocated and going nowhere. But is that going to give any errors or warnings? No. Is there any complaint that we didn't free that memory? You didn't have enough memory to blow up. You didn't have enough memory to blow up? I'll see, actually. Okay, so it compiles fine. So if I run, if I run it and set size 4, so how many bytes do I want to malloc? Four. Four bytes, right? So those are the pointers that I'm returning. So the first one just returns me whatever. 408A008. So now, what's the next one? The address of the next thing that it's going to return. Is it going to be 804A00C? Why would it be that? Why would I just say C? Because four bytes, right? Because that would be four bytes above this. Or could it be 804A004 if it's going down, right? I don't know. Do we know anything about the heap at this point? Not really. Except that it gives us addresses, right? So okay, let's look at it. So then the next go-around, it returns us 804A018. So what's the difference between these two? 16 bytes. 16 bytes, in which direction? Yeah, we need to specify the direction, but up, right? If we're thinking about the way to stack, the way we lay out the stack, right? So this is what you expected? No. Sort of? What was what you expected and what was it not? Well, it was still like the four bytes difference. The 16 byte difference. Yeah, right. So what's the next one going to be? 804A018 28 23 112 28 And it keeps going like that. All 16 bytes after each other. Until we've gone one, two, three, nine times. Or ten times. Yeah, okay. I'll make sure that I won't make sense. Why does it go up 16? Let's look at 8. What happens if we do 8? So what's going to be the first value that returns? Is it going to be the same thing? It doesn't have to be. It doesn't have to be, why? It could be other stuff. Could be different. Yeah, it could be different, right? There's nothing that says it has to be. In fact, on a modern machine, it's always going to be different for security reasons. A side note is a technology called ASLR, which basically continually shifts the address spaces. Because if an attacker can't predict where your stuff is in memory, it makes their job more difficult. But I had to actually disable that on the system to show this, but when you do disable that, you get the exact same things every time. So this is what it did. 804A008. So what's the next one going to be? So how many bytes am I alerting this time? Eight. What's it going to be? 18? Don't take... I can't, I can't believe it, but if you want to take an imaginary dollar, that's too much. So legal. Okay, so it turns out it's the same. And then above that, it keeps going. What if we increase it even more? Let's say we want to malloc 24 bytes. The first one different? Same? It turns out to be the same. What about the next one? Two eighths. Two eighths? 112? 18? Two eighths. So why can't it be 18? It has a ton of space in between, right? So we said that if you gave me 24 bytes and said, hey, start here. This is your buffer. Here's 24 bytes. And then I asked for another 24 bytes that started at 18, only 16 passed that. Now I've overlapped buffers, right? And so that would be a memory. That would be a very, very bad and really difficult memory error to figure out. So it's good that it's doing this, right? We want it. This is the biggest error we want. Yeah, so that keeps going back by, I want to say twos, but it's really by 32s. Okay, let's crank it up a little more. What about 4096? Is this a reasonable thing for me to request as a program? That's not even that much memory, right? That's like, what, 4K maybe? Yeah, right? That's barely anything. So it's the first one going to be same, different? Same? What's the next one going to be? Stretching, X-Map. Yeah, it's hard. Yeah, so it's actually it will be an 804B010 1804D020 and it keeps going on kind of in this way where it's iterating over the one, two, three, four, the fourth digit but also by two. What if we do something really big? Is it going to cause our program to crash? Possibly. It's going to grind my computer to a halt if it's using all of the machines memory. So what do you think the first thing is going to be the same? A little different, right? What's the difference between those two? I'll just say I don't know what's big. It's very different. So what's the next one going to be? Has anybody noticed a pattern? So what's the other thing that's really interesting about this one? That's decreasing, right? What would be the other ones? Increasing. Increasing, yeah. What's the next one going to be? Is it going to wrap around? Because it's so big it's exceeding the size of the 32-bit number. So this number still less than 2 to 32 is what? 4.7 billion or something like that? It's actually larger than this number. So this is what I did is I started from that number and then divided by two every time until I found a number that worked well for what I wanted to demonstrate. So how do you outfit about 500 megabytes? 5 gigabytes? I don't think this is... I think it's like 5... What does that... I think it's 500 megabytes. Yeah, 500 megabytes, exactly. So that's each time? Yes. So that's the total of 5 megabytes? Correct. So what's going to happen next? So since we're using 32-bit aging stuff, it definitely is doing some weird stuff. What's going to happen next? So you've basically allocated 500 meg jumps all this memory, right? And so with 2 to 32 is what? 4 gigs basically? Something like that? Is that right? So if we're trying to allocate 5 gigs we only have 4 gigs that we could ever possibly allocate not including the area for the stack and the area for the code and all that stuff. So from this pattern are we running out of memory? Because the next one should be decreasing by... It's not 2, but whatever 2 is times 32 at that offset. So what are the semantics of malloc? Let's go back to the semantics. Isn't it crazy enough to be running some version of Linux on the laptop? You want to do man malloc and re-disk the man page of malloc? That's cheating. What does it say? What does it say in malloc? In your best? Allocate size by some in terms of pointer to the allocated memory. What would they do? Good. Perfect. But also too, this is an example right here that with Linux systems it follows the optimistic memory allocation strategy. So this means that even when malloc returns a non-null it will guarantee that the members will be there for the visit. That's scary. Keep reading. What else? Specifically malloc. Okay. If the size is 0 then malloc returns either null or you keep pointer value that later may successfully pass to free. Okay. Also weird. Continue. That was for the malloc line. So the malloc and callum function return a pointer to the allocated memory for any kind of variable. Okay. So that means it's going to align. It's not going to give us like an odd memory. It's always going to be, I think, 8 by the line. It's actually what part of it we can see here. And then it says odd error these functions return null. So on error these functions return null. So what would, trying to ask for more memory than the system can give you? Should return null. Yeah. Should return null. So is that going to crash our program? No. Why not? Should it just be a null pointer exception? What was that? Yeah, I'm not. Am I ever dereferencing test? So it shouldn't throw an exception, right? It should just output null. Which it does. Which is weird. I didn't know this program could do this, but I didn't know how to print out this. So this is all on set OS 6.7. Everything you guys have been using compiled for 32 bits. So it returns null. And then what happens I'm going to call it again. So null. Done. So our program actually didn't crash. Because Malak actually has a way to tell our program, hey, something went wrong and you didn't actually get the memory that you thought you were going to get. So should you be checking for that and your code that you're writing? What was that? What's your thoughts? Well, typically if you can't get the memory then you're not going to be able to do what your program wants to be doing anyways. So it would be almost better to just let it crash and not. Yeah. So it's a tricky thing, right? Because it's like, well if my program needs this memory to run, which is why I'm asking for it, if the system can't give it to me then how can I just continue executing if I don't have that memory that I need? On the flip side, if you don't actually check for it and die there, maybe it dies later in another function so it's hard to tell where that memory couldn't be allocated and why you got a null pointer to this specific variable. Yeah. Yes. So yeah, if you want to die and quit, right? You could call a cert or a bore, there are all kinds of functions, exit. Those functions themselves may want to call malloc and call printf to print out some debugging things, but your system's out of memory so maybe you'll crash while you do that and then you have this weird thing of like, why is the system that exit crashing? That doesn't make any sense. So yeah, it's actually a really big problem. One way you may think about maybe like a database or something wants to use as much memory as possible so like tries to malloc a large chunk of memory and keeps, when it can't get it it keeps going smaller and so it can finally you know, you think about maybe if it's not something that you desperately need but you're trying to reserve that memory maybe in that case it's nice to know that you couldn't get it but yeah, it's one of these really weird kind of edge cases where it's like it's kind of like a Java when you catch that exception when you write out like system.out or when you read in and something like that is how it is, when you read in you have to explicitly either throw an exception or catch that exception now do I not know what I'm talking about? So it's like well, what are you going to do if you can't read from the keyboard like what could you possibly do your program's never going to execute? Thanks, that's one of these cases. Okay, so what do we learn about the heat from this little exercise? Heat can grow both ways Up and down Yes, that actually is really weird I have theories but we have to go through it What else did we learn? But mainly what did we see? It grow Up, yeah, so we saw it growing in up addresses it would keep returning that addresses higher up in memory What else did we learn? That has a minimum size that it will allocate It's allocating at least 16 bytes even if we only ask for 4 bytes and it allocates the same thing even if we ask for 8 bytes You're going to get a decent amount of memory out of the system, which is kind of nice if you need it Anything else? Does it always increment in the same way like it went from 16 to 32 and to 64 It seems like many of you Seems interesting Okay, so it helps too We're going to look at the kind of memory layout we're even looking at From all of our diagrams of memory what's at the top? What address? The highest one, all Fs, right? I'll say it since I made you all say it F, F, F, F, F 8S What about the bottom? 0, 0, 0, 0, 0 Yeah, or just 0 Same thing So what's at the top of the stack that we've been talking about? What was it? The base pointer Yeah, it's part of it Color functions also A big region of memory that Stacked Stacked, right? And which way does the stack grow? Down So the heap actually is then below the stack in the lower portion of memory And so the stack's growing down Which direction is the heap growing? Up, yeah it's kind of cool So you kind of start the stack up here and the heap down here and then they kind of grow as need be and if they ever cross you're going to have massive problems and everybody's going to go to heck Or the code of the program in the summer Yeah, the code of the program is usually I believe actually below the heap It's usually somewhere here at least in the normal allocation but there's nothing special that says it has to go in this specific location But yeah, you definitely don't want to put it in the middle right? How would be bad if somebody could override it? Oh, Mike went out Hello Is this what that red battery light is? Always fun changing a 9 volt battery Alright Questions while I do this? I don't even know which way to push Okay Do you feel pressured? Yeah, I do actually Oh, there we go, got it Salted it This is why a lot of them That's a red battery 50-50 chance Oh no, which one was which? I think it's this one Okay, how about now? Hello? We have one half of a bar Otherwise I'll just start shouting and it'll be really awful Okay, great So, how does this actually happen? So is malloc moving this stack up? Yeah, there's a question? You couldn't ask while I was doing the batteries It gave you time to think I'm just teasing So what if your last program you took up all the space on the heap and we run some infinite recursive program that takes a place on the stack What would that be? You're gonna crash at some point Yeah There's no space on that Exactly, there's no space anywhere so you're gonna run out of room at some point and something's gonna crash Yeah, we're exactly at crashes, that's a good question Okay, so is malloc doing this? Is malloc moving the stack for us? No No? Is that what the mandate tells you? Yeah, it says that program called svrk is Okay, not a program Okay, so yes, so it turns out malloc itself doesn't actually control the stack which is kind of crazy when you think about it but so what actually happens is there's a system call so the Linux OS has a function called svrk which will increase the size of the heap or alternatively, if you get a negative number will decrease the heap and it's defined in this header file and this is the signature so you call svrk, you give it an increment how much you want the stack to move and it'll return a new pointer to that, I believe the old location so you'll get the it will actually move the heap and allocate memory for you and it'll give you a pointer to that last location so this is actually nice in some ways in that malloc is not doing anything special, right? malloc is not allocating new heap it's actually just asking the operating system to allocate more heap so let's look at how that works we have pretty much the same program I'm going to loop the same thing I just added one more local variable called current break I'm going to call malloc so I'm going to malloc the memory and then I'm going to call sbreak0 so it was sbreak0 this is awesome, we have our human man page so this will return a pointer to the current location of the heap so I'm passing 0 so I'm not changing it but I could if I wanted to right? it's just a system call I can make that as a program or malloc can make it on my behalf and then I'm going to output what we got back from malloc and the current break the current location of the heap then we're going to return to this is kind of an off topic but can you say it's a Linux system call but it worked obviously in location functions on other systems so SBRK works on all systems then? not necessarily so the malloc implementation has to use this is one of the nice things is that abstraction means that you can write a general malloc that can operate if it has a function to ask for more memory from a stack so on Linux it's SBRK on Windows they have some other way to do it I don't know exactly what it is and on Mac OSX they also have I think probably different and similar Mac OSX is weird so I won't get into it but yeah so yeah this is all just defined so you can do this okay so is this going to give any errors? good morning I hope not right so it's pretty much exactly the same except for the addition of one local variable one function call and slightly changing the print statement right okay so let's run this with four so let's see address that malloc returns is it going to be the same as what we previously called for? doesn't have to be true doesn't have to be except every process sees its own memory so we don't have to worry about any other processes that's what the operating system handles for us let's SBRK is it going to return the same thing that we just malloc I think it's going to be the same so malloc when we call it it says okay they need 16 bytes and then let's move let's first move SBRK up change that and then return that memory to them okay so this is the same right so malloc returns is the same it makes sense right it's pretty much the exact same function and we've removed ASLR so that doesn't change at all but SBRK returns something much higher up right so what happens so now when I call on the next iteration what's malloc going to return 18 what do you think about SBRK what's it going to be same? why the same what does this effectively mean what's it what does that mean right so when I call malloc it seems like it moved it reserved a bunch of memory from the system and then gave me 16 of those bytes at the bottom and the next time it gives me the 16 bytes after that and then the 16 bytes after that and so on and so forth all the way through and it never actually has to move and ask for more memory from the system because it's already got you know we haven't we haven't crossed this threshold right we've only allocated maybe this much of that memory something like that so why would it do that why would it reallocate that memory chump is reserved for this program it's easier to read sequentially it's all here it also takes more time to if it only allocates that memory once I'm allocating it again right so we think about it even if it's relatively cheap I still have to go from my process to the operating system to ask for something it does whatever things it does and then returns me back more memory right that's a lot more than when I'm calling malloc so that's a quick very quick function call so it's actually it's a lot slower to go to the operating system than it is to come back for various reasons you'll find out in your operating systems class basically the first time it goes to the it doesn't operate into some call and the rest of the time it doesn't unless it preallocates it even when it initializes they could have some malloc initialization thing I'm not exactly sure if that happens or not C program will explicitly have a memory on accident it'll still free it does have to do with that like in a way when we stop running we stop running our environment or something like that anything that we forgot to free will be free correct because the OS knows this is that function this is that program's memory bam throw it away it's all gone it can be reused that's sequential is it is that sequential in space have to do with that I don't think so I think it's mostly just performance we all need multiple times right so I might as well store some memory and however much this is that's not that much 10 megs or something on a modern system that's like nothing I don't know very much just guessing but you know reserve some memory and if they use it if they stay within that then I never have to bother the operating system again okay let's do bigger what if we do bigger 1024 okay so same boom boom boom boom boom boom so we still here stayed within underneath that that's great alright let's make it a little bit bigger oh no I didn't okay so 4096 this one's actually very interesting so is the s-brake different yeah but it actually did it the first time it actually allocated more memory based on our first request so these things are very smart or maybe not depending on how you look at alright let's bump it up even more alright so here I'm asking for I don't remember what power of 2 this is 10 something like that 16 16 okay cool so it returns the same pointer again for malloc now s-brake is 807B00 and then it increments goes to 805 806 and now it's going to have to call s-brake because I want more memory than the operating system has allocated to it and so when we do that we can see that actually it goes and gets more memory and then gives some of that memory to me keeps that while it services more requests and then when it runs out and it says oh we need more questions on this? oops so that's part of the semantics of s-brake so it basically starts here and it says okay give me whatever your system can say increase this deep by 100 so it can increase it and that says okay all of this is now yours and you say increase it 100 again and it increases all that so you have to all continue this memory because you can only increase it or decrease it those are the only two directions so it's not available in old era basically like s-brake will throw it s-brake will signal to malloc and it can give it the memory and then malloc will return it all exactly so we can see from this we learned that malloc is calling s-brake to request more memory so that's pretty clear right but then what is malloc returning to us as programmers that's the definition of some of the memory that it requested so how is that actually being freed so think about it so now we know that malloc is not doing anything special right all it's calling is the system call to ask for more memory and it can increase it up or down but now when we pass this thing back to free what do you think about how does that actually get freed and deallocated what do I have to do so to do that let's look at an example okay so exact same thing but I'm going to call I'm going to free test so I malloc something now I fixed my oh no there's a a memory leak in my program I'm creating garbage so I'm going to free that so exact same thing so now I run it with 4 bytes what's the first thing it's going to return at 08 the same thing are you going to change anything not the first time it better not because nothing changed up to that first call to printf they're exactly the same and we can see that this is the exact same memory address so next time through what's it going to malloc what address is it going to return the same one a different one something 16 above it depends on the malloc depends on the malloc it's giving us no qualms about what it's doing but of course we're kind of peeking under the hood a little bit right by printing out these pointers so yeah we can see it actually reuses it and it just keeps reusing that memory and saying okay well this because when we pass that pointer back to free what did we tell malloc what was it yeah we're no longer using it right we're no longer using that pointer that you gave us so you can reuse it now but is it freeing the entire chunk that SPRK return what does this say telling us whether that it's I guess not because it's it's one of the same starting right it's staying right there right so it's not ever decreasing this makes sense because it's the first allocation to your larger point I actually don't know I mean shouldn't if you weren't using any of that larger chunk that SPRK gave you shouldn't have this system you all just agree that it could yeah it could okay so this is interesting it does that so let's do more memory so we always want more so now what's the next one it's going to be the same, different same yeah great it's really lazy so you tell but notice here so what's the difference between this and the previous example I think it's actually the same yeah same ooh this is nice I like that so what's the difference here there is none there will be some differences am I running these programs exactly the same the same memory is still being free so the same memory is still being free but how much memory is being free 1,024 in this case and how much in this case so how does it know so look at another example okay we're going to slightly change this and we're going to say every odd iteration we're going to free tests so we're only going to free half the time okay we're going to compile it it's going to qualify and we're going to now lock 4 bytes so now okay we're going to do the same thing what's the next one going to be are we going to free what's I on the first iteration is zero odd is zero even yes so we're going to free so then what happens the next go around will be malloc memory same okay oh wait now when we call malloc now what memory is it going to give us 18 because we didn't free that now we're going to free this memory right because this is the 012 2 is even so we're going to free that so then when we come back around when we call malloc what memory is it going to give us is it going to give us 08 why not still being used exactly so it's going to reuse that 18 and then the next one is going to give us 28 and so on and so forth I don't know I don't want to be an example okay so but how did I know so I didn't know to only free 4 bytes here and not to free 1024 bytes yeah because we told it to right when we called malloc we said malloc 4 bytes and so it has to have some way of knowing to associate 4 bytes to that pointer so what's actually happening we'll get into a little bit is it's doing some internal bookkeeping and that's why it doesn't just allocate exactly how many bytes you asked it to it allocates some bookkeeping bytes too so it can keep that size in there in that memory that it gives you in a place that it can find it later okay so we need to do this so we're going to call malloc and free so these are the these are the semantics so how would you do that so what would you use with malloc to increase the heap size sbrk alright you use sbrk and you just return the pointer that sbrk returns right so hey here's a memory book what about to free let's say you want to free something but what would be something simple that would be the opposite of what you just malloc sbrk minus to some negatively alloc size but the problem is you need to know that size so you need to using this pointer that you returned from malloc you need to somehow be able to get that that size that you created okay so the way it's actually implemented and this is kind of generally for all malloc implementations you always want to reserve more memory than requested because you want to have some overhead some bookkeeping bytes and you store that size that was that was requested in the malloc had some fixed offset from the pointer so that way when somebody calls free and gives you that pointer you know you can look at a specific offset to find the size of that pointer that kind of make sense where's the fixed offset exactly I mean it depends on the malloc implementation could you put it right at that could you put it right at the beginning let's ask so how is this pointer used yeah as a program right so if you return an int star into some variable x you malloc four bytes put it into x you can say star x is equal to something right and we'll store that value in there so can you store the size of that pointer that you return no because specifically the programmer can mess with that right you're returning a pointer to that start of that new memory that they can use you're saying use this go ahead do whatever you want but you could put something in front of it or behind it it kind of depends on how you think about it but yeah so what if we did something like this so let's create a struct we kind of adapted this slightly from the real malloc implementation that's on sento s67 this is actually the very nice thing about using Linux and all that fun open source stuff because when you have questions like this like how does malloc work you can actually dig into the source code and it is actually very well documented you can actually just read it it's pretty legible so we're going to create a structure right this chunk and that's going to be internal to us from our malloc and we're going to have a field called size this is what we care about this is that size that we need to keep track of and then we're going to keep after that is just going to be a void star we're going to call buff trying to think I may have made a mistake but that's fine so when we define malloc we have to follow the signature if we don't follow the signature we're going to do malloc doesn't this answer my question about assigning an arbitrary size to instar since you're right there you're kind of just making the size of the star arbitrary without actually knowing what type of variable to be assigned to exactly so yeah this is why when you request memory and malloc if you want to malloc like an array of integers say you want to allocate 10 integers you do 10 times size of int and it'll give you a pointer to 40 bytes that you're free to use and you can walk over all those 40 bytes and access all of those integers but the programmer doesn't have access to this size that you gave it this is our internal structure what we're going to do is we're going to return to them basically a pointer to buffer and that's what the programmer can use but we're going to keep the size right above that pointer and they're never going to know because they can't they shouldn't have access that memory okay so we do some stuff in malloc or initializing things whatever it's actually very complicated but there's actually really good simple malloc implementations you can go read there's I don't know all kinds of stuff this is not crazy out of the world I don't know it is not rocket surgery or science yeah so this is basically what we're going to do this is kind of in our very simple stupid malloc implementation we're going to say okay we need more memory so we're going to call sbreak to move increased memory right from the operating system and we want size right by size what was that that's how much the programmer wants so we have to at least get that much bytes that many bytes otherwise it's bad but then we're also going to ask for a little bit more we're going to ask for a size of this malloc chunk which I think actually we'll ask for eight bytes which is not exactly what I want but that's fine but we're a little bit overhead here so we're getting more bytes than we asked for and now we need to store the size that they gave us right for this point so we're going to store in this new memory the size that we gave is the chunk size right makes sense we want to be able to access this later but now the question is what do we return to the programmer yeah exactly so we want to return so what is new memory pointing to let's think about it what is a struct in C a location a struct I'd say is like continuous continuous data right so we know it's size a size T which is just basically an untimed integer or actually maybe a signed integer those are not actually the purposes it's four bytes a size and then four bytes of whatever a void star we actually don't care about that at all but what is a new memory point to the start of the structure right so if I dereference the start of the structure the start of the structure but I'm storing the size in there right so I definitely don't want to return that because then the programmer couldn't overwrite that what I actually want to do is return then that memory address that's right that's four bytes after this pointer that I just got which will point to where buff is and so this is actually I did lift this directly from the docks the actual code adapt it a little bit okay so what is this doing let's unpack this it's taking new men and it's casting it to a character pointer is that valid you can cast right it's an explicit cast the programmer can do that so then it's adding size of size T so what's the size of size T how many bytes four so why did it do this care star addition here because aren't the addition to a current increments of one yes exactly so we know that if you have an int star and you increment it by one how many bytes does that move the pointer size of int yeah exactly normally four bytes and that's why you can use basically a pointer as an array is you can iterate over that pointer incrementing it by one and it's going to increment however many the size of that pointer is bytes so if I did new men plus one where is that going to point to what was that yeah eight bytes afterwards right that's going to point to eight bytes into the s break which is not really what I want I want to return this this address here so by taking new men casting it to a character pointer now I know I'm incrementing by bytes I'm talking about bytes so I'm going to move that pointer forward size of size T which is four bytes I'm turning that so now the programmer can use that their pointer is going to point to right here and they can use all of those size bytes and we've allocated more than enough memory for them so they'll be fine as long as they stay within those bytes is there a specific reason why these types of protocols and other memory allocation protocols use size T instead of int yes but I don't know it off the top of my head maybe else knows to be more clear I would say it's just the largest size integer okay I think it's sine I don't think so yeah I don't know so you're going to have different invalentations do things so you're going to have to see the same code you can change the pound defines the different integers because you have ints of different sizes 64 bit integers but sizes be different this oh this it's not necessary correct but it actually gives you a way to talk about that memory that's located there they actually don't do it exactly like this but you can so you've got to think about it what are we returning here basically we're returning a pointer to this buff star to the buff which is a void star so now we're free with this pointer what do we get back are we getting a malloc chunk a pointer to a malloc chunk no what are we getting a pointer to buff yeah exactly so how do we get back so we want to take that pointer that they give us and where do we want to move that pointer up four or down four decrease it by four which put it into the structure but now we want to move it back up four so we're pointing to the start of the structure so yeah that's exactly what it does so to take that memory they give us and turn it into a chunk they take that pointer cast it to a pair star again and subtract size of t and now bam we're back to that memory that we called s break on and now we can get the size to free right now we know exactly how many bytes they asked for when they allocated it we gave it back to them and now we can do other stuff we can call s break so what is the big problem with this way we've done it here where we call s break every time they give us memory and then we just call minus s break every time we want to free memory what was that it takes time yeah what else right exactly the way we were doing it right you malloc malloc malloc we want to free the very first thing that I'm out right if I'm just moving the s break pointer the heap I'm going to accidentally free all that stuff or not free that stuff right it's going to be a problem so you can think as the heap only grows up or down right but it's not the heap can't just free one thing that's on the bottom yeah exactly is the question yeah so that's the thing right so this is kind of super simple malloc but even that's too simple to actually function because we need to be able to free something that's not exactly below us and let's say you allocate a bunch of things right there on the heap in this order and then you free from bottom up free free free well now maybe what we're talking about maybe I want to call s break and free all that memory but how do I know that all that memory is actually be allocated by the programmer so this is kind of a very high level of how it actually works so the basic idea is so it's going to call malloc s break to move the heap up some size and that's going to change the heap and the program malloc gets a pointer to the start of that new memory and then what it does it actually not only thinks about chunks in terms of memory that it gives the programmer it thinks about chunks also in free space so it says I have this whole space that's free so I can say hey I've got a free chunk I know how many bytes it is because I know exactly how many I asked for from this offset so I know this is the many bytes I get great so I know this is all free and it keeps the pointer to basically let's say the first free chunk then when the program asks for a chunk it splits the free chunk into two chunks and says okay how many bytes did you want great 4 bytes okay I need 4 bytes plus 24 bytes for overhead so I'm going to actually allocate 16 bytes so 12 bytes overhead so 4 and 16 so I'm going to allocate this but I've picked a pointer to this and so when I want to I may want to go to the next one so it actually uses a doubly linked list each of these chunks of memory has pointers to the next chunk of memory and has pointers back to the last chunk of memory and each chunk has a little flag that says if it's free or not so when it needs to allocate more memory it goes to the first element of this list it's actually more complicated but conceptually it goes to the first element and says okay are you free no you're not free okay great go to the next one hey this one's free is there enough memory here yeah it's a tiny request so bam split this up allocate some more memory here make new pointers make the pointers all nice and now when we want to free the first memory we know exactly how to do that right because when we the programmer says I want to free this chunk of memory and we go okay great I can tell from this chunk of memory the size that you've allocated and I have pointers to the next memory and the previous memory so I can make myself free and in this case I'll just do that and then if somebody if they want to allocate a small chunk of memory in here well I can say okay is this smaller than this chunk I already have and now I made more pointers in here so all this is all this list we're just keeping track of what memory is free how it can free things how it works on if it needs to do more it'll do more all that kind of stuff so anyways lots of cool stuff yeah it's really interesting modern malloc is very complicated they keep different buckets for different sizes of memory so that made me why when we asked for a lot of memory it actually allocated a bunch and then gave us back from that but anyways great I will see everybody in a week