Programming thread

I feel very nervous patching specific issues with a hard coded solution. It's like having a flaw in your plumbing system and just putting duct tape over a leaky pipe. When is it better to hack a quick fix v.s going deeper into the actual system?
 
Scope-Bound Resource Management
This is a much better name for it.
I feel very nervous patching specific issues with a hard coded solution. It's like having a flaw in your plumbing system and just putting duct tape over a leaky pipe. When is it better to hack a quick fix v.s going deeper into the actual system?
Time permitting.

Your code should be as data-oriented/functional as possible within reason, but it's hard to say what/how/if it's worth it without knowing what you're getting yourself into.
 
I can't believe I've never read about this, it would be ideal for the temporary string buffers you often see popping up
Isn't alloca how local variables are allocated on the stack? I've always used (variable length) arrays of chars for buffers, ex:
C:
char temp[1000] = {0}; // should be the same with alloca & setting everything to 0
or in variable length form:
C:
char temp[n] = {0}; // same thing
 
Isn't alloca how local variables are allocated on the stack? I've always used (variable length) arrays of chars for buffers, ex:
C:
char temp[1000] = {0}; // should be the same with alloca & setting everything to 0
or in variable length form:
C:
char temp[n] = {0}; // same thing
Yes.
DESCRIPTION
The alloca() macro allocates size bytes of space in the stack frame of the caller. This temporary space is automatically freed on return.

You weren't always able to do the variable length form in earlier versions of C. Tbh it's still not the best idea compatibility-wise. Nevertheless, it's the same mechanism but treated slightly differently.

BUGS
alloca() is machine and compiler dependent; its use is discouraged.

alloca() is slightly unsafe because it cannot ensure that the pointer returned points to a valid and usable block of memory. The allocation made may exceed the bounds of the
stack, or even go further into other objects in memory, and alloca() cannot determine such an error. Avoid alloca() with large unbounded allocations.

The use of C99 variable-length arrays and alloca() in the same function will cause the lifetime of alloca's storage to be limited to the block containing the alloca()

As a side note, the first form you gave with the explicit size (1000) is able to be allocated on the stack in a way that can be determined at compile time. For variable lengths, more trickery has to happen to fit everything in the stack frame without problems. Dynamic arrays and buffers are typically done through a strategy involving amortized constant time, which is like a statistics trick that limits inefficiencies of array resizes by spacing them out adequately.
 
Last edited:
When is it better to hack a quick fix v.s going deeper into the actual system?
Depends on the operational parameters of the system. In production, our old pattern used to be: identify problem -> triage -> if urgently needed, hackfix -> schedule improvement -> develop improvement -> test. The "quick fix" branch of logic will be logically proportionate to the impact of the issue. Duct tape may stop a minor leak until you can turn the water system off to fix a problem, or maybe not if the leaky pipe is pressured.

it would be ideal for the temporary string buffers you often see popping up
Generally well-intentioned. The question with a "temporary string buffer" is "just how much do I actually need?". You can blow your stack limit rather quickly trying to mangle a 1MB string in certain ways. OTOH, maybe you're dealing with filenames so you know PATH_MAX, and you only need ~4K.
 
Story from the frontlines today:

We had one of our cronjobs fail during ingestion. When I pulled up the logs, an insert had failed because it was attempting to insert a null value for the LastName column but the column isn't nullable. Pulled up the data in question and sure enough - no last name.

This system handles pre-employment data so I couldn't take the user's SSN into our lookup to get their last name. So I have to email the team in charge of that stuff and ask them if they can look him up. Luckily they're able to look this guy up and give me a last name.

That last name? Null
 
Story from the frontlines today:

We had one of our cronjobs fail during ingestion. When I pulled up the logs, an insert had failed because it was attempting to insert a null value for the LastName column but the column isn't nullable. Pulled up the data in question and sure enough - no last name.

This system handles pre-employment data so I couldn't take the user's SSN into our lookup to get their last name. So I have to email the team in charge of that stuff and ask them if they can look him up. Luckily they're able to look this guy up and give me a last name.

That last name? Null
I'm naming my kid SELECT * FROM Main WHERE Name=""; DROP TABLE *; -- "
 
Isn't alloca how local variables are allocated on the stack?
I ended up looking into it more after I first posted and yeah, the only difference I guess is that you're less likely to try and return the pointer?

