mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 00:49:02 -06:00 
			
		
		
		
	kernel: fix unbounded stack usage in atomics
This commit is contained in:
		@@ -35,24 +35,30 @@ bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address
 | 
			
		||||
 | 
			
		||||
    // TODO(bunnei): We should call CanAccessAtomic(..) here.
 | 
			
		||||
 | 
			
		||||
    // Load the value from the address.
 | 
			
		||||
    const s32 current_value =
 | 
			
		||||
        static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address)));
 | 
			
		||||
    s32 current_value{};
 | 
			
		||||
 | 
			
		||||
    // Compare it to the desired one.
 | 
			
		||||
    if (current_value < value) {
 | 
			
		||||
        // If less than, we want to try to decrement.
 | 
			
		||||
        const s32 decrement_value = current_value - 1;
 | 
			
		||||
    while (true) {
 | 
			
		||||
        // Load the value from the address.
 | 
			
		||||
        current_value =
 | 
			
		||||
            static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address)));
 | 
			
		||||
 | 
			
		||||
        // Compare it to the desired one.
 | 
			
		||||
        if (current_value < value) {
 | 
			
		||||
            // If less than, we want to try to decrement.
 | 
			
		||||
            const s32 decrement_value = current_value - 1;
 | 
			
		||||
 | 
			
		||||
            // Decrement and try to store.
 | 
			
		||||
            if (monitor.ExclusiveWrite32(current_core, GetInteger(address),
 | 
			
		||||
                                         static_cast<u32>(decrement_value))) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        // Decrement and try to store.
 | 
			
		||||
        if (!monitor.ExclusiveWrite32(current_core, GetInteger(address),
 | 
			
		||||
                                      static_cast<u32>(decrement_value))) {
 | 
			
		||||
            // If we failed to store, try again.
 | 
			
		||||
            DecrementIfLessThan(system, out, address, value);
 | 
			
		||||
        } else {
 | 
			
		||||
            // Otherwise, clear our exclusive hold and finish
 | 
			
		||||
            monitor.ClearExclusive(current_core);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        // Otherwise, clear our exclusive hold and finish
 | 
			
		||||
        monitor.ClearExclusive(current_core);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // We're done.
 | 
			
		||||
@@ -70,23 +76,29 @@ bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32
 | 
			
		||||
 | 
			
		||||
    // TODO(bunnei): We should call CanAccessAtomic(..) here.
 | 
			
		||||
 | 
			
		||||
    s32 current_value{};
 | 
			
		||||
 | 
			
		||||
    // Load the value from the address.
 | 
			
		||||
    const s32 current_value =
 | 
			
		||||
        static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address)));
 | 
			
		||||
    while (true) {
 | 
			
		||||
        current_value =
 | 
			
		||||
            static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address)));
 | 
			
		||||
 | 
			
		||||
    // Compare it to the desired one.
 | 
			
		||||
    if (current_value == value) {
 | 
			
		||||
        // If equal, we want to try to write the new value.
 | 
			
		||||
        // Compare it to the desired one.
 | 
			
		||||
        if (current_value == value) {
 | 
			
		||||
            // If equal, we want to try to write the new value.
 | 
			
		||||
 | 
			
		||||
            // Try to store.
 | 
			
		||||
            if (monitor.ExclusiveWrite32(current_core, GetInteger(address),
 | 
			
		||||
                                         static_cast<u32>(new_value))) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        // Try to store.
 | 
			
		||||
        if (!monitor.ExclusiveWrite32(current_core, GetInteger(address),
 | 
			
		||||
                                      static_cast<u32>(new_value))) {
 | 
			
		||||
            // If we failed to store, try again.
 | 
			
		||||
            UpdateIfEqual(system, out, address, value, new_value);
 | 
			
		||||
        } else {
 | 
			
		||||
            // Otherwise, clear our exclusive hold and finish.
 | 
			
		||||
            monitor.ClearExclusive(current_core);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        // Otherwise, clear our exclusive hold and finish.
 | 
			
		||||
        monitor.ClearExclusive(current_core);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // We're done.
 | 
			
		||||
 
 | 
			
		||||
@@ -33,21 +33,26 @@ bool UpdateLockAtomic(Core::System& system, u32* out, KProcessAddress address, u
 | 
			
		||||
    auto& monitor = system.Monitor();
 | 
			
		||||
    const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
 | 
			
		||||
 | 
			
		||||
    // Load the value from the address.
 | 
			
		||||
    const auto expected = monitor.ExclusiveRead32(current_core, GetInteger(address));
 | 
			
		||||
    u32 expected{};
 | 
			
		||||
 | 
			
		||||
    // Orr in the new mask.
 | 
			
		||||
    u32 value = expected | new_orr_mask;
 | 
			
		||||
    while (true) {
 | 
			
		||||
        // Load the value from the address.
 | 
			
		||||
        expected = monitor.ExclusiveRead32(current_core, GetInteger(address));
 | 
			
		||||
 | 
			
		||||
    // If the value is zero, use the if_zero value, otherwise use the newly orr'd value.
 | 
			
		||||
    if (!expected) {
 | 
			
		||||
        value = if_zero;
 | 
			
		||||
    }
 | 
			
		||||
        // Orr in the new mask.
 | 
			
		||||
        u32 value = expected | new_orr_mask;
 | 
			
		||||
 | 
			
		||||
        // If the value is zero, use the if_zero value, otherwise use the newly orr'd value.
 | 
			
		||||
        if (!expected) {
 | 
			
		||||
            value = if_zero;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Try to store.
 | 
			
		||||
        if (monitor.ExclusiveWrite32(current_core, GetInteger(address), value)) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    // Try to store.
 | 
			
		||||
    if (!monitor.ExclusiveWrite32(current_core, GetInteger(address), value)) {
 | 
			
		||||
        // If we failed to store, try again.
 | 
			
		||||
        return UpdateLockAtomic(system, out, address, if_zero, new_orr_mask);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // We're done.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user