Skip to content

Commit 1bfe473

Browse files
fix(discover): address QA round 1 findings
- pipeline.c: inline userconfig cleanup on early-exit paths (discover failure and cancel check) so userconfig is always freed, fixing the resource leak when pipeline exits before reaching the cleanup label - userconfig.c: free partially-built entries array on global config parse failure to fix alloc-failure memory leak - language.c: probe user config for compound extensions (e.g. ".blade.php") by scanning from the first dot to the last, falling back to built-in single-extension lookup — preserves built-in behavior while correctly resolving user-defined compound extensions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 1cdb983 commit 1bfe473

File tree

3 files changed

+33
-5
lines changed

3 files changed

+33
-5
lines changed

src/discover/language.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -386,13 +386,30 @@ CBMLanguage cbm_language_for_filename(const char *filename) {
386386
}
387387
}
388388

389-
/* Fall back to extension-based lookup */
390-
const char *dot = strrchr(filename, '.');
391-
if (dot) {
392-
return cbm_language_for_extension(dot);
389+
/* Fall back to extension-based lookup.
390+
* For compound extensions (e.g. ".blade.php") defined in the user config,
391+
* scan from the first dot in the basename toward the last, checking user
392+
* config at each position. Built-in extensions use the last dot only. */
393+
const char *last_dot = strrchr(filename, '.');
394+
if (!last_dot) {
395+
return CBM_LANG_COUNT;
393396
}
394397

395-
return CBM_LANG_COUNT;
398+
/* Probe user config for compound extensions (e.g. ".blade.php"). */
399+
const cbm_userconfig_t *ucfg = cbm_get_user_lang_config();
400+
if (ucfg) {
401+
const char *p = strchr(filename, '.');
402+
while (p && p < last_dot) {
403+
CBMLanguage lang = cbm_userconfig_lookup(ucfg, p);
404+
if (lang != CBM_LANG_COUNT) {
405+
return lang;
406+
}
407+
p = strchr(p + 1, '.');
408+
}
409+
}
410+
411+
/* Standard single-extension lookup (built-ins + user overrides). */
412+
return cbm_language_for_extension(last_dot);
396413
}
397414

398415
const char *cbm_language_name(CBMLanguage lang) {

src/discover/userconfig.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,10 @@ cbm_userconfig_t *cbm_userconfig_load(const char *repo_path) {
304304
snprintf(global_path, sizeof(global_path), "%s/config.json", global_dir);
305305

306306
if (load_config_file(global_path, &entries, &count) != 0) {
307+
for (int i = 0; i < count; i++) {
308+
free(entries[i].ext);
309+
}
310+
free(entries);
307311
free(cfg);
308312
return NULL;
309313
}

src/pipeline/pipeline.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,13 +322,20 @@ int cbm_pipeline_run(cbm_pipeline_t *p) {
322322
int rc = cbm_discover(p->repo_path, &opts, &files, &file_count);
323323
if (rc != 0) {
324324
cbm_log_error("pipeline.err", "phase", "discover", "rc", itoa_buf(rc));
325+
cbm_discover_free(files, file_count);
326+
cbm_set_user_lang_config(NULL);
327+
cbm_userconfig_free(p->userconfig);
328+
p->userconfig = NULL;
325329
return -1;
326330
}
327331
cbm_log_info("pipeline.discover", "files", itoa_buf(file_count), "elapsed_ms",
328332
itoa_buf((int)elapsed_ms(t0)));
329333

330334
if (check_cancel(p)) {
331335
cbm_discover_free(files, file_count);
336+
cbm_set_user_lang_config(NULL);
337+
cbm_userconfig_free(p->userconfig);
338+
p->userconfig = NULL;
332339
return -1;
333340
}
334341

0 commit comments

Comments
 (0)