You can blow your stack limit rather quickly trying to mangle a 1MB string in certain ways
For me it's usually when I'm trying to format my own structs as strings or whatever, there are times snprintf or strncat on an existing buffer just aren't enough
 
Story from the frontlines today:

We had one of our cronjobs fail during ingestion. When I pulled up the logs, an insert had failed because it was attempting to insert a null value for the LastName column but the column isn't nullable. Pulled up the data in question and sure enough - no last name.

This system handles pre-employment data so I couldn't take the user's SSN into our lookup to get their last name. So I have to email the team in charge of that stuff and ask them if they can look him up. Luckily they're able to look this guy up and give me a last name.

That last name? Null
It reminds me of this story from a few years ago: https://www.wired.com/story/null-license-plate-landed-one-hacker-ticket-hell/, https://archive.is/R1FMz
 
A lot of my time spent, back when I was learning how to program initially, was on learning Java; and as someone who spent most of their time programming in java and python, I always liked how I could split off a class and its constituent methods into a file if I felt it got too big for the first file or whatnot. Does C have something similar? I know it has header files, but I don't think those are quite the same...
C headers are just interface declarations. You can split your code over however many files you want in C, so long as the declaration order makes sense to the compiler. You can even put each function into its own file, its encouraged for library type code if not all functions are expected to be used, like glibc, resulting in the linker only pulling in the object it needs without requiring LTO analysis. In Java, the compiler scans the class files for how a method is declared in a class. In C, that information comes from header files. Same for C++, which chromium is infamous for because its a big fat piece of shit code.
I can't believe I've never read about this, it would be ideal for the temporary string buffers you often see popping up
Its fast but the danger is that there is no way to communicate a failure, like running out of stack space and colliding with other data. It NEVER returns NULL, especially dangerous if you use recursive calls.
Isn't alloca how local variables are allocated on the stack? I've always used (variable length) arrays of chars for buffers, ex:
C:
char temp[1000] = {0}; // should be the same with alloca & setting everything to 0
or in variable length form:
C:
char temp[n] = {0}; // same thing
If you know the size of an array ahead of time and you're not doing any multithreading, you can just declare the array outside the function scope to avoid stack problems completely. Be sure to memset it as necessary, or just use static if you're using it just once.
Yes.


You weren't always able to do the variable length form in earlier versions of C. Tbh it's still not the best idea compatibility-wise. Nevertheless, it's the same mechanism but treated slightly differently.



As a side note, the first form you gave with the explicit size (1000) is able to be allocated on the stack in a way that can be determined at compile time. For variable lengths, more trickery has to happen to fit everything in the stack frame without problems. Dynamic arrays and buffers are typically done through a strategy involving amortized constant time, which is like a statistics trick that limits inefficiencies of array resizes by spacing them out adequately.
I always get worried with variable length arrays in the stack, since its the prime candidate for stack spraying and smashing attacks. It can result in program control being passed to arbitrary functions.
 
not sure if im breaking any rules, i looked around for another thread dedicated to programming assistance and found none so excuse me if im derailing the thread or breaking any rules
im working on a traditional roguelike in pygame. iev gotten to the point where id like to add doors but can seem to figure it out. i figure i can use the fact that the program already knows the center of each room created in order to make the hallway and some how use that to place the doors in the right place but i cant seem to figure it out.

