2 puntos por GN⁺ 2024-12-22 | 1 comentarios | Compartir por WhatsApp
  • Scylla propone una ruta para compilar directamente a Rust seguro estructurando gradualmente el C original, en lugar de primero migrar el C existente a Rust unsafe y luego corregirlo
  • El objetivo es un subconjunto applicative de C que incluye procesamiento de datos, aritmética de punteros, flujo de control estructurado y código portable; se excluye el código que depende de goto, casts entero-puntero, trucos con punteros, bitfields y uniones untagged
  • La transformación tiene dos etapas: primero baja el AST de Clang a Mini-C y luego lo pasa a Rust seguro, haciendo explícitos comportamientos sutiles de C como promociones de enteros, conversiones implícitas, expresiones de asignación e incrementos prefijos/posfijos
  • La parte más difícil, la aritmética de punteros, se convierte en particiones basadas en slices de Rust y split_at_mut/split_at; también se manejan inferencia de mutabilidad, derivación de traits y la elección entre Box y borrow
  • Se evaluaron SymCrypt de Windows, HACL★, el algoritmo central de compresión de bzip2, el parser/serializador CBOR de EverParse y partes de Microsoft FrodoKEM; durante la transformación también se encontró undefined behavior en bzip2 y FrodoKEM

La ruta C→Rust elegida por Scylla

  • La motivación para migrar código C existente a Rust parte del problema de la seguridad de memoria
    • Estudios de Google y Microsoft estiman que el 70% de las vulnerabilidades de seguridad están relacionadas con un manejo incorrecto de la memoria
    • Empresas y gobiernos recomiendan usar lenguajes con seguridad de memoria como Rust en sistemas críticos para la seguridad
  • Rust tiene ventajas claras para código nuevo, pero reescribir por completo código C industrial ya probado y depurado es difícil
  • Las herramientas automáticas existentes de conversión C→Rust, para soportar todo C, suelen generar Rust unsafe
    • Permiten modismos estilo C como punteros unchecked o transmutation de Rust
    • Se pierden las garantías estáticas de seguridad de memoria, debilitando el propósito de usar un lenguaje seguro
  • El flujo de trabajo habitual toma la salida en Rust unsafe como punto de partida y luego la refactoriza iterativamente hacia Rust seguro
    • Se han propuesto análisis estáticos que convierten raw pointers en borrows seguros de Rust o recuperan abstracciones de Rust desde representaciones de bajo nivel
    • Las herramientas de refactorización están dispersas, y el soporte de c2rust refactor se discontinuó en 2022
  • Scylla elige estructurar gradualmente el código C original para que pueda compilarse a Rust seguro, en vez de corregir el Rust unsafe generado

Subconjunto de C soportado y patrones excluidos

  • El objetivo de Scylla es producir una transformación predecible y código Rust cercano al C original
  • El objetivo soportado es un subconjunto applicative de C
    • Código que manipula y procesa datos
    • Código que usa aritmética de punteros
    • Código con flujo de control estructurado
    • Código portable
  • No se soportan codebases que dependen de los siguientes patrones
    • goto
    • Uso de la representación de objetos mediante casts entero-puntero
    • Trucos con punteros
    • Bitfields
    • Uniones untagged
  • Los desarrolladores pueden aplicar reescrituras y anotaciones dirigidas al código fuente C para que Scylla pueda entenderlo
    • Pueden reescribir patrones de aliasing incompatibles con el borrow checker de Rust
    • Pueden entregar a Scylla la información de que una tagged union debe traducirse a un ADT de alto nivel

