Skip to content

Commit 5f40053

Browse files
committed
Replace setlocale with thread-safe uselocale for locale handling
The previous implementation used setlocale(LC_ALL/LC_NUMERIC, "C") which affects the entire process and is not thread-safe. This could cause issues in multi-threaded environments where different threads might need different locale settings. Replace setlocale calls with the POSIX.1-2008 thread-safe alternatives: - Use newlocale() to create a C locale for numeric formatting - Use uselocale() to set the locale for the current thread only - Properly restore the previous locale and free resources Changes: - libvmaf/src/svm.cpp: Update svm_save_model() locale handling - libvmaf/src/read_json_model.c: Update vmaf_read_json_model() locale handling - libvmaf/src/output.c: Update all output functions (vmaf_write_output_xml, vmaf_write_output_json, vmaf_write_output_csv, vmaf_write_output_sub) to use thread-safe locale handling with LC_ALL_MASK This ensures consistent numeric formatting (decimal point vs comma) when reading/writing model files and generating output in all formats (XML, JSON, CSV, subtitle) while being thread-safe and not affecting other parts of the application.
1 parent 7c4beca commit 5f40053

File tree

3 files changed

+69
-7
lines changed

3 files changed

+69
-7
lines changed

libvmaf/src/output.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <errno.h>
2020
#include <math.h>
2121
#include <stdio.h>
22+
#include <locale.h>
2223

2324
#include "feature/alias.h"
2425
#include "feature/feature_collector.h"
@@ -72,6 +73,12 @@ int vmaf_write_output_xml(VmafContext *vmaf, VmafFeatureCollector *fc,
7273
if (!fc) return -EINVAL;
7374
if (!outfile) return -EINVAL;
7475

76+
locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL);
77+
locale_t old_locale = (locale_t)0;
78+
if (c_locale != (locale_t)0) {
79+
old_locale = uselocale(c_locale);
80+
}
81+
7582
fprintf(outfile, "<VMAF version=\"%s\">\n", vmaf_version());
7683
fprintf(outfile, " <params qualityWidth=\"%d\" qualityHeight=\"%d\" />\n",
7784
width, height);
@@ -154,13 +161,24 @@ int vmaf_write_output_xml(VmafContext *vmaf, VmafFeatureCollector *fc,
154161

155162
fprintf(outfile, "</VMAF>\n");
156163

164+
if (c_locale != (locale_t)0) {
165+
uselocale(old_locale);
166+
freelocale(c_locale);
167+
}
168+
157169
return 0;
158170
}
159171

160172
int vmaf_write_output_json(VmafContext *vmaf, VmafFeatureCollector *fc,
161173
FILE *outfile, unsigned subsample, double fps,
162174
unsigned pic_cnt)
163175
{
176+
locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL);
177+
locale_t old_locale = (locale_t)0;
178+
if (c_locale != (locale_t)0) {
179+
old_locale = uselocale(c_locale);
180+
}
181+
164182
int leading_zeros_count;
165183
fprintf(outfile, "{\n");
166184
fprintf(outfile, " \"version\": \"%s\",\n", vmaf_version());
@@ -299,12 +317,23 @@ int vmaf_write_output_json(VmafContext *vmaf, VmafFeatureCollector *fc,
299317
fprintf(outfile, "\n }\n");
300318
fprintf(outfile, "}\n");
301319

320+
if (c_locale != (locale_t)0) {
321+
uselocale(old_locale);
322+
freelocale(c_locale);
323+
}
324+
302325
return 0;
303326
}
304327

305328
int vmaf_write_output_csv(VmafFeatureCollector *fc, FILE *outfile,
306329
unsigned subsample)
307330
{
331+
locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL);
332+
locale_t old_locale = (locale_t)0;
333+
if (c_locale != (locale_t)0) {
334+
old_locale = uselocale(c_locale);
335+
}
336+
308337
int leading_zeros_count;
309338
fprintf(outfile, "Frame,");
310339
for (unsigned i = 0; i < fc->cnt; i++) {
@@ -342,12 +371,23 @@ int vmaf_write_output_csv(VmafFeatureCollector *fc, FILE *outfile,
342371
fprintf(outfile, "\n");
343372
}
344373

374+
if (c_locale != (locale_t)0) {
375+
uselocale(old_locale);
376+
freelocale(c_locale);
377+
}
378+
345379
return 0;
346380
}
347381

