Skip to content

Commit 5ba92db

Browse files
author
Tavian Barnes
committed
Update the locale thread-safely.
setlocale() affects the entire process, potentially changing the locale while another thread is executing. In POSIX.1-2008, a thread-safe uselocale() function was added that affects only the current thread. Use this function instead when it's available.
1 parent 8822de4 commit 5ba92db

File tree

1 file changed

+53
-15
lines changed

1 file changed

+53
-15
lines changed

svm.cpp

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@
77
#include <stdarg.h>
88
#include <limits.h>
99
#include <locale.h>
10+
11+
#if __unix__
12+
# include <unistd.h> // For _POSIX_VERSION
13+
#endif
14+
1015
#include "svm.h"
16+
1117
int libsvm_version = LIBSVM_VERSION;
1218
typedef float Qfloat;
1319
typedef signed char schar;
@@ -2638,16 +2644,55 @@ static const char *kernel_type_table[]=
26382644
"linear","polynomial","rbf","sigmoid","precomputed",NULL
26392645
};
26402646

2641-
int svm_save_model(const char *model_file_name, const svm_model *model)
2647+
#if _POSIX_VERSION >= 200809L
2648+
2649+
// If possible, use the thread-safe uselocale() function
2650+
typedef locale_t locale_handle;
2651+
2652+
static locale_handle set_c_locale()
26422653
{
2643-
FILE *fp = fopen(model_file_name,"w");
2644-
if(fp==NULL) return -1;
2654+
locale_handle c_locale = newlocale(LC_ALL_MASK, "C", 0);
2655+
locale_handle old_locale = uselocale(c_locale);
2656+
return old_locale;
2657+
}
2658+
2659+
static void restore_locale(locale_handle locale)
2660+
{
2661+
locale_handle c_locale = uselocale(locale);
2662+
if (c_locale && c_locale != LC_GLOBAL_LOCALE) {
2663+
freelocale(c_locale);
2664+
}
2665+
}
2666+
2667+
#else
2668+
2669+
// But fall back to setlocale() if uselocale() is not available
2670+
typedef char *locale_handle;
26452671

2646-
char *old_locale = setlocale(LC_ALL, NULL);
2672+
static locale_handle set_c_locale()
2673+
{
2674+
locale_handle old_locale = setlocale(LC_ALL, NULL);
26472675
if (old_locale) {
26482676
old_locale = strdup(old_locale);
26492677
}
26502678
setlocale(LC_ALL, "C");
2679+
return old_locale;
2680+
}
2681+
2682+
static void restore_locale(locale_handle locale)
2683+
{
2684+
setlocale(LC_ALL, locale);
2685+
free(locale);
2686+
}
2687+
2688+
#endif
2689+
2690+
int svm_save_model(const char *model_file_name, const svm_model *model)
2691+
{
2692+
FILE *fp = fopen(model_file_name,"w");
2693+
if(fp==NULL) return -1;
2694+
2695+
locale_handle old_locale = set_c_locale();
26512696

26522697
const svm_parameter& param = model->param;
26532698

@@ -2728,8 +2773,7 @@ int svm_save_model(const char *model_file_name, const svm_model *model)
27282773
fprintf(fp, "\n");
27292774
}
27302775

2731-
setlocale(LC_ALL, old_locale);
2732-
free(old_locale);
2776+
restore_locale(old_locale);
27332777

27342778
if (ferror(fp) != 0 || fclose(fp) != 0) return -1;
27352779
else return 0;
@@ -2878,11 +2922,7 @@ svm_model *svm_load_model(const char *model_file_name)
28782922
FILE *fp = fopen(model_file_name,"rb");
28792923
if(fp==NULL) return NULL;
28802924

2881-
char *old_locale = setlocale(LC_ALL, NULL);
2882-
if (old_locale) {
2883-
old_locale = strdup(old_locale);
2884-
}
2885-
setlocale(LC_ALL, "C");
2925+
locale_handle old_locale = set_c_locale();
28862926

28872927
// read parameters
28882928

@@ -2898,8 +2938,7 @@ svm_model *svm_load_model(const char *model_file_name)
28982938
if (!read_model_header(fp, model))
28992939
{
29002940
fprintf(stderr, "ERROR: fscanf failed to read model\n");
2901-
setlocale(LC_ALL, old_locale);
2902-
free(old_locale);
2941+
restore_locale(old_locale);
29032942
free(model->rho);
29042943
free(model->label);
29052944
free(model->nSV);
@@ -2971,8 +3010,7 @@ svm_model *svm_load_model(const char *model_file_name)
29713010
}
29723011
free(line);
29733012

2974-
setlocale(LC_ALL, old_locale);
2975-
free(old_locale);
3013+
restore_locale(old_locale);
29763014

29773015
if (ferror(fp) != 0 || fclose(fp) != 0)
29783016
return NULL;

0 commit comments

Comments
 (0)