Monday, November 28, 2022

The curious case of the extra for loop iteration

 

Lately, I stumbled upon a lovely and elegant bug, yes it's pretty funny to call a bug elegant but my opinion here is quite firm.

Lets, consider the following short piece of code: 

package main

import (
"fmt"
"reflect"
)

type MyStruct struct{}

func (t *MyStruct) Func0() {
fmt.Println("func0")
}

func (t *MyStruct) Func1() {
fmt.Println("func1")
}

func main() {
var t MyStruct
searchTables := [3]uint32{0, 1}
for _, v := range searchTables {
methodName := "Func" + fmt.Sprint(v)
reflect.ValueOf(&t).MethodByName(methodName).
Call([]reflect.Value{})
}
}

Looking through the code we see a range loop running over a two-member array. calling a function by name, nothing really special here unless you see the output, which is :

func0
func1
func0

Wait, What was that? how did a two-member range loop become a three iterations output?

The reason for that lies in the fact the array was declared as a 3-member array, while initializing a static array the zero value of that array (in this case uint32(0)) will fill the last value in the array. 

Admittedly this is not a very hard bug to diagnose, but its a very easy bug to fall into, example scenario: you might have a declared array from which you would like to remove one member, and although that member has been removed you forgot to change the size of the array and the last value will be filled with the zero value of that type which can lead to a disaster in runtime. 

Hope this helps anyone 










 























Monday, June 13, 2022

How obvious date comparison in bash really is ?

So, What's the big deal anyway?

When I encountered this situation in a real-life scenario I could not imagine that I would invest so much time in comparing dates. after all comparing dates in bash has been documented a thousand times over the web. 

The solution is quite obvious if you have two date strings and would like to compare them. If you have two unix epoch on your hand the solution is evident as well. 

But, what happens when you have on one hand an epoch and on the other, an arbitrary date time and you would like to fully compare them. well, that's less documented. so after hours of trying out various solutions and failing this is what worked for me.

Code sample: 

# Assume we have an epoch named "first_epoch" 

# get the process uptime as a date formatted string

process_uptime_tmp=$(systemctl status <your_process> | grep ago | awk '{print $6" "$7}')

# convert the date into a comparable epoch

process_start_epoch=$(echo $(date -d"$process_uptime_tmp" +%s))

# compare epochs

if [ "$first_epoch" -gt "$process_start_epoch" ]

then

  echo "do something"

else

 echo "do something else"

fi 


Hope this helps anyone out there looking for a solution.

Cheers,