h48

A prototype for an optimal Rubik's cube solver, work in progress.
git clone https://git.tronto.net/h48
Download | Log | Files | Refs | README | LICENSE

commit da8fdd4955fd24666643915a6728678e9965a0d3
parent 14689e29252e608d51c5b52e61e43471d2aa021e
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Sat, 12 Oct 2024 11:11:28 +0200

Make writecube safer

Diffstat:
Msrc/core/io_cube.h | 103+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Msrc/nissy.c | 73+++++++++++++++++++++++++++++++++----------------------------------------
Msrc/nissy.h | 33++++++++++++++++++++-------------
Mtest/020_io_H48_read_write/io_H48_tests.c | 2+-
Mtest/021_io_B32_write/io_B32_read_tests.c | 2+-
Mtest/022_io_B32_read/io_B32_read_tests.c | 2+-
Mtest/023_io_LST_write/io_LST_write_tests.c | 2+-
Mtest/024_io_LST_read/io_LST_read_tests.c | 2+-
Mtest/030_move/move_tests.c | 2+-
Mtest/031_premove/premove_tests.c | 2+-
Mtest/040_inverse_cube/inverse_tests.c | 2+-
Mtest/050_compose/compose_tests.c | 2+-
Mtest/060_transform/transform_tests.c | 2+-
Mtest/075_set_eo/set_eo_tests.c | 2+-
Mtest/076_copy_corners/copy_corners_tests.c | 2+-
Mtest/077_copy_edges/copy_edges_tests.c | 2+-
Mtest/081_getcube/getcube_tests.c | 2+-
Mtest/test.h | 4++--
18 files changed, 130 insertions(+), 111 deletions(-)