Mini-C: un lenguaje intermedio que reduce las ambigüedades de C

  • Scylla parte del AST del frontend de Clang y primero lo transforma a un lenguaje llamado Mini-C
  • Mini-C maneja branches, loops, punteros, dereferencias y toma de direcciones como C, pero tiene una semántica “sin sorpresas”
    • Todos los enteros tienen ancho fijo
    • La integer promotion y la integer conversion de C se expresan como casts explícitos
    • No se permiten punteros untyped como void *
  • A diferencia de C, Mini-C es un lenguaje de expresiones
    • La asignación no devuelve un valor
    • Sintaxis de C como e1 = e2 = e3 o p[i++] se desazucara en Mini-C
    • Las expresiones de prueba de loops y condicionales deben ser de tipo bool, no int de C
  • Al pasar el AST tipado de Clang al AST tipado de Mini-C, se hacen explícitos los comportamientos implícitos de C
    • Las condiciones se ajustan a bool
    • Los índices de arreglos se ajustan a size_t
    • Las conversiones implícitas en argumentos de llamadas a funciones y en el lado derecho de asignaciones se convierten en casts explícitos
    • En operaciones aritméticas se reflejan las usual arithmetic conversions del estándar C
  • La transformación asume que el código C es portable y que no depende del modelo de datos de C
    • Por ejemplo, no se espera código cuyo comportamiento cambie según si long mide 4 u 8 bytes
    • La implementación detecta en configure-time el modelo de datos de la arquitectura objetivo y convierte unsigned int a tipos de ancho fijo como uint32_t

Composición de ADT y tuplas

  • Mini-C ofrece ADT, tuplas y pattern matching de mayor nivel que C
  • Las tagged unions se traducen a ADT mediante anotaciones
    • La forma objetivo es una estructura como { int tag; union { t0 case0; ...; tn caseN }}
    • Se asume que los valores de tag van de 0 a N y que coinciden con el orden de los cases de la union
  • Scylla convierte los tipos tagged union anotados en tipos variant
    • Al crear valores, verifica que .tag = i y .casej = e coincidan
    • Si coinciden, los convierte al valor constructor correspondiente
    • Si el payload y el tag no coinciden, no los traduce a Mini-C
  • Para que el acceso a campos de una tagged union sea seguro, se debe conocer el estado actual del tag
    • Reconoce patrones como if (x.tag == i) { ... x.casei } o switch
    • Los transforma a una forma match x with | Ci v -> ...
    • El acceso a otros cases de la union se considera inválido y produce un error de transformación
  • Las tuplas también pueden componerse mediante anotaciones
    • Un struct con n campos se transforma en una tupla n-aria
    • Los accesos a campos se convierten en accesos a campos de tupla
    • Las tuplas se tipan estructuralmente y pueden aprovechar el mut-polymorphism

Transformación de Mini-C a Rust seguro

  • Mini-C ofrece una representación de programas C con anotaciones de tipo completas, que luego se transforma a Rust seguro
  • Hay tres dificultades principales
    • Eliminar la aritmética de punteros de C
    • Hacer explícitas la mutabilidad y el aliasing
    • Proveer automáticamente estructuras idiomáticas de Rust como traits
  • La conversión de tipos de puntero es compleja por las diferencias en la representación de punteros de Rust
    • Rust distingue entre Box<T> y &T
    • También distingue punteros a un solo elemento y punteros a múltiples elementos, por ejemplo &T y &[T]
    • Los arreglos de Rust son valores y no decaen automáticamente a punteros como en C
  • La estrategia básica es compilar todos los pointer types de C como slice borrows &[T] de Rust
    • Tanto los punteros de stack como los de heap se vuelven por defecto slice borrows
    • Los punteros a un solo elemento y a múltiples elementos también se vuelven por defecto slice borrows
    • La mutabilidad se infiere automáticamente en una etapa separada
  • Scylla traduce algunos punteros a Box<T> mediante heurísticas y anotaciones manuales
    • Funciones como T *create(), que no tienen referencias globales y se consideran fresh allocations, pueden traducirse como fn create() -> Box<T>
    • Este análisis se aplica recursivamente con un enfoque de punto fijo incluso dentro de definiciones de structs y variants
    • Los structs en los que permanecen borrows obtienen parámetros de lifetime

Restricciones en la conversión de Box, slice y array

  • En Rust se necesitan conversiones explícitas entre arrays, slice borrows y Box, por lo que la transformación a Rust de Scylla también opera de forma orientada por tipos
  • Las reglas de transformación insertan coercions que convierten arrays o boxed slices en slice borrows
    • Un array se vuelve un slice borrow con una forma como &x[..]
    • Un boxed slice puede convertirse en un borrow
  • También es posible la conversión en sentido contrario
    • Un slice o array puede promoverse a una heap allocation y convertirse en Box<[T]>
  • Esta conversión inversa puede generar diferencias en la semántica de copia
    • En C, arrays y punteros pueden apuntar a la misma memoria
    • En Rust, Box::new(x) puede crear una copy de x
    • En arrays de tipos básicos como arrays de enteros, no hay forma de hacer opt out del trait Copy, por lo que Rust puede copiar silenciosamente
  • Cuando ocurre este tipo de conversión, Scylla elimina la variable original del entorno y prohíbe su uso posterior
    • Si el programa C original sigue usando esa variable, queda un error de transformación
    • El desarrollador debe corregir el código fuente C antes de la transformación para dejar más clara la intención

Convertir aritmética de punteros en particiones de slices de Rust

  • Los programas C no acceden a los arrays solo mediante un único base pointer; con frecuencia usan patrones en los que dividen arrays en chunks o recorren manteniendo un puntero a la posición actual
  • Rust no permite aritmética arbitraria de punteros y ofrece una forma de dividir slices con split_at_mut o split_at
    • split_at_mut es un primitive que entrega dos sub-slices renunciando a la propiedad del slice original
    • Mantiene el invariant de Rust de que los datos mutables deben tener un owner único
  • Scylla introduce un split tree para alinear la aritmética de punteros de C con el esquema de partición de Rust
    • Cada puntero de C se mapea a un split tree
    • El split tree cambia de forma flow-dependent
    • Rastrea qué acceso a slice de Rust debe reemplazar un acceso de puntero de C en un punto específico del programa
  • Como los punteros de C no tienen información de longitud, Scylla asume que los chunks no se solapan
    • Si la intención era que se solaparan, no podrá pasar el type checking de Rust y el desarrollador deberá reescribir el código C
    • Para que la transformación sea predecible, evita backtracking y se realiza hacia adelante
  • En el ejemplo, un array de 32 bytes abcd se divide en cuatro regiones limb de 8 bytes
    • En C se usa aritmética de punteros no ordenada de izquierda a derecha, como abcd + 0, abcd + 16, abcd + 8, abcd + 24
    • La transformación a Rust mantiene el historial de llamadas a split_at_mut en un split tree para encontrar el sub-slice correcto

Objetivos de evaluación y undefined behavior encontrado

  • La implementación de Scylla usa Clang para tomar código C existente como entrada y generar Rust seguro como salida
  • La evaluación incluye partes de varios proyectos C existentes
    • Partes de SymCrypt de Windows
    • Partes de la biblioteca criptográfica HACL★
    • La parte central del algoritmo de compresión bzip2
    • El parser y serializador binario CBOR de la biblioteca EverParse
    • La implementación de la primitive criptográfica post-cuántica FrodoKEM de Microsoft
  • Estos casos muestran que el subconjunto applicative de C de Scylla puede cubrir varias aplicaciones sensibles a la seguridad
  • Durante la transformación, también se identificó y reportó undefined behavior presente en el código C original de bzip2 y FrodoKEM