348382
int vmaf_write_output_sub(VmafFeatureCollector *fc, FILE *outfile,
349383
unsigned subsample)
350384
{
385+
locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL);
386+
locale_t old_locale = (locale_t)0;
387+
if (c_locale != (locale_t)0) {
388+
old_locale = uselocale(c_locale);
389+
}
390+
351391
int leading_zeros_count;
352392
for (unsigned i = 0 ; i < max_capacity(fc); i++) {
353393
if ((subsample > 1) && (i % subsample))
@@ -381,5 +421,10 @@ int vmaf_write_output_sub(VmafFeatureCollector *fc, FILE *outfile,
381421
fprintf(outfile, "\n");
382422
}
383423

424+
if (c_locale != (locale_t)0) {
425+
uselocale(old_locale);
426+
freelocale(c_locale);
427+
}
428+
384429
return 0;
385430
}

libvmaf/src/read_json_model.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <errno.h>
2525
#include <stdlib.h>
2626
#include <string.h>
27+
#include <locale.h>
2728

2829
#define MAX_FEATURE_COUNT 64 //FIXME
2930
#define MAX_KNOT_COUNT 10 //FIXME
@@ -432,6 +433,7 @@ static int model_parse(json_stream *s, VmafModel *model,
432433
static int vmaf_read_json_model(VmafModel **model, VmafModelConfig *cfg,
433434
json_stream *s)
434435
{
436+
int err = -EINVAL;
435437
VmafModel *const m = *model = malloc(sizeof(*m));
436438
if (!m) return -ENOMEM;
437439
memset(m, 0, sizeof(*m));
@@ -449,7 +451,20 @@ static int vmaf_read_json_model(VmafModel **model, VmafModelConfig *cfg,
449451
if (!m->score_transform.knots.list) return -ENOMEM;
450452
memset(m->score_transform.knots.list, 0, knots_sz);
451453

452-
return model_parse(s, m, cfg->flags);
454+
locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL);
455+
locale_t old_locale = (locale_t)0;
456+
if (c_locale != (locale_t)0) {
457+
old_locale = uselocale(c_locale);
458+
}
459+
460+
err = model_parse(s, m, cfg->flags);
461+
462+
if (c_locale != (locale_t)0) {
463+
uselocale(old_locale);
464+
freelocale(c_locale);
465+
}
466+
467+
return err;
453468
}
454469

455470
int vmaf_read_json_model_from_buffer(VmafModel **model, VmafModelConfig *cfg,

libvmaf/src/svm.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2653,11 +2653,11 @@ int svm_save_model(const char *model_file_name, const svm_model *model)
26532653
FILE *fp = fopen(model_file_name,"w");
26542654
if(fp==NULL) return -1;
26552655

2656-
char *old_locale = setlocale(LC_ALL, NULL);
2657-
if (old_locale) {
2658-
old_locale = strdup(old_locale);
2656+
locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL);
2657+
locale_t old_locale = (locale_t)0;
2658+
if (c_locale != (locale_t)0) {
2659+
old_locale = uselocale(c_locale);
26592660
}
2660-
setlocale(LC_ALL, "C");
26612661

26622662
const svm_parameter& param = model->param;
26632663

@@ -2738,8 +2738,10 @@ int svm_save_model(const char *model_file_name, const svm_model *model)
27382738
fprintf(fp, "\n");
27392739
}
27402740

2741-
setlocale(LC_ALL, old_locale);
2742-
free(old_locale);
2741+
if (c_locale != (locale_t)0) {
2742+
uselocale(old_locale);
2743+
freelocale(c_locale);
2744+
}
27432745

27442746
if (ferror(fp) != 0 || fclose(fp) != 0) return -1;
27452747
else return 0;

0 commit comments

Comments
 (0)