diff --git a/CHANGELOG b/CHANGELOG index 715dbe1e0f..870b064ad2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,12 @@ Next: + - INT 21h: If a DOS program frees a memory block, and then resizes the + freed memory block, reassign ownership of that block to the program + as if allocated. This is apparently canonical MS-DOS behavior. Added + dosbox.conf option to control whether resizing a freed block silently + assigns ownership (default setting) or whether it returns an error. + DOS resize memory function for the most part DID assign ownership but + not in the case where the size of the MCB was exactly the size requested + to resize to. (joncampbell123). - Sound Blaster: Fix bug where "force autoinit" prevented Sound Blaster playback from working at all, fix for "Jump" by Public NMI (joncampbell123). - Debugger UI now shows PIC_FullIndex() and whether or not the CPU is diff --git a/src/dos/dos.cpp b/src/dos/dos.cpp index 45ce65cb22..57c4987318 100644 --- a/src/dos/dos.cpp +++ b/src/dos/dos.cpp @@ -140,6 +140,7 @@ bool enable_dbcs_tables = true; bool enable_share_exe = true; bool enable_filenamechar = true; bool shell_keyboard_flush = true; +bool freed_mcb_allocate_on_resize = true; bool enable_network_redirector = true; bool force_conversion = false; bool hidenonrep = true; @@ -4110,6 +4111,7 @@ class DOS:public Module_base{ #endif dos_sda_size = section->Get_int("dos sda size"); + freed_mcb_allocate_on_resize = section->Get_bool("resized free memory block becomes allocated"); shell_keyboard_flush = section->Get_bool("command shell flush keyboard buffer"); enable_network_redirector = section->Get_bool("network redirector"); enable_dbcs_tables = section->Get_bool("dbcs"); diff --git a/src/dos/dos_memory.cpp b/src/dos/dos_memory.cpp index ec0952a9d3..52b69ee851 100644 --- a/src/dos/dos_memory.cpp +++ b/src/dos/dos_memory.cpp @@ -333,6 +333,7 @@ bool DOS_AllocateMemory(uint16_t * segment,uint16_t * blocks) { return false; } +extern bool freed_mcb_allocate_on_resize; bool DOS_ResizeMemory(uint16_t segment,uint16_t * blocks) { if (segment < DOS_MEM_START+1) { @@ -349,6 +350,13 @@ bool DOS_ResizeMemory(uint16_t segment,uint16_t * blocks) { return false; } + if (mcb.GetPSPSeg()==MCB_FREE && !freed_mcb_allocate_on_resize) { + *blocks=0; + DOS_SetError(DOSERR_MCB_DESTROYED); + LOG(LOG_DOSMISC,LOG_DEBUG)("DOS application attempted to resize freed memory block at segment 0x%x",(unsigned int)segment); + return false; + } + uint16_t total=mcb.GetSize(); DOS_MCB mcb_next(segment+total); @@ -359,7 +367,10 @@ bool DOS_ResizeMemory(uint16_t segment,uint16_t * blocks) { if (*blocks<=total) { if (GCC_UNLIKELY(*blocks==total)) { - /* Nothing to do */ + /* Nothing to do, however if the block is freed, canonical MS-DOS behavior is to assign your PSP segment as if allocated (Incentiv by DID, party '94) */ + if (mcb.GetPSPSeg()==MCB_FREE && freed_mcb_allocate_on_resize) + mcb.SetPSPSeg(dos.psp()); + return true; } /* Shrinking MCB */ @@ -405,6 +416,7 @@ bool DOS_ResizeMemory(uint16_t segment,uint16_t * blocks) { /* adjust type of joined MCB */ mcb.SetType(mcb_next.GetType()); } + mcb.SetSize(total); mcb.SetPSPSeg(dos.psp()); if (*blocks==total) return true; /* block fit exactly */ diff --git a/src/dosbox.cpp b/src/dosbox.cpp index be1aeb7455..874b7bd96e 100644 --- a/src/dosbox.cpp +++ b/src/dosbox.cpp @@ -4229,6 +4229,10 @@ void DOSBOX_SetupConfigSections(void) { Pbool->Set_help("Enable XMS support."); Pbool->SetBasic(true); + Pbool = secprop->Add_bool("resized free memory block becomes allocated",Property::Changeable::WhenIdle,true); + Pbool->Set_help("If set, and the DOS application resizes a freed memory block, that block will be marked as allocated to that program.\n" + "MS-DOS behaves in this manner, apparently."); + Pint = secprop->Add_int("xms handles",Property::Changeable::WhenIdle,0); Pint->Set_help("Number of XMS handles available for the DOS environment, or 0 to use a reasonable default"); Pint->SetBasic(true);