1 comentarios

 
GN⁺ 2024-12-22
Opiniones de Hacker News
  • Es importante que este trabajo apunta a “bases de código en C que ya fueron verificadas formalmente”.
    El C de sistemas común no está verificado formalmente, así que es una historia bastante distinta.

    • Aun así, no parece ser completamente confiable. En la sección 2.2 del paper también se dice que las coerciones introducidas por las reglas de transformación pueden generar diferencias semánticas sutiles.
      Por ejemplo, un puntero que apuntaba a un arreglo de C en la pila podría traducirse en Rust como Box<[u8]>, es decir, como un puntero que posee una nueva copia en el heap. Si el código original dependía del hecho de que el puntero apuntaba al arreglo real, el código traducido podría comportarse mal en silencio.
      La función de traducción automática del subconjunto de C++ con seguridad de memoria de mi proyecto scpptool lo habría manejado moviendo los arreglos a tipos sustitutos e iteradores para preservar la semántica original.
      Puede que el proyecto del OP solo trate C que sea fácil de convertir a Rust seguro, pero considerando la dificultad del problema, el logro es respetable y también se le ve cierta utilidad.
    • Esto tiene muchísimas más advertencias y roza la publicidad exagerada.
      Para empezar, no tradujeron C real, sino que modificaron código escrito en F* para que del lado del compilador a C emitiera Rust. No se enfrentaron a C real complejo; como mucho trataron un Mini-C limitado, de esos que podría emitir un compilador de juguete.
      Incluso el texto original dice que si el programa C original depende más de x, la traducción produce un error y le exige al programador modificar el código fuente, lo que significa que esperan que el C ya esté escrito en un estilo que satisfaga al borrow checker de Rust.
      Suena a la típica expresión académica de “en la Figura 4 presentamos reglas hermosas, pero la implementación real depende de un montón de trucos”.
      Peor aún, dicen que los solapamientos distinguibles estáticamente generan errores de compilación, y que si no, el código Rust puede entrar en pánico en tiempo de ejecución. Convertir un programa C verificado formalmente en un programa Rust que “ahora también podría crashear” es raro.
      También es impreciso llamar a HACL* una base de código C existente y verificada formalmente. HACL* compila a C, pero no es una biblioteca en C; está escrita en un lenguaje completamente distinto.
      Un título honesto habría sido algo como “Compilar un subconjunto de F* a Rust parcialmente seguro, parcialmente formalizado”.
    • ¿Rust en sí está verificado formalmente? Hasta donde sé, no.
    • Me da curiosidad qué significa exactamente C verificado formalmente y por qué no hay más.
    • Me pregunto cuál es la diferencia clave. ¿Se puede exigir el cumplimiento con flags del compilador?
  • En 2002, investigadores publicaron un paper sobre Cyclone, un dialecto seguro de C, y al portar manualmente código C a Cyclone encontraron bugs de seguridad en el código C existente.
    Estas transformaciones de C, manuales o automáticas, tienen potencial no solo para aumentar la adopción de lenguajes más seguros, sino también para revelar bugs existentes.
    [1] https://www.researchgate.net/profile/James-Cheney-2/publicat...

    • Cyclone ya no recibe soporte, el proyecto de investigación principal terminó y sus desarrolladores pasaron a otras cosas.
      Varias ideas de Cyclone llegaron a Rust, y el código puede hacerse funcionar con algo de esfuerzo, pero no compila directamente en plataformas modernas de 64 bits.
      http://cyclone.thelanguage.org
  • Probé portar a Rust algunos proyectos, incluidos proyectos en C, usando C2Rust como primer paso, y llegué a varias conclusiones.

    1. Al mover un programa C a Rust, incluso si incluye unsafe, las fuertes restricciones de Rust —por ejemplo, la verificación de límites y las firmas estrictas— suelen hacer que los bugs aparezcan rápido.
    2. Creo que la conversión automática de C→Rust no puede resolverse por completo. El diseño de un programa C es fundamentalmente distinto al de Rust, y para hacerlo seguro hace falta un rediseño considerable.
    3. En algunos casos es imposible pasar de C a Rust preservando exactamente la semántica. La inseguridad puede estar incorporada en el propio diseño.
      Aun así, las herramientas son esenciales para portar, y mientras más mejoren, más fluido será el proceso.
    • Convertir automáticamente a “Rust rápido y seguro” es difícil, pero convertir automáticamente a Rust seguro en general es mucho más fácil.
      Basta con representar la memoria como un arreglo y tratar los punteros como índices dentro de ese arreglo. Así se pueden expresar comportamientos de C como la aritmética de punteros sin chequeos o los union, sin pelearse con el borrow checker, y se preserva la semántica. En C→Java se han usado técnicas similares desde hace mucho.
      Claro que el valor de esa conversión es ambiguo. En la práctica se parece a compilar C a wasm, pero más lento, y aunque el código resultante sea técnicamente “seguro”, siguen existiendo problemas como que un buffer overflow cree un estado incorrecto o que un puntero colgante permita acceder a datos en un contexto donde no debería permitirse.
    • En principio estoy de acuerdo con que “la inseguridad puede estar incorporada en el diseño”, y por mi experiencia también lo siento muy fuertemente, pero sería bueno tener un ejemplo simple para concretar la discusión.
  • Soy el autor. Creo que sería útil ordenar algunas cosas que salieron en varios hilos

    1. Esto es un artículo académico subido a arxiv, no el anuncio de un producto nuevo que afirme haber resuelto el problema C→Rust. Fue enviado a una conferencia de PL, y el público y las expectativas son distintos a los de una charla en un evento open source como FOSDEM
    2. El enfoque es simple. Partimos de la restricción de traducir C a Rust seguro, y analizamos que se necesita un subconjunto pequeño de C que funcione bien, inferencia de partición de slices, traducciones que puedan producir errores, programas que puedan abortarse, etc. Lo evaluamos sobre el objetivo que teníamos, C embebido en F*, y mostramos que, bajo esta restricción, escala bastante en bibliotecas C grandes usadas en software mainstream como Firefox, Python, etc. No afirmamos que Firefox pueda reescribirse automáticamente en Rust
    3. Así es como normalmente avanza la investigación. Vemos un punto interesante en el espacio de diseño y, aunque no afirmamos resolver todos los problemas, creemos que es una idea que puede abrir más avances en la traducción C→Rust. Alguna herramienta existente podría usar este enfoque para el código que encaja en el subconjunto y hacer fallback a unsafe Rust para las partes que no encajan
    4. Esto no es la versión final. Estamos construyendo el frontend real de C con libclang, y también exploramos formas de garantizar que el Rust generado no produzca accesos fuera de rango. Por ejemplo, estamos pensando en emitir condiciones de verificación a Z3. Si los revisores consideran que hace falta más trabajo, lo mejoraremos y lo volveremos a enviar; y si aceptan el artículo porque juzgan que el área está activa y que otras personas pueden beneficiarse de las ideas, mejor todavía
  • Lo que de verdad me pregunto es por qué habría que hacerlo así
    Si es una tecnología capaz de convertir de verdad apps industriales de C a Rust, parecería que también podría facilitar blindar apps C existentes. Bastaría con crear análisis para integrarlos en herramientas existentes como analizadores estáticos o generadores de pruebas
    Del mismo modo, también se podrían generar wrappers seguros para permitir escribir código nuevo en Rust junto al C verificado. El código nuevo obtiene los beneficios de Rust, el código existente queda confirmado como seguro y la interfaz también se vuelve más segura
    Un traductor completo puede ser ideal. A largo plazo conviene que la base de código tenga un solo lenguaje. Pero para C/C++ existente, la mayor necesidad sigue siendo lograr seguridad con un solo botón y pocos falsos positivos. También podría ser posible corregir automáticamente estructuras peligrosas dentro de C, como las herramientas de compilador de Google o Mayhem de ForAllSecure

    • Algunos programas en C no pueden hacerse seguros, así que no es correcto decir que “si es una tecnología para convertir apps industriales a Rust, puede blindar más fácilmente apps C”
      Puede ser porque dependen de comportamiento indefinido o no especificado, o porque agregar comprobaciones de seguridad adecuadas reduce tanto el rango de entradas aceptables que dejan de ser útiles
      Traducirlos a un lenguaje seguro es objetivamente mejor en esos casos, porque permite mantener la expresividad de las entradas y garantizar estáticamente un comportamiento correcto en tiempo de ejecución
      La idea de “C probado en producción” también es difícil de sostener, como muestran innumerables vulnerabilidades críticas. Lo que realmente existe es C que funciona lo bastante bien con suficiente frecuencia como para parecer útil
      El código viejo se asume seguro por suerte, no porque esté demostrado. “Demostrar” tiene un significado específico, sobre todo en el contexto de este tipo de artículos, y la abrumadora mayoría del código C no está demostrado bajo criterios matemáticos rigurosos. En cambio, la corrección del sistema de tipos de Rust sí está demostrada matemáticamente
      Un traductor completo depende de qué estés dispuesto a sacrificar. Si puedes sacrificar rendimiento, rango de entradas, rango de salidas, legibilidad del código, etc., hasta cierto punto es posible; pero los problemas aparecen cuando empiezas a querer un traductor sólido y completo en todos esos aspectos
  • Si se traduce ingenuamente a Rust, ¿no terminaría mezclando partes seguras y partes unsafe? Entonces el trabajo manual solo tendría que verificar la seguridad de las zonas unsafe. Sería parecido a escribir Rust desde cero
    Si el 90% del resultado no es unsafe, parece que podría ser una ganancia considerable

    • En efecto, es así. Alguien convirtió OpenJPEG con c2rust a unsafe Rust de bajo nivel
      Se sabía que OpenJPEG provocaba un segfault con cierto caso de prueba, y al correr esa prueba en la versión Rust, se produjo un segfault en el código Rust correspondiente al mismo lugar. Al menos era compatible
      Pero ese enfoque es un callejón sin salida. Para avanzar, el traductor tiene que reconocer modismos comunes de C y elevarlos a formas naturales del lenguaje destino. Si “compilas” a Rust, obtienes un Rust horrible lleno de llamadas a funciones de manipulación de punteros al estilo C inseguro
      El mayor problema de elevación tiene que ver, en su mayoría, con punteros. El resultado más prometedor de este artículo es que encontró una forma de convertir la aritmética de punteros de C en slices de Rust. Los slices pueden hacer la mayor parte de lo que hace la aritmética de punteros de C, y ahora alguien automatizó esa traducción. La aritmética de punteros que no se pueda traducir debería verse con muchísima sospecha
      Es útil pensar que los punteros crudos que apuntan a arrays en C tienen una longitud implícita asociada. Esa longitud no aparece en el código fuente C, pero existe en alguna parte como función del estado del programa. Puede ser una constante, el tamaño solicitado a malloc o un parámetro de función. Para un programador de mantenimiento, encontrar la longitud de un array no suele ser demasiado difícil
      Este podría ser un problema adecuado para un LLM. La idea sería preguntarle “mira este código y encuentra cuál es la longitud del array foo”, y luego hacer que un traductor que no sea el LLM use eso para guiar la conversión a Rust. Si el LLM se equivoca, Rust producirá un error de índice o tendrá un array demasiado grande, pero no será inseguro. Los modismos de C para la información de tamaño de arrays son lo bastante formalizados como para acertar en la mayoría de los casos. En particular, los LLM también pueden leer comentarios
    • Una traducción ingenua produciría código Rust que sería casi todo unsafe, porque usaría punteros crudos por todas partes en vez de referencias
      El código C no se escribe teniendo en cuenta el modelo de aliasing de Rust ni las restricciones del borrow checker, así que traducirlo a referencias es difícil
  • Solo compila un subconjunto de C muy pequeño. En la práctica, podría ser tan pequeño que resulte inútil
    Tengo pocas expectativas para este enfoque. Inevitablemente se topará con los límites de lo que puede hacerse con análisis estático de código C. Además, al elegir Rust como destino, el problema se vuelve innecesariamente difícil. El modelo de propiedad de Rust es demasiado distinto de la forma en que funcionan los programas reales en C

    • El modelo de propiedad de Rust es lo bastante cercano para traducir C. Solo tiene tipos más explícitos y fuertes, así que el traductor tiene que entender qué intenta hacer el código C libre y mapearlo a modismos de Rust
      Por ejemplo, los buffers de C obviamente tienen una longitud, pero en C la longitud no está vinculada explícitamente al puntero. Por eso el traductor tiene que inferir cómo el programa en C rastrea la longitud y convertirlo en un slice. Incluso si la longitud es una variable explícita no es fácil, y se vuelve más complicado si se calcula o si la representación cambia a una forma de “puntero al elemento posterior al final”
      Patrones de C como bool should_free_this_pointer también pueden trasladarse a un enum Owned/Borrowed de Rust, pero hay que inferir qué asignación está conectada con qué booleano y cuál es el verdadero alcance seguro de la variante prestada
    • Podría ser bueno como lenguaje de interfaz. Útil para bindings
    • Al final, creo que la gente va a meterle LLMs y decir que está bien aunque alucinen grandes cantidades de código que parece correcto
      Aun así, estoy de acuerdo en que producir Rust idiomático a partir de C arbitrario será difícil. Digamos que quedará en un nivel de “más o menos correcto”
  • Me da curiosidad cómo se compara esto con la función de traducción de C de Zig
    Zig parece destacarse para crear un entorno mixto donde el código nuevo está en Zig y el legado queda en C, hacer traducción o interoperabilidad, e incluso actuar como compilador de C
    Seguramente hay muy buenas razones por las que los mantenedores del kernel de Linux no ven a Zig, en lugar de Rust, como reemplazo de C. No sé lo suficiente como para especular, así que me gustaría que gente con más conocimiento lo explicara

    • Rust no es tanto un “reemplazo de C” como una herramienta que se suma a C. Es una herramienta cuyo valor Torvalds y otros reconocieron y permitieron en el kernel, y la mayor parte del código del kernel seguirá escribiéndose en C
      No soy mantenedor del kernel, pero si tuviera que adivinar dos grandes razones por las que se eligió Rust por encima de Zig, podrían ser que el lenguaje ofrece mejores garantías en tiempo de compilación y que su adopción avanza más rápido
      Grandes empresas de la industria están haciendo mucho trabajo para ofrecer código nativo en Rust para APIs o bindings de Rust mantenidos. Los desarrolladores de Windows también están reescribiendo partes de su kernel en Rust. Es un movimiento que lleva bastante tiempo y espero que no se detenga
      Puede que los mantenedores sientan que Zig no aporta suficientes ventajas frente a C. Muchos de ellos todavía se oponen incluso a Rust
    • Según entiendo, la mayoría de los mantenedores del kernel no quieren reemplazar C por nada
      Zig tiene una interoperabilidad con C mucho mejor que Rust, pero no es seguro en memoria y tampoco está estabilizado. La adopción de Zig en el mundo C probablemente crecerá bastante, pero es difícil verlo como competidor directo de Rust
      En mi región nadie adopta Rust, y la gente de C++ se queda en C++. Al principio había algo de interés en Rust, pero no logró consolidarse en ninguna empresa que conozca. Probablemente sea por razones parecidas a por qué Go creció mucho en empresas jóvenes, pero no logró entrar bien en compañías tradicionales de Java/C#. Aunque tenga sentido técnicamente, es un enorme desafío de gestión del cambio
      Zig está ganando tracción en programas que no necesitan asignación dinámica de memoria, pero no mucho más allá de eso
    • Zig todavía no es lo bastante maduro como para considerarse para el kernel
      Sigue teniendo cambios que rompen compatibilidad con regularidad, lo cual ahora es bueno para Zig, pero no para una base de código tan enorme y longeva como Linux. También aparecen bugs del compilador
      Lo digo como alguien a quien, en general, le gusta la dirección de Zig
    • Zig todavía no es 1.0 y no tiene ninguna garantía de compatibilidad hacia atrás. Casi no se usa en ningún lado y, aunque algunas partes parecen prometedoras, todavía no ha demostrado su valor
    • Podría ser porque Zig no es seguro en memoria
  • Me pregunto si herramientas como C2Rust podrían usar esto para generar código formalmente correcto
    También me da curiosidad cuánto trabajo manual hicieron los autores, o si ejecutaron algo para generar el código Rust. Si es así, no sé dónde está el código que genera Rust, y tampoco veo un enlace al repositorio fuente

    • El paper dice que, una vez terminado el proceso de revisión, es decir, básicamente después de la publicación formal del paper, publicarán este resultado de desarrollo bajo una licencia open source
  • Si una biblioteca en C funciona, es decir, si en general anda bien aunque no haya sido demostrada formalmente como libre de problemas, me pregunto por qué no traducirla usando unsafe Rust
    Creo que tiene valor, porque en general a Rust le faltan bibliotecas. Al final, no es muy distinto de usar una dll/so escrita en C que en ciertas situaciones podría no ser segura