Python:
def generate_map():
    #This creates a map filled with walls to be carved later
    game_map = [[TILES["WALL"] for _ in range(MAP_WIDTH)] for _ in range(MAP_HEIGHT)]

    # this stores the rooms
    all_rooms = []
    num_random_rooms = random.randint(10, 20) # Adjust as needed
 


    # generates the rooms
    for _ in range(num_random_rooms):  #sets the ammount of rooms per floor may make random later but for now we move
        width = random.randint(4,8)
        height = random.randint(4,8)
        x = random.randint(1, MAP_WIDTH - width - 1)
        y = random.randint(1, MAP_HEIGHT - height - 1)

        new_room = {"x":x, "y":y, "width": width, "height": height}

        #checks for any over laps before placing the rooms hence the omega long parameter
        #the any parameter checks if all the conditions inside it to see if any are true or false
        if not any(
            (new_room["x"] < room["x"] + room["width"] and
            new_room["x"] + new_room["width"] > room["x"] and
            new_room["y"] < room["y"] + room["height"] and
            new_room["y"] + new_room["height"] > room["y"])
            for room in all_rooms
        ):
            #this is wwhat carves/ places the rooms with athe help of the dreaded nested for loop (doctos)
            for y in range(new_room["y"], new_room["y"] + new_room["height"]):
                for x in range(new_room["x"], new_room["x"] + new_room["width"]):
                    game_map[y][x] = TILES["FLOOR"]

            all_rooms.append(new_room)

    #this is what connects the rooms wth corridors
    for i in range (1, len(all_rooms)):
         # is i-1 because its the previous room, could also have made it so the current room is i +1 and make prev room be i but that makes less sense intuitively
        prev_room = all_rooms[i -1]
        curr_room = all_rooms[i]

        #grabs the centers of each room so we knwo where to put the corridors
        #standard stuff getting middle by adding and then dividing by 2 really if you need this reminder comment you should n be programming and should consider killing yourself
        prev_center = (prev_room["x"]+ prev_room["width"] // 2, prev_room["y"] +prev_room["height"] // 2)
        curr_center = (curr_room["x"] + curr_room["width"] // 2, curr_room["y"] +curr_room["height"] // 2)

        #magic  that makes the horizontal corridor
        for x in range (min(prev_center[0], curr_center[0]), max(prev_center[0], curr_center[0])+ 1):
            game_map[prev_center[1]][x] = TILES["FLOOR"]
        
        #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ vertical corridor
        for y in range (min(prev_center[1], curr_center[1]), max(prev_center[1], curr_center[1])+ 1):
            game_map[y][curr_center[0]] = TILES["FLOOR"]

        

    

    return game_map

again apologies if im not meeting a specific format standard or if ive given too much context or some other arbitrary unwritten rule. Any help is appreciated
 
  • Like
Reactions: Evil Whitey and sci
i looked around for another thread dedicated to programming assistance and found none
This is the thread, until someone gets to work on KiwiOverflow...

Where do you want to put the doors? First/last tile of the corridor?

You can also read from the map and check what was in the tile (wall or floor) as you "carve" the corridor tile.

Python:
        #magic  that makes the horizontal corridor
(+)     has_put_door = False
        for x in range (min(prev_center[0], curr_center[0]), max(prev_center[0], curr_center[0])+ 1):
(+)         if game_map[prev_center[1]][x] == TILES["WALL"] and not has_put_door:
(+)             has_put_door = True
(+)             game_map[prev_center[1]][x] = TILES["DOOR"]
(+)         else:
(~)             game_map[prev_center[1]][x] = TILES["FLOOR"]
Doors on the left hand side of horizontal corridors.
Code:
################################################################################
################################################################################
################################################################################
#############################################################    ###############
#############################################################    ###############
##################################       ####################    ###############
##################################       ##########              ###############
##################################       +                       ###############
##################################       #######      ######     ###############
#########     ####################       #######      ####    # ################
#########     ##################################      ####    # ################
#########     ##################################      ####    # ################
#########     +                                                 ################
#########     ###########                                     ##################
#########     ########### ################################    ##################
########### ############# #################     ##########    ##################
########### ###########     ###############     ##########    ##################
########### ###########     ###############     ################################
###########                                     ################################
#######################     +                   ################################
#######################     ###############     ################################
#######################     ####################################################
#######################     ####################################################
################################################################################

- Keep the map data as an actual data structure and not an array of tiles.
- You'll probably want to split the generation into multiple passes/functions.
- Pass the configuration via function parameters instead of using globals.
- Seed the random generator during testing/development so you can better judge the changes that you make.
- Reading your code gave me cancer.
- Procedural dungeon generation algorithms can become quite complex, depending on requirements; You might wish to "take a little inspiration" from others.
 
Any help is appreciated
I know that this isn't in Python and uses a different structure than what you're doing but here's what I'm using
Code:
fn door_possible(&self, build_data : &mut BuilderMap, idx : usize) -> bool {
        let mut blocked = false;
        for spawn in build_data.spawn_list.iter() {
            if spawn.0 == idx { blocked = true; }
        }
        if blocked { return false; }

        let x = (idx % build_data.map.width as usize) as i32;
        let y = (idx / build_data.map.width as usize) as i32;

        // Check for east-west door possibility
        if build_data.map.tiles[idx] == TileType::Floor &&
            (x > 1 && build_data.map.tiles[idx-1] == TileType::Floor) &&
            (x < build_data.map.width-2 && build_data.map.tiles[idx+1] == TileType::Floor) &&
            (y > 1 && build_data.map.tiles[idx - build_data.map.width as usize] == TileType::Wall) &&
            (y < build_data.map.height-2 && build_data.map.tiles[idx + build_data.map.width as usize] == TileType::Wall)
        {
            return true;
        }

        // Check for north-south door possibility
        if build_data.map.tiles[idx] == TileType::Floor &&
            (x > 1 && build_data.map.tiles[idx-1] == TileType::Wall) &&
            (x < build_data.map.width-2 && build_data.map.tiles[idx+1] == TileType::Wall) &&
            (y > 1 && build_data.map.tiles[idx - build_data.map.width as usize] == TileType::Floor) &&
            (y < build_data.map.height-2 && build_data.map.tiles[idx + build_data.map.width as usize] == TileType::Floor)
        {
            return true;
        }

        false
    }

    // Place the doors
    // build_data is so I have access to the entities and tiles, it seems like you already have this
    fn doors(&mut self, rng : &mut RandomNumberGenerator, build_data : &mut BuilderMap) {
        if let Some(halls_original) = &build_data.corridors {
            let halls = halls_original.clone(); // To avoid nested borrowing
            for hall in halls.iter() {
                if hall.len() > 2 { // We aren't interested in tiny corridors
                    // 1 in 2 chance
                    if self.door_possible(build_data, hall[0]) && rng.roll_dice(1,2)==1 {
                        // This is equivalent to setting the tile at the beginning of a hall  in your program to a Door tile, although in this game Doors are entities (So that they can be opened and closed)
                        build_data.spawn_list.push((hall[0], "Door".to_string()));
                    }
                }
            }
        } else {
            // There are no corridors - scan for possible places
            // 1 in 3 chance of placing a door
            let tiles = build_data.map.tiles.clone();
            for (i, tile) in tiles.iter().enumerate() {
                if *tile == TileType::Floor && self.door_possible(build_data, i) && rng.roll_dice(1,3)==1 {
                    build_data.spawn_list.push((i, "Door".to_string()));
                }
            }
        }
    }

1745767080774.webp
1745767201551.webp

The '+' chars are closed doors and the '/' chars are opened doors
 
Wonder if someone here can help since google is useless and chatGPT loops on bad answers. I have a large c++ application that uses grpc. I want to find data leaks due to frequent hard crashes and from what I gather Address Sanitizer is the best tool. However it shits the bed when used in conjunction with grpc. One of the solution I read is to recompile grpc with address sanitizer, but I'm worried I'd need to compile multiple libraries that grpc uses in turn. You'd think there would be a method to tell the sanitizer to ignore grpc but I can't find one with the suppression list not having any effect.
 
  • Thunk-Provoking
Reactions: Evil Whitey
I've always thought it would be better to start people new to programming with elemental languages like assembly. It's hard to do very useful things with it but very easy to wrap your head around what it's doing. I also think it falls in line with most other teaching that follows the course of history.

Though introduction with high level languages like python would not have taken off without reason.

So, why teach python first instead of something simple like Atmel/AVR assembly?
 
I've always thought it would be better to start people new to programming with elemental languages like assembly. It's hard to do very useful things with it but very easy to wrap your head around what it's doing.
There's too much fiddly junk in assembly that adds complexity without enlightening. If you're learning, you shouldn't have to bother knowing about accumulators and juggling data around to get everything into place for a MUL or DIV, for example.

Besides which, at least on your typical desktop CPU, it's been several decades since your assembly listing has been "what the CPU actually does", which is a whole other can of irrelevant worms.
 
I've always thought it would be better to start people new to programming with elemental languages like assembly. It's hard to do very useful things with it but very easy to wrap your head around what it's doing. I also think it falls in line with most other teaching that follows the course of history.

Though introduction with high level languages like python would not have taken off without reason.

So, why teach python first instead of something simple like Atmel/AVR assembly?
I still think BASIC was a good learning language. Could do more than assembly and do fun stuff but the concepts carry over. 6510 was my second language.
 
Back