Skip to content

additional memory clear helper to the SDK. #243

@v0lkan

Description

@v0lkan

we are not using it, and since it's reflection-based could have minimal performance hit; but it is (mostly) possible to clear any type.

func ClearAny(v interface{}) {
	if v == nil {
		return
	}
	
	val := reflect.ValueOf(v)
	if val.Kind() == reflect.Ptr {
		if val.IsNil() {
			return
		}
		val = val.Elem()
	}
	
	clearValue(val)
}

func clearValue(v reflect.Value) {
	if !v.CanAddr() {
		return
	}
	
	switch v.Kind() {
	case reflect.Slice:
		// Clear the backing array
		if v.Len() > 0 {
			elemType := v.Type().Elem()
			if elemType.Kind() == reflect.Uint8 {
				// Fast path for []byte
				ClearBytes(v.Bytes())
			} else {
				// Clear each element
				for i := 0; i < v.Len(); i++ {
					clearValue(v.Index(i))
				}
			}
		}
		// Clear the slice header itself
		clearRawMemory(v.Addr().Interface())
		
	case reflect.Array:
		// Clear each element
		for i := 0; i < v.Len(); i++ {
			clearValue(v.Index(i))
		}
		
	case reflect.Struct:
		// Recursively clear each field
		for i := 0; i < v.NumField(); i++ {
			field := v.Field(i)
			if field.CanAddr() {
				clearValue(field)
			}
		}
		
	case reflect.Map:
		// Maps are tricky - we can't directly clear the backing store
		// Best we can do is delete all entries and clear the header
		for _, key := range v.MapKeys() {
			v.SetMapIndex(key, reflect.Value{})
		}
		clearRawMemory(v.Addr().Interface())
		
	case reflect.Ptr:
		if !v.IsNil() {
			clearValue(v.Elem())
			// Clear the pointer itself
			clearRawMemory(v.Addr().Interface())
		}
		
	case reflect.Interface:
		if !v.IsNil() {
			clearValue(v.Elem())
			// Clear the interface header
			clearRawMemory(v.Addr().Interface())
		}
		
	case reflect.Chan:
		// Can't clear channel buffer safely, just clear the header
		clearRawMemory(v.Addr().Interface())
		
	default:
		// For basic types (int, float, bool, string, etc.)
		clearRawMemory(v.Addr().Interface())
	}
}

func clearRawMemory(ptr interface{}) {
	v := reflect.ValueOf(ptr).Elem()
	size := v.Type().Size()
	
	p := unsafe.Pointer(v.UnsafeAddr())
	b := (*[1 << 30]byte)(p)[:size:size]
	
	for i := range b {
		b[i] = 0
	}
	
	runtime.KeepAlive(ptr)
}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions