From: Marko Semet Subject: [PATCH 4/7] widl: generate deterministic temporary filenames Message-Id: <20200624134550.Se9ke%marko@marko10-000.de> Date: Wed, 24 Jun 2020 15:45:50 +0200 Using xorshift* as pseudorandom number generator. It get initialised with the environment (sorted by name) and arguments. Signed-off-by: Marko Semet --- tools/widl/parser.l | 4 +- tools/widl/utils.c | 156 ++++++++++++++++++++++++++++++++++++++++++++ tools/widl/utils.h | 6 ++ tools/widl/widl.c | 3 +- 4 files changed, 166 insertions(+), 3 deletions(-) diff --git a/tools/widl/parser.l b/tools/widl/parser.l index 3cbf4ff2d2..a2b510324a 100644 --- a/tools/widl/parser.l +++ b/tools/widl/parser.l @@ -543,7 +543,7 @@ int do_import(char *fname) line_number = 1; name = xstrdup( "widl.XXXXXX" ); - if((fd = mkstemps( name, 0 )) == -1) + if((fd = pseudorandom_tempfile(name)) == -1) error("Could not generate a temp name from %s\n", name); temp_name = name; @@ -584,7 +584,7 @@ static void switch_to_acf(void) line_number = 1; name = xstrdup( "widl.XXXXXX" ); - if((fd = mkstemps( name, 0 )) == -1) + if((fd = pseudorandom_tempfile(name)) == -1) error("Could not generate a temp name from %s\n", name); temp_name = name; diff --git a/tools/widl/utils.c b/tools/widl/utils.c index ea92372c8c..5dce1a0231 100644 --- a/tools/widl/utils.c +++ b/tools/widl/utils.c @@ -474,3 +474,159 @@ void align_output( unsigned int align ) memset( output_buffer + output_buffer_pos, 0, size ); output_buffer_pos += size; } + +/* xorshift* random generator. Source: https://en.wikipedia.org/wiki/Xorshift#xorshift* */ +static uint64_t pseudorandom_state = 1; + +static uint64_t pseudorandom_algo(uint64_t* generator_state, uint64_t add_to_state) +{ + uint64_t tmp = (*generator_state) + add_to_state; + tmp ^= tmp >> 12; + tmp ^= tmp << 25; + tmp ^= tmp >> 27; + (*generator_state) = tmp; + return tmp * UINT64_C(0x2545F4914F6CDD1D); +} + +uint64_t pseudorandom(uint64_t add_to_state) +{ + return pseudorandom_algo(&pseudorandom_state, add_to_state); +} + +char pseudorandom_char(void) +{ + char tmp; + tmp = (char) (pseudorandom(0) % 62); + if (tmp < 10) + { + return '0' + tmp; + } + else if (tmp < 36) + { + return 'A' + (tmp - 10); + } + else + { + return 'a' + (tmp - 36); + } +} + +int pseudorandom_tempfile(char* file) +{ + /* variables */ + int result; + + int counter; + char *filename_pos; + + char *debug_filename; + FILE *debug_file; + + /* replaces Xs */ + for (filename_pos = file; (*filename_pos) != 0; filename_pos++) + { + if ((*filename_pos) == 'X') + { + (*filename_pos) = pseudorandom_char(); + } + } + + /* try to open file */ + counter = 0; + do + { + result = open(file, O_CREAT | O_EXCL | O_RDWR, 0600); + if (result != -1) + { + break; + } + sleep(5); + counter++; + } while (counter <= 12); + return result; +} + +void init_random_generator(int argc, char **argv) +{ + /* variables */ + uint64_t generator_state; + + void *argv_data; + size_t argv_size; + + unsigned int counter; + void *env_data; + size_t env_size; + char **tmp_envs; + + char *buffer_pos; + char **env; + size_t length; + + unsigned int i; + size_t j; + + /* process environment */ + generator_state = 1; + env_size = 0; + { + /* sort environment variables */ + counter = 0; + for (env = environ; (*env) != NULL; env++) + { + counter++; + env_size += strlen(*env) + 1; + } + tmp_envs = (char**) malloc(sizeof(char*) * counter); + for (i = 0; i < counter; i++) + { + tmp_envs[i] = (char*) (environ[i]); + } + qsort(tmp_envs, counter, sizeof(char*), (int(*)(const void*, const void*)) &strcmp); + + /* and copy them */ + env_data = malloc(env_size * sizeof(char)); + buffer_pos = env_data; + for (i = 0; i < counter; i++) + { + length = strlen(tmp_envs[i]) + 1; + memcpy(buffer_pos, tmp_envs[i], length); + buffer_pos += length; + } + + /* add sorted environment to random generator */ + for (j = 0; j < env_size; j++) + { + pseudorandom_algo(&generator_state, ((unsigned char*) env_data)[j]); + } + + /* free temp environment */ + free(tmp_envs); + } + + /* copy argv */ + argv_size = 0; + for (i = 0; i < argc; i++) + { + argv_size += strlen(argv[i]) + 1; + } + argv_data = malloc(sizeof(char) * argv_size); + buffer_pos = argv_data; + for (i = 0; i < argc; i++) + { + length = strlen(argv[i]) + 1; + memcpy(buffer_pos, argv[i], length); + buffer_pos += length; + } + + /* add arguments to gnerator */ + for (j = 0; j < argv_size; j++) + { + pseudorandom_algo(&generator_state, ((unsigned char*) argv_data)[j]); + } + + /* set state and free rest */ + free(env_data); + free(argv_data); + pseudorandom_state = generator_state; +} diff --git a/tools/widl/utils.h b/tools/widl/utils.h index 3740665650..206a80bc39 100644 --- a/tools/widl/utils.h +++ b/tools/widl/utils.h @@ -24,6 +24,7 @@ #include "widltypes.h" #include /* size_t */ +#include void *xmalloc(size_t); void *xrealloc(void *, size_t); @@ -72,6 +73,11 @@ extern void put_pword( unsigned int val ); extern void put_str( int indent, const char *format, ... ) __attribute__((format (printf, 2, 3))); extern void align_output( unsigned int align ); +extern uint64_t pseudorandom(uint64_t add_to_state); +extern char pseudorandom_char(void); +extern int pseudorandom_tempfile(char* file); +extern void init_random_generator(int argc, char **argv); + /* typelibs expect the minor version to be stored in the higher bits and * major to be stored in the lower bits */ #define MAKEVERSION(major, minor) ((((minor) & 0xffff) << 16) | ((major) & 0xffff)) diff --git a/tools/widl/widl.c b/tools/widl/widl.c index 7dd61c9105..b79edb683f 100644 --- a/tools/widl/widl.c +++ b/tools/widl/widl.c @@ -607,6 +607,7 @@ int main(int argc,char *argv[]) #ifdef SIGHUP signal( SIGHUP, exit_on_signal ); #endif + init_random_generator(argc, argv); init_argv0_dir( argv[0] ); { @@ -948,7 +949,7 @@ int main(int argc,char *argv[]) strcpy( name, header_name ); strcat( name, ".XXXXXX" ); - if ((fd = mkstemps( name, 0 )) == -1) + if ((fd = pseudorandom_tempfile(name)) == -1) error("Could not generate a temp name from %s\n", name); temp_name = name;