Something escaping my grasp about memory allocation and the debugger

Mu0n

Well-known member
I've been working on programatically open up a .mid file, parse it to find the minimal MIDI command bytes out of it and set up a data structure that makes it easy to play it back on a System 7 Mac SE/30. All the more esoteric parts of the project have been more or less solved already, but this basic memory related behavior is stumping me.

It may not be the most space-efficient way of storing the MIDI data ever, but it has proven to work in a python version of my project, that I did for fast prototyping. I'm well aware that python consumes lots of resources to make programming more thoughtless and I don't really want to enter a philosophical debate about this.
But, I have a working python script that works on my modern PC machine. See here if you're curious: https://github.com/Mu0n/PythonMidiPlayer

My next step is to make it work in C.
I've got these 3 typedef structs to hold my MIDI data in.

Problem: I can't seem to make internal assignments 'stick' for some reason. it has worked some times by stepping through with the debugger, sometimes stuff like theBigList.TrackEventList[j].trackno stays at 0 instead of taking values like 1,2,3,4,etc.

Things I tried (none worked)
Bump up the project allocation to 1024 K from 384K (but this barely uses it)
clear out the debugger expressions and retype them from scratch from the loop


This is the source of the faulty code stripped down to the bare minimum. I use Symantec C++ 6.0. I'm just adding the standard library of ANSI to get tried and true simple printf outputs to get sanity checks for this prototype. Or I use the debugger.

C:
#include <stdio.h>

typedef struct aMIDIEvent {
    int deltaToGo;
    int bytecount;
    char* msgToSend;
    } aME;
    
typedef struct aTableOfEvent {
    int trackno;
    int eventcount; //keeps track of total events for playback
    int eventleft; //rises when building up, lowers when playing back
    aME* trackEvents;
    } aTOE, *aTOEPtr;
    
typedef struct bigParsedEventList {
    int trackcount;
    aTOE* TrackEventList;
    Boolean hasBeenUsed;
    } bigParsed;
    
    
bigParsed theBigList;

void main()
    {
    int j=0;
    
    printf("hello");
    
        theBigList.trackcount = 6;
    theBigList.TrackEventList = (aTOEPtr)malloc(6*sizeof(aTOE));
    if(theBigList.TrackEventList == NULL)
        {
        printf("ERRORRRRR\n");
        }
    for(j=0;j<6;j++)
        {
        theBigList.TrackEventList[j].trackno=j;
        }
    }

I had to check it out in one of these C sandbox websites. Everything works peach perfect there.
 

Mu0n

Well-known member
so maybe the solution is to use a handle so I can avoid my structs pointers to get trampled over?

seems to work here:
1720713517508.png
 

Mu0n

Well-known member
ok, the same example above, after running back in forth into my main project, rebooting my emulator, etc.

no.
longer.
works.

I bet it's something really easy I'm missing but I'm properly stumped.


this should output 0,1,2,3 in the first 4 trackno debugging values on the right since I'm at index j=4 here.
1720716061615.png
 

Mu0n

Well-known member
MaxApplZone();
MoreMasters();

is a promising avenue being tested atm.

edit - and using NewPtr for those dynamically allocated arrays instead of malloc
and using HLock HUnlock on theBigList....
 
Last edited:

mrw

Member
Add #include <stdlib.h> to bring in the correct prototype for malloc. Without that, the compiler assumes the return type is 2 bytes wide as show in the disassembly (Source -> Disassemble):
symc++malloc-nostdlibr.png

Note the MOVEA.W D0,A0 instruction which moves a word (16 bits/2 bytes) from D0, malloc's result register, to A0.

Here's the disassembly with stdlib.h:
symc++malloc-stdlib.png

Now the instruction is a MOVE.L D0,theBigList+$02, a long word move directly to theBigList's aTOE* member.

Here's a useful Usenet discussion from comp.sys.mac.programmer:
https://groups.google.com/g/comp.sys.mac.programmer/c/cxrmloB0zD0/m/S3e7usifzqwJ - in particular:

"One of the most annoying (and non-portable) features of C is that
unprototyped functions will default to int for all input and output
parameters. The size of int is not defined but is usually 32 bits on
workstations and 16 bits for most PC implementations, and for THINK_C
However pointers for a 68000 will be 32 bits whatever.
This means code running on a 32 bit workstation will work passing
pointers to subroutines without declaring the parameters of those functions
unfortunately THINK_C will not work because it will assume 16 bits is
passed to malloc if not declared to take a size_t (=pointer size (=32 bits))
parameter.The compiler will also need to know that malloc is supposed
to return a void *, otherwise it will assume an integer(16 bits)"

I highly recommend adding comp.sys.mac.programmer to your groups in groups.google.com for easy searching.
 

ymk

Well-known member
Think C 6 has a "Require prototypes" option that would have caught this. C++ might have it as well.
 

Mu0n

Well-known member
thanks all, it seems to work taking 0 chances with:

-using a MaxApplZone() at the start
-using MoreMasters() for good measure (who knows how some .midi files go up in size and data content)
-NewPtr and DisposePtr for those arrays in case a 2nd, 3rd, etc file is loaded up (so I'm currently moving away from malloc)
-HLock and HUnlock for the handle, although that turns out to be pretty small* and could be transformed into a Ptr itself.


*it's only gonna carry a few atomic members and an array of pointers to the other levels of my overall structure. in the worst case, about 20-30 pointers to add on top of that.

The only thing that is staying weird is that using a printf in conjuction with the debugger -- the values I was checking up in the debugger are now displaying the correct values, but printf-ing the same variables while the debugger is halted prints some 0's instead, as if there's a hold up on the character buffer used by printf. That must require some in-depth knowledge about Symantec THINK C that's above my pay grade.
 

saybur

Well-known member
Think C 6 has a "Require prototypes" option that would have caught this. C++ might have it as well.
Excellent, thank you for pointing that option out. I spent a head-scratching half hour last night trying to figure out why a function was returning only the bottom half of a long. Like here, I had a missing include. I had some choice words for why it wasn't an explicit error, explains what I was missing.
 
Top