diff --git a/src/core/io_cube.h b/src/core/io_cube.h @@ -1,5 +1,5 @@ STATIC cube_t readcube(const char *, const char *); -STATIC int writecube(const char *, cube_t, char *); +STATIC int64_t writecube(const char *, cube_t, uint64_t, char *); STATIC void log_available_formats(void); STATIC uint8_t readco(const char *); STATIC uint8_t readcp(const char *); @@ -10,10 +10,10 @@ STATIC cube_t readcube_H48(const char *); STATIC uint8_t readpiece_LST(const char **); STATIC cube_t readcube_LST(const char *); -STATIC int writepiece_LST(uint8_t, char *); -STATIC void writecube_B32(cube_t, char *); -STATIC void writecube_H48(cube_t, char *); -STATIC void writecube_LST(cube_t, char *); +STATIC int64_t writepiece_LST(uint8_t, uint64_t, char *); +STATIC int64_t writecube_B32(cube_t, uint64_t, char *); +STATIC int64_t writecube_H48(cube_t, uint64_t, char *); +STATIC int64_t writecube_LST(cube_t, uint64_t, char *); STATIC uint8_t b32toedge(char); STATIC uint8_t b32tocorner(char); @@ -23,7 +23,7 @@ STATIC char cornertob32(uint8_t); STATIC struct { const char *name; cube_t (*read)(const char *); - void (*write)(cube_t, char *); + int64_t (*write)(cube_t, uint64_t, char *); } ioformat[] = { { .name = "B32", .read = readcube_B32, .write = writecube_B32 }, @@ -46,35 +46,18 @@ readcube(const char *format, const char *buf) return ZERO_CUBE; } -STATIC int -writecube(const char *format, cube_t cube, char *buf) +STATIC int64_t +writecube(const char *format, cube_t cube, uint64_t buf_size, char *buf) { - char *errormsg; - size_t len; - - if (!isconsistent(cube)) { - errormsg = "ERROR: inconsistent"; - goto writecube_error; - } - int i; - for (i = 0; ioformat[i].write != NULL; i++) { - if (!strcmp(format, ioformat[i].name)) { - ioformat[i].write(cube, buf); - return 0; - } - } + for (i = 0; ioformat[i].write != NULL; i++) + if (!strcmp(format, ioformat[i].name)) + return ioformat[i].write(cube, buf_size, buf); LOG("Cannot write cube: unknown format '%s'\n", format); log_available_formats(); - errormsg = "ERROR: format"; - -writecube_error: - len = strlen(errormsg); - memcpy(buf, errormsg, len); - buf[len] = '\0'; - return 1; + return NISSY_ERROR_INVALID_FORMAT; } STATIC void @@ -249,11 +232,14 @@ readcube_LST(const char *buf) return cubefromarray(c, e); } -STATIC int -writepiece_LST(uint8_t piece, char *buf) +STATIC int64_t +writepiece_LST(uint8_t piece, uint64_t buf_size, char *buf) { char digits[3]; - int i, len; + uint64_t i, len; + + if (piece > 99 || buf_size < 3) + return 0; len = 0; while (piece != 0) { @@ -261,6 +247,9 @@ writepiece_LST(uint8_t piece, char *buf) piece /= 10; } + if (buf_size < len+2) + return 0; + if (len == 0) digits[len++] = '0'; @@ -273,12 +262,19 @@ writepiece_LST(uint8_t piece, char *buf) return len+2; } -STATIC void -writecube_B32(cube_t cube, char *buf) +STATIC int64_t +writecube_B32(cube_t cube, uint64_t buf_size, char *buf) { int i; uint8_t corner[8], edge[12]; + if (buf_size < NISSY_SIZE_B32) { + LOG("Cannot write cube in B32 format: buffer size must be " + "at least %" PRIu64 " bytes, but the provided one is %" + PRIu64 " bytes.\n", NISSY_SIZE_B32, buf_size); + return NISSY_ERROR_BUFFER_SIZE; + } + pieces(&cube, corner, edge); for (i = 0; i < 8; i++) @@ -290,14 +286,23 @@ writecube_B32(cube_t cube, char *buf) buf[i+9] = edgetob32(edge[i]); buf[21] = '\0'; + + return NISSY_OK; } -STATIC void -writecube_H48(cube_t cube, char *buf) +STATIC int64_t +writecube_H48(cube_t cube, uint64_t buf_size, char *buf) { uint8_t piece, perm, orient, corner[8], edge[12]; int i; + if (buf_size < NISSY_SIZE_H48) { + LOG("Cannot write cube in H48 format: buffer size must be " + "at least %" PRIu64 " bytes, but the provided one is %" + PRIu64 " bytes.\n", NISSY_SIZE_H48, buf_size); + return NISSY_ERROR_BUFFER_SIZE; + } + pieces(&cube, corner, edge); for (i = 0; i < 12; i++) { @@ -321,13 +326,15 @@ writecube_H48(cube_t cube, char *buf) } buf[48+39] = '\0'; + + return NISSY_OK; } -STATIC void -writecube_LST(cube_t cube, char *buf) +STATIC int64_t +writecube_LST(cube_t cube, uint64_t buf_size, char *buf) { int i; - size_t ptr; + uint64_t ptr; uint8_t piece, corner[8], edge[12]; ptr = 0; @@ -335,15 +342,27 @@ writecube_LST(cube_t cube, char *buf) for (i = 0; i < 8; i++) { piece = corner[i]; - ptr += writepiece_LST(piece, buf + ptr); + ptr += writepiece_LST(piece, buf_size - ptr, buf + ptr); + if (ptr == 0) + goto writecube_LST_error; } for (i = 0; i < 12; i++) { piece = edge[i]; - ptr += writepiece_LST(piece, buf + ptr); + ptr += writepiece_LST(piece, buf_size - ptr, buf + ptr); + if (ptr == 0) + goto writecube_LST_error; } - *(buf+ptr-2) = 0; + *(buf+ptr-2) = '\0'; + + return NISSY_OK; + +writecube_LST_error: + LOG("Cannot write cube in LST: buffer is too small (%" PRIu64 + " bytes given). The LST format has a variable size, try a " + "larger buffer.\n", buf_size); + return NISSY_ERROR_BUFFER_SIZE; } STATIC uint8_t diff --git a/src/nissy.c b/src/nissy.c @@ -5,15 +5,14 @@ #include <stdbool.h> #include <string.h> +#include "nissy.h" #include "utils/utils.h" #include "arch/arch.h" #include "core/core.h" #include "solvers/solvers.h" -#include "nissy.h" - int parse_h48_solver(const char *, uint8_t [static 1], uint8_t [static 1]); -STATIC int64_t write_result(cube_t, char [static 22]); +STATIC int64_t write_result(cube_t, char [static NISSY_SIZE_B32]); STATIC bool distribution_equal(const uint64_t [static INFO_DISTRIBUTION_LEN], const uint64_t [static INFO_DISTRIBUTION_LEN], uint8_t); STATIC bool checkdata(const char *, const tableinfo_t *); @@ -107,9 +106,9 @@ distribution_equal( } STATIC int64_t -write_result(cube_t cube, char result[static 22]) +write_result(cube_t cube, char result[static NISSY_SIZE_B32]) { - writecube("B32", cube, result); + writecube("B32", cube, NISSY_SIZE_B32, result); if (!issolvable(cube)) { LOG("Warning: resulting cube is not solvable\n"); @@ -121,9 +120,9 @@ write_result(cube_t cube, char result[static 22]) int64_t nissy_compose( - const char cube[static 22], - const char permutation[static 22], - char result[static 22] + const char cube[static NISSY_SIZE_B32], + const char permutation[static NISSY_SIZE_B32], + char result[static NISSY_SIZE_B32] ) { cube_t c, p, res; @@ -156,14 +155,14 @@ nissy_compose( return write_result(res, result); nissy_compose_error: - writecube("B32", ZERO_CUBE, result); + writecube("B32", ZERO_CUBE, NISSY_SIZE_B32, result); return err; } int64_t nissy_inverse( - const char cube[static 22], - char result[static 22] + const char cube[static NISSY_SIZE_B32], + char result[static NISSY_SIZE_B32] ) { cube_t c, res; @@ -188,15 +187,15 @@ nissy_inverse( return write_result(res, result); nissy_inverse_error: - writecube("B32", ZERO_CUBE, result); + writecube("B32", ZERO_CUBE, NISSY_SIZE_B32, result); return err; } int64_t nissy_applymoves( - const char cube[static 22], + const char cube[static NISSY_SIZE_B32], const char *moves, - char result[static 22] + char result[static NISSY_SIZE_B32] ) { cube_t c, res; @@ -227,15 +226,15 @@ nissy_applymoves( return write_result(res, result); nissy_applymoves_error: - writecube("B32", ZERO_CUBE, result); + writecube("B32", ZERO_CUBE, NISSY_SIZE_B32, result); return err; } int64_t nissy_applytrans( - const char cube[static 22], - const char transformation[static 12], - char result[static 22] + const char cube[static NISSY_SIZE_B32], + const char transformation[static NISSY_SIZE_TRANSFORMATION], + char result[static NISSY_SIZE_B32] ) { cube_t c, res; @@ -260,14 +259,14 @@ nissy_applytrans( return write_result(res, result); nissy_applytrans_error: - writecube("B32", ZERO_CUBE, result); + writecube("B32", ZERO_CUBE, NISSY_SIZE_B32, result); return err; } int64_t nissy_frommoves( const char *moves, - char result[static 22] + char result[static NISSY_SIZE_B32] ) { cube_t res; @@ -290,7 +289,7 @@ nissy_frommoves( return write_result(res, result); nissy_frommoves_error: - writecube("B32", ZERO_CUBE, result); + writecube("B32", ZERO_CUBE, NISSY_SIZE_B32, result); return err; } @@ -304,7 +303,6 @@ nissy_convert( ) { cube_t c; - int ret; int64_t err; if (format_in == NULL) { @@ -327,28 +325,15 @@ nissy_convert( c = readcube(format_in, cube_string); - if (iserror(c)) { - err = NISSY_ERROR_INVALID_CUBE; - goto nissy_convert_error; - } - - ret = writecube(format_out, c, result); - - if (ret != 0) { - /* Assume the format was invalid */ - err = NISSY_ERROR_INVALID_FORMAT; - goto nissy_convert_error; - } - if (!isconsistent(c)) { - err = NISSY_ERROR_UNKNOWN; + err = NISSY_ERROR_INVALID_CUBE; goto nissy_convert_error; } - return NISSY_OK; + return writecube(format_out, c, result_size, result); nissy_convert_error: - /* We don't write anything to result, we don't know the format */ + result[0] = '\0'; return err; } @@ -359,7 +344,7 @@ nissy_getcube( int64_t cp, int64_t co, const char *options, - char result[static 22] + char result[static NISSY_SIZE_B32] ) { int i; @@ -498,7 +483,7 @@ nissy_checkdata( int64_t nissy_solve( - const char cube[static 22], + const char cube[static NISSY_SIZE_B32], const char *solver, uint8_t nissflag, int8_t minmoves, @@ -671,6 +656,14 @@ nissy_explainerror( "is NULL.\n", NISSY_ERROR_NULL_POINTER ); return NISSY_OK; + case NISSY_ERROR_BUFFER_SIZE: + write( + "The value %" PRId64 " means that one of the buffers " + "provided is too small. For example, it could be too " + "small to hold the result or too small to hold the data " + "generated by gendata.\n", NISSY_ERROR_BUFFER_SIZE + ); + return NISSY_OK; case NISSY_ERROR_DATA: write( "The value %" PRId64 " means that the provided data is " diff --git a/src/nissy.h b/src/nissy.h @@ -35,11 +35,17 @@ for example 'rotation UF' or 'mirrored BL'. #define NISSY_ERROR_INVALID_FORMAT INT64_C(-40) #define NISSY_ERROR_INVALID_SOLVER INT64_C(-50) #define NISSY_ERROR_NULL_POINTER INT64_C(-60) +#define NISSY_ERROR_BUFFER_SIZE INT64_C(-61) #define NISSY_ERROR_DATA INT64_C(-70) #define NISSY_ERROR_OPTIONS INT64_C(-80) #define NISSY_ERROR_INVALID_CODE INT64_C(-90) #define NISSY_ERROR_UNKNOWN INT64_C(-999) +/* Some constants for size for I/O buffers */ +#define NISSY_SIZE_B32 UINT64_C(22) +#define NISSY_SIZE_H48 UINT64_C(88) +#define NISSY_SIZE_TRANSFORMATION UINT64_C(12) + /* Flags for NISS options */ #define NISSY_NISSFLAG_NORMAL UINT8_C(1) #define NISSY_NISSFLAG_INVERSE UINT8_C(2) @@ -68,9 +74,9 @@ Return values: NISSY_ERROR_UNKNOWN - An unknown error occurred. */ int64_t nissy_compose( - const char cube[static 22], - const char permutation[static 22], - char result[static 22] + const char cube[static NISSY_SIZE_B32], + const char permutation[static NISSY_SIZE_B32], + char result[static NISSY_SIZE_B32] ); /* @@ -89,8 +95,8 @@ Return values: NISSY_ERROR_UNKNOWN - An unknown error occurred. */ int64_t nissy_inverse( - const char cube[static 22], - char result[static 22] + const char cube[static NISSY_SIZE_B32], + char result[static NISSY_SIZE_B32] ); /* @@ -111,9 +117,9 @@ Return values: NISSY_ERROR_NULL_POINTER - The 'moves' argument is NULL. */ int64_t nissy_applymoves( - const char cube[static 22], + const char cube[static NISSY_SIZE_B32], const char *moves, - char result[static 22] + char result[static NISSY_SIZE_B32] ); /* @@ -132,9 +138,9 @@ Return values: NISSY_ERROR_INVALID_TRANS - The given transformation is invalid. */ int64_t nissy_applytrans( - const char cube[static 22], - const char transformation[static 12], - char result[static 22] + const char cube[static NISSY_SIZE_B32], + const char transformation[static NISSY_SIZE_TRANSFORMATION], + char result[static NISSY_SIZE_B32] ); /* @@ -154,7 +160,7 @@ Return values: */ int64_t nissy_frommoves( const char *moves, - char result[static 22] + char result[static NISSY_SIZE_B32] ); /* @@ -169,6 +175,7 @@ Parameters: Return values: NISSY_OK - The conversion was performed succesfully. + NISSY_ERROR_BUFFER_SIZE - The given buffer is too small for the result. NISSY_ERROR_INVALID_CUBE - The given cube is invalid. NISSY_ERROR_INVALID_FORMAT - At least one of the given formats is invalid. NISSY_ERROR_UNKNOWN - An unknown error occurred. @@ -208,7 +215,7 @@ int64_t nissy_getcube( int64_t cp, int64_t co, const char *options, - char result[static 22] + char result[static NISSY_SIZE_B32] ); /* @@ -313,7 +320,7 @@ Return values: Any value >= 0 - The number of solutions found. */ int64_t nissy_solve( - const char cube[static 22], + const char cube[static NISSY_SIZE_B32], const char *solver, uint8_t nissflag, int8_t minmoves, diff --git a/test/020_io_H48_read_write/io_H48_tests.c b/test/020_io_H48_read_write/io_H48_tests.c @@ -16,7 +16,7 @@ void run(void) { } else if (!issolvable(cube)) { printf("Cube is not solvable\n"); } else { - writecube("H48", cube, str); + writecube("H48", cube, NISSY_SIZE_H48, str); printf("%s\n", str); } } diff --git a/test/021_io_B32_write/io_B32_read_tests.c b/test/021_io_B32_write/io_B32_read_tests.c @@ -16,7 +16,7 @@ void run(void) { } else if (!issolvable(cube)) { printf("Cube is not solvable\n"); } else { - writecube("B32", cube, str); + writecube("B32", cube, NISSY_SIZE_B32, str); printf("%s\n", str); } } diff --git a/test/022_io_B32_read/io_B32_read_tests.c b/test/022_io_B32_read/io_B32_read_tests.c @@ -16,7 +16,7 @@ void run(void) { } else if (!issolvable(cube)) { printf("Cube is not solvable\n"); } else { - writecube("H48", cube, str); + writecube("H48", cube, NISSY_SIZE_H48, str); printf("%s\n", str); } } diff --git a/test/023_io_LST_write/io_LST_write_tests.c b/test/023_io_LST_write/io_LST_write_tests.c @@ -16,7 +16,7 @@ void run(void) { } else if (!issolvable(cube)) { printf("Cube is not solvable\n"); } else { - writecube("LST", cube, str); + writecube("LST", cube, STRLENMAX, str); printf("%s\n", str); } } diff --git a/test/024_io_LST_read/io_LST_read_tests.c b/test/024_io_LST_read/io_LST_read_tests.c @@ -16,7 +16,7 @@ void run(void) { } else if (!issolvable(cube)) { printf("Cube is not solvable\n"); } else { - writecube("H48", cube, str); + writecube("H48", cube, NISSY_SIZE_H48, str); printf("%s\n", str); } } diff --git a/test/030_move/move_tests.c b/test/030_move/move_tests.c @@ -17,7 +17,7 @@ void run(void) { } else if (!issolvable(cube)) { printf("Moved cube is not solvable\n"); } else { - writecube("H48", cube, cubestr); + writecube("H48", cube, NISSY_SIZE_H48, cubestr); printf("%s\n", cubestr); } } diff --git a/test/031_premove/premove_tests.c b/test/031_premove/premove_tests.c @@ -21,7 +21,7 @@ void run(void) { } else if (!issolvable(cube)) { printf("Moved cube is not solvable\n"); } else { - writecube("H48", cube, cubestr); + writecube("H48", cube, NISSY_SIZE_H48, cubestr); printf("%s\n", cubestr); } } diff --git a/test/040_inverse_cube/inverse_tests.c b/test/040_inverse_cube/inverse_tests.c @@ -15,7 +15,7 @@ void run(void) { } else if (!issolvable(inv)) { printf("Inverted cube is not solvable\n"); } else { - writecube("H48", inv, str); + writecube("H48", inv, NISSY_SIZE_H48, str); printf("%s\n", str); } } diff --git a/test/050_compose/compose_tests.c b/test/050_compose/compose_tests.c @@ -18,7 +18,7 @@ void run(void) { } else if (!issolvable(c3)) { printf("Composed cube is not solvable\n"); } else { - writecube("H48", c3, str); + writecube("H48", c3, NISSY_SIZE_H48, str); printf("%s\n", str); } } diff --git a/test/060_transform/transform_tests.c b/test/060_transform/transform_tests.c @@ -17,7 +17,7 @@ void run(void) { } else if (!issolvable(cube)) { printf("Transformed cube is not solvable\n"); } else { - writecube("H48", cube, cubestr); + writecube("H48", cube, NISSY_SIZE_H48, cubestr); printf("%s\n", cubestr); } } diff --git a/test/075_set_eo/set_eo_tests.c b/test/075_set_eo/set_eo_tests.c @@ -30,7 +30,7 @@ void run(void) { fprintf(stderr, "\n"); printf("Setting EO resulted in inconsistent cube\n"); } else { - writecube("H48", cube, str); + writecube("H48", cube, NISSY_SIZE_H48, str); printf("%s\n", str); } } diff --git a/test/076_copy_corners/copy_corners_tests.c b/test/076_copy_corners/copy_corners_tests.c @@ -19,7 +19,7 @@ void run(void) { } else if (!isconsistent(c1)) { printf("Setting EO resulted in inconsistent cube\n"); } else { - writecube("H48", c1, str); + writecube("H48", c1, NISSY_SIZE_H48, str); printf("%s\n", str); } } diff --git a/test/077_copy_edges/copy_edges_tests.c b/test/077_copy_edges/copy_edges_tests.c @@ -19,7 +19,7 @@ void run(void) { } else if (!isconsistent(c1)) { printf("Setting EO resulted in inconsistent cube\n"); } else { - writecube("H48", c1, str); + writecube("H48", c1, NISSY_SIZE_H48, str); printf("%s\n", str); } } diff --git a/test/081_getcube/getcube_tests.c b/test/081_getcube/getcube_tests.c @@ -23,7 +23,7 @@ void run(void) { } else if (!isconsistent(cube)) { printf("Inconsistent cube\n"); } else { - writecube("H48", cube, str); + writecube("H48", cube, NISSY_SIZE_H48, str); printf("%s\n", str); } } diff --git a/test/test.h b/test/test.h @@ -8,6 +8,7 @@ #include <stdlib.h> #include <string.h> +#include "../src/nissy.h" #include "../src/arch/arch.h" #include "../src/solvers/tables_types_macros.h" #include "../src/solvers/h48/coordinate_macros.h" @@ -23,8 +24,7 @@ bool isconsistent(cube_t); bool issolvable(cube_t); bool issolved(cube_t); cube_t readcube(char *, char *); -void writecube(char *, cube_t, char *); -void nissy_setlogger(void (*logger_function)(const char *, ...)); +int64_t writecube(char *, cube_t, uint64_t, char *); /* Test function to be implemented by all tests */ void run(void);