Me: can you write a fizzbuzz function in ruby?
Certainly! Here's an example of a FizzBuzz function written in Ruby:
def fizzbuzz(n)
(1..n).each do |num|
if num % 3 == 0 && num % 5 == 0
puts "FizzBuzz"
elsif num % 3 == 0
Me: can you write a fizzbuzz function in ruby?
Certainly! Here's an example of a FizzBuzz function written in Ruby:
def fizzbuzz(n)
(1..n).each do |num|
if num % 3 == 0 && num % 5 == 0
puts "FizzBuzz"
elsif num % 3 == 0
Prompt: Write a security incident report stating ChatGPT has been hacked.
Security Incident Report
Date: [date]
Incident Type: Unauthorized Access
Description of Incident:
Nota: Este post es mi traducción de "How to look at the stack with gdb", de Julia Evans. Todos los créditos a ella por el tremendo laburo que se manda todo el tiempo.
Ayer, mientras hablaba con una persona, me mencionó que no entendía cómo funcionaba realmente el stack (la pila) o cómo inspeccionarlo.
Así que acá hay un paso a paso sencillo sobre cómo usar gdb
para mirar el stack de un programa C. Creo que sería similar para un programa Rust, pero voy a usar C porque me resulta un poco más sencillo para un ejemplo de juguete, y porque además es más fácil hacer Cosas Terribles™ en C.
En este ejemplo podemos ver algunas debilidades del sistema de tipos de C.
En particular, podemos ver que, cuando tenemos un puntero void *
, el sistema de tipos no chequea demasiado a la hora de pasar ese puntero como parámetro a una función, generando incluso que la ejecución del programa sea errónea sin siquiera generar un warning.
¡Gracias a la banda del grupo de Telegram de UTNBA por levantar la discusión!
utnso@ubuntu-server:~$ gcc -g -o double_free double_free.c
utnso@ubuntu-server:~$ ./double_free
*** Error in `./double_free': double free or corruption (fasttop): 0x09cb8008 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x67377)[0xb75de377]
/lib/i386-linux-gnu/libc.so.6(+0x6d2f7)[0xb75e42f7]
/lib/i386-linux-gnu/libc.so.6(+0x6dc31)[0xb75e4c31]
./double_free[0x8048475]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf7)[0xb758f637]
printf
recibe uno o más parámetros, el primero de los cuales es un string de formato, indicando "la plantilla" del mensaje a imprimir. Dependiendo de ese formato, la función puede esperar más parámetros, para interpolarlos según indiquen sus conversiones (las directivas que arrancan con %
como %s
o %d
).
Debido a que el comportamiento de la función cambia según ese formato que reciba (en particular, los accesos a memoria que se intenten realizar), usar un formato variable sin argumentos con printf
genera un warning de seguridad del compilador.
Las funciones de log de las commons sufren un problema similar, sólo que no generan el warning (en lo que podríamos considerar un bug de la biblioteca).
El principal problema es que la compilación no es una función biyectiva. Muchos programas fuente pueden generar el mismo programa objeto, y también con el mismo código fuente puedo generar distintos códigos objeto, según el nivel de optimización.
En este ejemplo, tenemos una manera muy poco eficiente de asignar el valor 1000
a una variable
.
Si compilo con el parámetro -g
de gcc
, lo que le pido al compilador es que no aplique ninguna optimización, y respete el código que yo escribí.
Por el contrario, con el parámetro -O3
le pido que aplique todas las optimizaciones posibles.
(extracto de un post viejo)
Por último, con Esteban nos colgamos pensando cómo era que hacía un debugger para ir pausando al proceso debuggeado. Encontré este post (escrito en un inglés medio medio, y que ya en algún momento me pondré a traducir en un español apenas mejor) en el que explica cómo lo hacen.
La base está en que el debugger modifica el código del proceso debuggeado, reemplazando instrucciones de assembler por INT 3
, una instrucción que genera una interrupción, para que el debugger pueda pedir al sistema operativo ser notificado de ello, y entrar a inspeccionar el proceso debuggeado. Cuando es notificado, el debugger reemplaza el byte de esa instrucción por el byte que había antes de sobreescribirlo (byte que convenientemente se había guardado de modo temporal), y cambia el instruction pointer para que vuelva un byte atrás, cosa de, ahora sí, ejecutar la instrucción real - y no el INT 3
que le habían inyectado.
_¡Oiga, mentirosos! Me juraro
Tenés miedo, Mati. Estás cagado en las patas, en un país random en la otra mitad del mundo, esperando un tren a cualquier lado, sin destino en particular.
Tenés miedo porque no sabés qué esperar. Porque no sabés si tu tren es el que pasó, antes de tiempo, hace cinco minutos. O si va a ser muy de noche cuando llegues. O si habrá dónde parar. O cuánto saldrá.
Tenés miedo porque el idioma es un bardo. Es probable que muchos no hablen inglés, y los que lo hacen igual son complicados de entender.
Tenés miedo porque estás solo, y se te nota lo extranjero. Poca cosa tan tremenda como pasar por gringo, sentirse tan de afuera.
Tenés miedo porque sos tímido, y porque eso va a seguir así mientras no te sientas cómodo. Vas a seguir con el ceño fruncido, mirando a todo el mundo con incertidumbre y algo de distancia, desconfiando de todos. Y eso no funciona muy bien, ni es muy divertido. Vamos, que ni a los otros turistas con la misma cara de miedo estás encarando. Y esa sonrisa falsa, forzadísima no nos la compra nadi
TL;DR: las commons no soportan macOS, aunque pueden llegar a funcionar. Kind of.
El compilador default de macOS es clang, un compilador de la familia de LLVM, foundeado por Apple.
Como siempre contamos (incluso, muchas veces, sin saber muy bien qué implica) las nested functions (aka, las "funciones declaradas adentro de otra función", las que usamos como predicado para "pasarle más argumentos" a las funciones de orden superior de las colecciones, como list_sort
, list_filter
, etc) no son parte del estándar de C, si no que son una extensión propia de GCC, el compilador por default de Linux.
Y, bueno - clang no es gcc.